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