Thread overview | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 11, 2004 function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
From the spec, it sounds like "in" parameters are supposed to be passed by value and "inout" parameters are passed by reference. I suppose "out" parameters are passed by reference as well, but I don't care about those for the moment. Here's a simple test: class A { int v; } A copy_1( A a ) { return a; } A copy_2( A a ) { a.v++; return a; } void test_ref() { A a = new A(); a.v = 5; A b = copy_1( a ); b.v = 10; printf( "%i %i\n", a.v, b.v ); A c = copy_2( a ); printf( "%i %i\n", a.v, c.v ); } Which (to my surprise) prints: 10 10 11 11 My first assumption was that "in" parameters were copied and those copies were pushed onto the stack. Were this true, copy_1 should have returned a valid copy of the passed object and the first line should have printed: 5 10 My second assumption was that perhaps a copy was only generated if the passed object was actually modified. Were this true, copy_2 should have returned a valid copy of the passed object and the second line should have printed (assuming copy_1 failed): 10 11 Again not the case. With "const" specifiers missing from function declarations, is there any way to pass object by value or ensure they aren't the victim of side-effects? Is this just a feature that hasn't been completed yet? Sean |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Nar, it's by-design. You see objects in D are references (pointers) themselves. Structs however aren't. Sean Kelly wrote: > From the spec, it sounds like "in" parameters are supposed to be passed by value and "inout" parameters are passed by reference. I suppose "out" parameters are passed by reference as well, but I don't care about those for the moment. Here's a simple test: > > class A > { > int v; > } > > > A copy_1( A a ) > { > return a; > } > > > A copy_2( A a ) > { > a.v++; > return a; > } > > > void test_ref() > { > A a = new A(); > a.v = 5; > A b = copy_1( a ); > b.v = 10; > printf( "%i %i\n", a.v, b.v ); > A c = copy_2( a ); > printf( "%i %i\n", a.v, c.v ); > } > Try this: struct A { int v; } A copy_1( A a ) { return a; } A copy_2( A a ) { a.v++; return a; } void test_ref() { A a; // = new A(); a.v = 5; A b = copy_1( a ); b.v = 10; printf( "%i %i\n", a.v, b.v ); A c = copy_2( a ); printf( "%i %i\n", a.v, c.v ); } > Which (to my surprise) prints: > > 10 10 > 11 11 > > My first assumption was that "in" parameters were copied and those copies were pushed onto the stack. Were this true, copy_1 should have returned a valid copy of the passed object and the first line should have printed: > > 5 10 > > My second assumption was that perhaps a copy was only generated if the passed object was actually modified. Were this true, copy_2 should have returned a valid copy of the passed object and the second line should have printed (assuming copy_1 failed): > > 10 11 > > Again not the case. With "const" specifiers missing from function declarations, is there any way to pass object by value or ensure they aren't the victim of side-effects? Is this just a feature that hasn't been completed yet? > > > Sean > -- -Anderson: http://badmama.com.au/~anderson/ |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | A a and A b are both references to the same object. you can only have references to class-types. you newed only one object. this is the only one existing in your whole app "Sean Kelly" <sean@ffwd.cx> schrieb im Newsbeitrag news:c0e5ma$rb2$1@digitaldaemon.com... > From the spec, it sounds like "in" parameters are supposed to be passed by value and "inout" parameters are passed by reference. I suppose "out" parameters are passed by reference as well, but I don't care about those for the moment. Here's a simple test: > > class A > { > int v; > } > > > A copy_1( A a ) > { > return a; > } > > > A copy_2( A a ) > { > a.v++; > return a; > } > > > void test_ref() > { > A a = new A(); > a.v = 5; > A b = copy_1( a ); > b.v = 10; > printf( "%i %i\n", a.v, b.v ); > A c = copy_2( a ); > printf( "%i %i\n", a.v, c.v ); > } > > Which (to my surprise) prints: > > 10 10 > 11 11 > > My first assumption was that "in" parameters were copied and those copies were pushed onto the stack. Were this true, copy_1 should have returned a valid copy of the passed object and the first line should have printed: > > 5 10 > > My second assumption was that perhaps a copy was only generated if the passed object was actually modified. Were this true, copy_2 should have returned a valid copy of the passed object and the second line should have printed (assuming copy_1 failed): > > 10 11 > > Again not the case. With "const" specifiers missing from function declarations, is there any way to pass object by value or ensure they aren't the victim of side-effects? Is this just a feature that hasn't been completed yet? > > > Sean > |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to J Anderson | J Anderson wrote:
>
> Nar, it's by-design. You see objects in D are references (pointers) themselves. Structs however aren't.
So there's no way for a caller to ensure he's safe from side-effects when passing a class to a function? I didn't think this was typical even for GC languages.
Sean
|
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > J Anderson wrote: > > > >> Nar, it's by-design. You see objects in D are references (pointers) themselves. Structs however aren't. > > > So there's no way for a caller to ensure he's safe from side-effects when passing a class to a function? I didn't think this was typical even for GC languages. I'm not 100% sure, but I think it's the same in Java. Although it would be nice to have a read only in D. You could always make a copy of A before you pass it (or after) if you want to modify without side effect. You can also use design by contracts. > Sean -- -Anderson: http://badmama.com.au/~anderson/ |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to J Anderson | J Anderson wrote: > > You can also use design by contracts. Definately. And perhaps that's the out. If so, it makes DBC even more important than I had first considered it. Sean |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > J Anderson wrote: > > > > You can also use design by contracts. > > Definately. And perhaps that's the out. If so, it makes DBC even more important than I had first considered it. > > > Sean > IMHO, for such a task, DBC is more work then marking a variable read-only (const or whatever). -- -Anderson: http://badmama.com.au/~anderson/ |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
J Anderson wrote:
>
> IMHO, for such a task DBC is more work with marking it read-only.
And how would DBC work in this case anyway? Say I have a function I want to gurantee will not alter its parameters:
class A {}
void func( int i, A a )
in
{
A ain = new A( a )
}
out
{
assert( a == ain );
}
body
{
...
}
This doesn't work for two reasons. First, A doesn't have a copy ctor, so I can't create a new A in this way. Second, ain expires when the in block completes. To make matters worse, if func is a template function and A might be either a primitive or object type, I need to be more careful about how I generate the copy. And all this just to produce a "const" equivalent. There has to be a better way.
|
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > J Anderson wrote: > > > >> IMHO, for such a task DBC is more work with marking it read-only. > > > And how would DBC work in this case anyway? You would need to test that the class members don't change. Like I said, it's more work then it's worth. ie template stack (T) //Re-usable { T [] stack; void push(T val) { stack ~= val; } T pop() { T val = stack[stack.length - 1]; stack.length = stack.length - 1; return val; } } class A { int v; char c; void pushCheck() { //Reusable to an extent (nice if we had RTTI for this then we could simply loop through them), or sizeof could be used stack!(int).push(v); stack!(char).push(c); } bool popCheck() //Reusable to an extent { return (stack!(int).pop() == v)?true:false & (stack!(char).pop() == c)?true:false; } } A copy_1( A a ) { return a; } A copy_2( A a ) { a.pushCheck(); a.v++; assert(a.popCheck()); //Make sure it doesn't change return a; } void test_ref() { A a = new A(); a.v = 5; A b = copy_1( a ); b.v = 10; printf( "%i %i\n", a.v, b.v ); A c = copy_2( a ); printf( "%i %i\n", a.v, c.v ); } That's still ugly + it's run-time. > This doesn't work for two reasons. First, A doesn't have a copy ctor, so I can't create a new A in this way. Second, ain expires when the in block completes. To make matters worse, if func is a template function and A might be either a primitive or object type, I need to be more careful about how I generate the copy. And all this just to produce a "const" equivalent. There has to be a better way. -- -Anderson: http://badmama.com.au/~anderson/ |
February 11, 2004 Re: function parameter passing broken? | ||||
---|---|---|---|---|
| ||||
Posted in reply to J Anderson | J Anderson wrote: > Sean Kelly wrote: > >> J Anderson wrote: >> > >> >>> IMHO, for such a task DBC is more work with marking it read-only. >> >> >> >> And how would DBC work in this case anyway? > > > You would need to test that the class members don't change. Like I said, it's more work then it's worth. ie > > template stack (T) //Re-usable > { > T [] stack; > void push(T val) > { > stack ~= val; > } > T pop() > { > T val = stack[stack.length - 1]; > stack.length = stack.length - 1; > return val; > } > } > > class A > { > int v; > char c; > > void pushCheck() > { > //Reusable to an extent (nice if we had RTTI for this then we could simply loop through them), or sizeof could be used By sizeof I mean taking the entire class and turning it into a memory block, and passing that to the stack. Of couse you wouldn't be able to do deep checks that way. With property RTTI you could write it into the base class. > stack!(int).push(v); > stack!(char).push(c); > } > bool popCheck() //Reusable to an extent > { return (stack!(int).pop() == v)?true:false & > (stack!(char).pop() == c)?true:false; > } > } > > > > A copy_1( A a ) > { > return a; > } > > > A copy_2( A a ) > { > a.pushCheck(); > a.v++; > assert(a.popCheck()); //Make sure it doesn't change > return a; > } > > > void test_ref() > { > A a = new A(); > a.v = 5; > A b = copy_1( a ); > b.v = 10; > printf( "%i %i\n", a.v, b.v ); > A c = copy_2( a ); > printf( "%i %i\n", a.v, c.v ); > } > > That's still ugly + it's run-time. > >> This doesn't work for two reasons. First, A doesn't have a copy ctor, so I can't create a new A in this way. Second, ain expires when the in block completes. To make matters worse, if func is a template function and A might be either a primitive or object type, I need to be more careful about how I generate the copy. And all this just to produce a "const" equivalent. There has to be a better way. > > > -- -Anderson: http://badmama.com.au/~anderson/ |
Copyright © 1999-2021 by the D Language Foundation