[chuck-users] Passing classes to functions
Hans Aberg
haberg at math.su.se
Fri Oct 2 14:16:53 EDT 2009
On 2 Oct 2009, at 09:38, Adam Tindale wrote:
> I was doing some work and created some bugs that I ironed out when I
> discovered something: when non-primitive types are passed to functions
> they are passed by reference and not by value! I include a test so you
> can see what I mean.
>
> I hope somebody find this useful.
Though it has been pointed out briefly as being the normal for a
typical reference implementation, it might help to linger a bit on the
details, and compare with the situation when a reference count or
other GC (garbage collector) is present. - Some say chuck might get a
ref count someday.
> class test{
> 0 => int val;
> }
Here, one typically implements two classes, this class test, and
another (using pseudo-code)
class test_ref {
test* pointer_;
};
If one uses a reference count, the class test will have an additional
integer, hidden from public view, indicating how many copies there are:
class test {
private:
int count_;
public:
0 => int val;
}
> test obj1;
This produces the implementation:
test_ref obj1;
obj1.pointer_ = new test();
obj1.count_ = 1; // If reference count is used.
> // obj2 is a reference to obj1
> test obj2 @=> obj1;
Now, this is equivalent to the implementation:
test_ref obj2;
obj2.pointer_ = new test(); // By test obj2
obj2.count_ = 1; // If reference count is used.
obj1.pointer_ = obj2.pointer_; // By the @=>
Since chuck does not have a ref count, the original obj1.pointer_ now
is referenced by nothing. So it is a memory leak. A so called tracing
GC (garbage collector) can find this out by starting from the set of
objects that originates all other objects: the function stack and
global objects, which is called the root system, and follow all
pointers. The objects not found in such a sweep are viewed as dead,
and removed.
When using a reference count, one needs to check if obj1.pointer_ and
obj2.pointer_ already point to the same object, and if they do, do
nothing - assignment does not change anything. Otherwise decrease the
reference count of obj1.pointer_, and if it becomes 0, remove it. Then
increase the reference count of obj2.pointer_ and set obj1.pointer_ =
obj2.pointer_.
> <<< obj1.val , "original object">>>;
> <<< obj2.val , "reference to original">>>;
>
> 2 => obj2.val;
>
> <<< obj1.val , "original object">>>;
> <<< obj2.val , "reference to original">>>;
>
> fun void testclasspassing(test i)
> {
> <<< i.val, "in function" >>>;
> }
This will be implemented as
void testclasspassing(test_ref i) {
<<< i.pointer_->val, "in function" >>>;
}
> testclasspassing(obj1);
> testclasspassing(obj2);
So this then becomes clear: obj1.pointer_ is the same as
obj2.pointer_; therefore testclasspassing() prints the same object.
(Since the pointer can be 0, then implementation might benefit from
some check.)
There is a memory leak, that would have been prevented by the use of a
reference count or other GC.
Hans
More information about the chuck-users
mailing list