D - function parameter passing broken?
- Sean Kelly (45/45) Feb 11 2004 From the spec, it sounds like "in" parameters are supposed to be passed...
- J Anderson (29/74) Feb 11 2004 Nar, it's by-design. You see objects in D are references (pointers)
- Sean Kelly (5/7) Feb 11 2004 So there's no way for a caller to ensure he's safe from side-effects
- J Anderson (7/15) Feb 11 2004 I'm not 100% sure, but I think it's the same in Java. Although it would
- Sean Kelly (4/5) Feb 11 2004 Definately. And perhaps that's the out. If so, it makes DBC even more
- J Anderson (5/11) Feb 11 2004 IMHO, for such a task, DBC is more work then marking a variable
- Sean Kelly (23/24) Feb 11 2004 And how would DBC work in this case anyway? Say I have a function I
- J Anderson (61/71) Feb 11 2004 You would need to test that the class members don't change. Like I
- J Anderson (7/76) Feb 11 2004 By sizeof I mean taking the entire class and turning it into a memory
- Matthew (3/28) Feb 22 2004 It's called const / readonly. :-(
- Sean Kelly (16/26) Feb 12 2004 I thought a bit more about this last night and decided the D way is
- Ilya Minkov (24/55) Feb 12 2004 Java doesn't have the distinction. It passes all by quasi-value, which
- Sean Kelly (7/16) Feb 12 2004 This was my conclusion last night. Once I gave it some thought I
- Matthew (10/36) Feb 22 2004 Nooooooooooooooo! Don't believe the hype.
- Sean Kelly (13/29) Feb 23 2004 I'll admit that I would like consts, but I can understand that it's far
- Matthew (13/42) Feb 23 2004 I am not bothered about the language absolutely preventing modification....
- Matthew (11/26) Feb 22 2004 No, this is an area where C/C++ got it right, and D/.NET/Java have it qu...
- J Anderson (7/43) Feb 22 2004 Where is that no referring to. No it's not the same in java? No it
- Matthew (4/34) Feb 22 2004 quite
- Matthew (3/10) Feb 22 2004 Sounds completely typical for GC languages.
- davepermen (5/50) Feb 11 2004 A a and A b are both references to the same object. you can only have
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
Feb 11 2004
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/
Feb 11 2004
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
Feb 11 2004
Sean Kelly wrote:J Anderson wrote: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.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-- -Anderson: http://badmama.com.au/~anderson/
Feb 11 2004
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
Feb 11 2004
Sean Kelly wrote:J Anderson wrote:IMHO, for such a task, DBC is more work then marking a variable read-only (const or whatever). -- -Anderson: http://badmama.com.au/~anderson/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
Feb 11 2004
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.
Feb 11 2004
Sean Kelly wrote:J Anderson wrote: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.IMHO, for such a task DBC is more work with marking it read-only.And how would DBC work in this case anyway?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/
Feb 11 2004
J Anderson wrote:Sean Kelly wrote: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.J Anderson wrote: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 usedIMHO, for such a task DBC is more work with marking it read-only.And how would DBC work in this case anyway?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.-- -Anderson: http://badmama.com.au/~anderson/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.
Feb 11 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c0ea34$136o$1 digitaldaemon.com...J Anderson wrote: >It's called const / readonly. :-(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.
Feb 22 2004
J Anderson wrote:Sean Kelly wrote:I thought a bit more about this last night and decided the D way is good. Adding const qualifiers for parameter passing would require the existence of const qualifiers for member functions, a mutable qualifier, etc. And then there's the issue of some classes which just plain aren't copyable: streams and other complex objects with state information. I think this is one thing I'm just going to have to get used to. Document the cases where a side-effect may occur and allow the user to make a copy before passing if it's an issue. And I checked the Java spec last night and I think you're right--I could find no mention of by value vs. by reference passing. The fact that structs are copied makes me wonder though. Is it enough just to rely on the optimizer for keeping such operations efficient? I'm inclined to think so. Also, I imagine that using the inout qualifier on POD types will pass them by reference? SeanSo 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.
Feb 12 2004
Sean Kelly wrote:J Anderson wrote: >Java doesn't have the distinction. It passes all by quasi-value, which makes integers, characters and floats/doubles (ie primitive types) pass by value, everything else is a class (even if the fact is partially hidden from the user) and thus passes by reference. In general, functions should be written in a safe manner, like the copy-on-write string examples from the manual.Sean Kelly wrote:I thought a bit more about this last night and decided the D way is good. Adding const qualifiers for parameter passing would require the existence of const qualifiers for member functions, a mutable qualifier, etc. And then there's the issue of some classes which just plain aren't copyable: streams and other complex objects with state information. I think this is one thing I'm just going to have to get used to. Document the cases where a side-effect may occur and allow the user to make a copy before passing if it's an issue. And I checked the Java spec last night and I think you're right--I could find no mention of by value vs. by reference passing.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.The fact that structs are copied makes me wonder though. Is it enough just to rely on the optimizer for keeping such operations efficient? I'm inclined to think so. Also, I imagine that using the inout qualifier on POD types will pass them by reference?I don't know how a current implementation decides it, but your struct is admittably tiny - everything not larger than 8 bytes is faster to pass by value than by reference. I would guess that implementation decides how to actually pass. However, value pass semantics stays - this can be done e.g. by detecting whether any change is being made, and if there is, then make a local copy in the beginning of the function. If i remember correctly, Delphi had 2 access modifiers, const and var. Var was the same as inout, const was to disallow any change. While this looks elegant, it has still at least one problem: you can *never* reasonably detect a change on an object, unlike a struct. There are deep reasons to that, if you like i could explain, or you simply may guess them. So i must say i'm satisfied with D solution. Especiall, it doesn't break common code e.g. from Java. And yes, inout on structs makes them definately pass by reference, but you shouldn't do that for performance reasons. Do this only if you actually modify the struct and need the inout semantics. -eye
Feb 12 2004
Ilya Minkov wrote:If i remember correctly, Delphi had 2 access modifiers, const and var. Var was the same as inout, const was to disallow any change. While this looks elegant, it has still at least one problem: you can *never* reasonably detect a change on an object, unlike a struct. There are deep reasons to that, if you like i could explain, or you simply may guess them. So i must say i'm satisfied with D solution.This was my conclusion last night. Once I gave it some thought I realized the complexity involved and decided it wasn't worth the hassle. The D method now makes sense.And yes, inout on structs makes them definately pass by reference, but you shouldn't do that for performance reasons. Do this only if you actually modify the struct and need the inout semantics.Agreed. I was mostly curious for academic reasons as I'm still getting the hang of this language. Sean
Feb 12 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c0g9td$17gl$1 digitaldaemon.com...J Anderson wrote: >Nooooooooooooooo! Don't believe the hype. It's bad, bad, bad. This is one important area in which the hunt for compiler simplicity is a specious one.Sean Kelly wrote:I thought a bit more about this last night and decided the D way is good. Adding const qualifiers for parameter passing would require the existence of const qualifiers for member functions, a mutable qualifier, etc. And then there's the issue of some classes which just plain aren't copyable: streams and other complex objects with state information.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.I think this is one thing I'm just going to have to get used to. Document the cases where a side-effect may occur and allow the user to make a copy before passing if it's an issue. And I checked the Java spec last night and I think you're right--I could find no mention of by value vs. by reference passing.Everything is passed by value in Java, including references. A copy of a reference is another reference to the same object. Since the only distinguishing aspect of a refernece is its referent, it looks as if pass-by-reference is being used for references, but it's not. :-)The fact that structs are copied makes me wonder though. Is it enough just to rely on the optimizer for keeping such operations efficient? I'm inclined to think so. Also, I imagine that using the inout qualifier on POD types will pass them by reference?We can but hope!
Feb 22 2004
Matthew wrote:"Sean Kelly" <sean ffwd.cx> wrote in message news:c0g9td$17gl$1 digitaldaemon.com...I'll admit that I would like consts, but I can understand that it's far more than just adding a "const" qualifier to parameters. but with "const" missing, I'd like to add a *strong* recommendation that creators of classes supply a copy ctor.I thought a bit more about this last night and decided the D way is good. Adding const qualifiers for parameter passing would require the existence of const qualifiers for member functions, a mutable qualifier, etc. And then there's the issue of some classes which just plain aren't copyable: streams and other complex objects with state information.Nooooooooooooooo! Don't believe the hype. It's bad, bad, bad. This is one important area in which the hunt for compiler simplicity is a specious one.Everything is passed by value in Java, including references. A copy of a reference is another reference to the same object. Since the only distinguishing aspect of a refernece is its referent, it looks as if pass-by-reference is being used for references, but it's not. :-)But it amounts to the same thing. This raises some interesting issues regarding exception safety and "const" gurantees. Can a function writer ever be sure that an object he is passed will be returned in an unaltered state? I'm inclined to think not, unless he always created a copy of any passed object before doing *anything* with it. This is an idea I'm still warming up to. I think I'll have to write some serious code in D before I decide whether this is an issue I'm happy with. Sean
Feb 23 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c1dfo4$2da7$1 digitaldaemon.com...Matthew wrote:I am not bothered about the language absolutely preventing modification. In fact, I would disagree with that - the Spirit Of C, and all that. All I want is that the programmer cannot alter a readonly variable without making some explicit (preferably ugly and greppable) construct, a la const_cast. I don't need/want the language to try and detect such abuses. One can always abuse in any language. It's about "helping" the programmer to do correct work, rather than standing on his neck to make him do so, or not caring in the first place (which is the current situation). But we're just hot-airing. This has been debated to death, and Walter's not buying."Sean Kelly" <sean ffwd.cx> wrote in message news:c0g9td$17gl$1 digitaldaemon.com...I'll admit that I would like consts, but I can understand that it's far more than just adding a "const" qualifier to parameters. but with "const" missing, I'd like to add a *strong* recommendation that creators of classes supply a copy ctor.I thought a bit more about this last night and decided the D way is good. Adding const qualifiers for parameter passing would require the existence of const qualifiers for member functions, a mutable qualifier, etc. And then there's the issue of some classes which just plain aren't copyable: streams and other complex objects with state information.Nooooooooooooooo! Don't believe the hype. It's bad, bad, bad. This is one important area in which the hunt for compiler simplicity is a specious one.Everything is passed by value in Java, including references. A copy of a reference is another reference to the same object. Since the only distinguishing aspect of a refernece is its referent, it looks as if pass-by-reference is being used for references, but it's not. :-)But it amounts to the same thing. This raises some interesting issues regarding exception safety and "const" gurantees. Can a function writer ever be sure that an object he is passed will be returned in an unaltered state? I'm inclined to think not, unless he always created a copy of any passed object before doing *anything* with it. This is an idea I'm still warming up to. I think I'll have to write some serious code in D before I decide whether this is an issue I'm happy with.
Feb 23 2004
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c0e6rk$t00$1 digitaldaemon.com...Sean Kelly wrote:No, this is an area where C/C++ got it right, and D/.NET/Java have it quite wrong. Alas Walter is influenced by the practical breakability of C/C++'s const - by casts - and its conceptual splendour seems to have skipped him. But this argument is long gone, and we lost. D will have to be broken in this regard. btw, DBC is *quite* the wrong tool for this - it's a compile time thing. Alas, because we are denied the const (or "readonly", which makes much more sense) keyword, it is our only tool. :(J Anderson wrote: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.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.
Feb 22 2004
Matthew wrote:"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c0e6rk$t00$1 digitaldaemon.com...Where is that no referring to. No it's not the same in java? No it wouldn't be nice to have a read-only in D? No you can't make a copy before/after passing it?Sean Kelly wrote:No, this is an area where C/C++ got it right, and D/.NET/Java have it quite wrong.J Anderson wrote: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.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.Alas Walter is influenced by the practical breakability of C/C++'s const - by casts - and its conceptual splendour seems to have skipped him. But this argument is long gone, and we lost. D will have to be broken in this regard. btw, DBC is *quite* the wrong tool for this - it's a compile time thing. Alas, because we are denied the const (or "readonly", which makes much more sense) keyword, it is our only tool. :(I completely agree, I was just trying to be practical. -- -Anderson: http://badmama.com.au/~anderson/
Feb 22 2004
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c1c89p$54m$1 digitaldaemon.com...Matthew wrote:quite"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c0e6rk$t00$1 digitaldaemon.com...Sean Kelly wrote:No, this is an area where C/C++ got it right, and D/.NET/Java have itJ Anderson wrote: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.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.It was no to DBC (in this case)wrong.
Feb 22 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c0e6jd$sr0$1 digitaldaemon.com...J Anderson wrote: >Sounds completely typical for GC languages.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.
Feb 22 2004
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
Feb 11 2004