-
Notifications
You must be signed in to change notification settings - Fork 229
Class vs Struct
Starting from Gravity version 0.7.8 I added preliminary support for Structs (original commit here).
A Struct in Gravity behaves in the same way as a Class except that it is passed by value instead of by reference. Let me better explain with an example:
class classFoo {
var x;
var y;
func init (a, b) {
x = a;
y = b;
}
func sum() {
return x + y;
}
}
struct structFoo {
var x;
var y;
func init (a, b) {
x = a;
y = b;
}
func sum() {
return x + y;
}
}
func main() {
var p1 = classFoo(10, 20);
var p2 = structFoo(20, 30);
var obj1 = p1;
obj1.x = 1000;
var obj2 = p2;
obj2.x = 1000;
return p1.sum() + p2.sum();
}
classFoo and structFoo have been declared in the same way, they both have two instance variables, a constructor and a sum method. The side effect of a Class vs Struct object is clear in the main function.
Once instantiated, p1
is copied by reference to obj1
and so when obj1.x
changes as a side effect also p1.x
changes. On the other hand, p2
is copied by value to obj2
and changing obj2.x
does not have any effect on the original p2
object.
Implementing Struct support in the compiler forced me to introduce a new CHECK opcode (gravity_opcodes.h). The new opcode is responsible to check at runtime if the object being copied is a struct and in that case, it performs a deep copy instead of a pointer copy.
gravity_value_t value = STACK_GET(r1);
if (VALUE_ISA_INSTANCE(value) && (gravity_instance_isstruct(VALUE_AS_INSTANCE(value)))) {
gravity_instance_t *instance = gravity_instance_clone(vm, VALUE_AS_INSTANCE(value));
SETVALUE(r1, VALUE_FROM_OBJECT(instance));
}
This introduces a very small overhead because in a dynamically typed language like Gravity I cannot know the exact type of an object at static compilation time and that forced me to postpone the decision at runtime. That's the main reason why I decided to skip the check for parameter passing (too much overhead).
In the next Gravity version, I'll add full support for manifest/hybrid typing where struct checking can be performed at compilation time and so the CHECK instruction can be generated only for the real struct based object. In that version struct support will be extended to func parameters too.