digitalmars.D - opValue()
- Derek Parnell (49/49) Apr 05 2005 Walter (and anyone else),
- Ben Hinkle (11/55) Apr 05 2005 no problem.
- Derek Parnell (55/119) Apr 05 2005 Huh? Did I mention initializing? See example code below. Classes would
- Regan Heath (7/13) Apr 05 2005 I think what Ben was trying to say here is that:
- Ben Hinkle (11/25) Apr 05 2005 Yes, that's what I was thinking. To put it another way, the code
- Derek Parnell (21/51) Apr 05 2005 In my way of thinking, when a class is initialized it calls the construc...
- Regan Heath (21/69) Apr 05 2005 Because as a general rule what you're suggesting appeared to me to effec...
- Derek Parnell (23/77) Apr 05 2005 We might actually need an opValue_r() routine too.
- Derek Parnell (6/22) Apr 05 2005 Why? Doesn't the 'new' keyword mean 'call the this() member function'?
- Regan Heath (15/35) Apr 05 2005 Well I'm no expert on how this works, but I imagine...
- Derek Parnell (24/65) Apr 05 2005 Yep.
- Regan Heath (13/33) Apr 05 2005 That's what I said above only I broke it into the 3 steps it takes.
- Derek Parnell (37/44) Apr 06 2005 Yes. It seems that I've (once again) been unable to express myself clear...
- Georg Wrede (2/53) Apr 06 2005 Id vote for this.
- xs0 (14/66) Apr 06 2005 What about
- Derek Parnell (17/33) Apr 06 2005 I'm not sure. I guess you wouldn't have a member function of Obj like
- xs0 (19/49) Apr 06 2005 OK, but what if it is FooFactory? If there was opValue() it would seem
- brad domain.invalid (30/41) Apr 06 2005 Argh! Surely not! I thought one of the philosophies of D was that
- Regan Heath (27/62) Apr 06 2005 And if they're the same type, it could be used for a "deep-copy"?
- Derek Parnell (32/45) Apr 06 2005 On Thu, 07 Apr 2005 13:34:52 +1200, Regan Heath wrote:
- brad domain.invalid (19/56) Apr 06 2005 Forgive me if I ramble a little - just thinking this through.
- Regan Heath (4/47) Apr 07 2005 This seems a fairly good list of the points so far, plus a few
- xs0 (12/30) Apr 07 2005 Hmm, that philosophy is good and all, but what would you expect to get
- brad domain.invalid (7/22) Apr 07 2005 Well, to be honest I don't know what to expect from <<= if you override
- Ben Hinkle (13/28) Apr 06 2005 I would recommend you use inheritance. If your code involves lots of cas...
- David Medlock (14/70) Apr 06 2005 Overloading assignment is a semantic minefield to say the least, and has...
- Derek Parnell (26/43) Apr 06 2005 Currently, I have this concept implemented as a property of the 'receivi...
- Vladimir (7/7) Apr 07 2005 I like the idea about := operator.
Walter (and anyone else), AAAARRRRRGGGGGHHHH!!!!! (Sorry about that. I'm getting a little frustrated at the hoops D is putting me through). Here's an idea to kick around... In the construct a = <expression>; when 'a' is an aggregate, it is equivalent to coding a.opValue(<expression>); This would make my coding life *so* much easier. It is one way of providing a natural coding style for implicit conversion of classes and structs. Here is some sample code to explain what I'd like ... <code> import std.stdio; class A { private int aa; this() { aa = 2; } A opValue(B y) { aa = y.bb + 1; // 'convert' a B to an A return this; } } class B { private int bb; this() { bb = 4; } B opValue(A y) { bb = y.aa - 10; // 'convert' an A to a B return this; } } void main() { A a = new A; B b = new B; writefln("Before %d %d", a.aa, b.bb); a.opValue(b); // aka: a = b; b.opValue(a); // aka: b = a; writefln("After %d %d", a.aa, b.bb); } </code> -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 6/04/2005 10:45:52 AM
Apr 05 2005
"Derek Parnell" <derek psych.ward> wrote in message news:9wvklcksh1nr.n1xvda56jdpe$.dlg 40tude.net...Walter (and anyone else), AAAARRRRRGGGGGHHHH!!!!! (Sorry about that. I'm getting a little frustrated at the hoops D is putting me through).no problem.Here's an idea to kick around... In the construct a = <expression>; when 'a' is an aggregate, it is equivalent to coding a.opValue(<expression>); This would make my coding life *so* much easier. It is one way of providing a natural coding style for implicit conversion of classes and structs.I'm confused. By aggregate I assume you mean either a struct or class type. But with a class a.opValue will seg-v if a is null so how does one initialize a? See http://www.digitalmars.com/d/archives/23623.html for a thread including a message from Walter explaining why D doens't allow assignment to be overloaded. More context about what you are actually trying to do would help, too.Here is some sample code to explain what I'd like ... <code> import std.stdio; class A { private int aa; this() { aa = 2; } A opValue(B y) { aa = y.bb + 1; // 'convert' a B to an A return this; } } class B { private int bb; this() { bb = 4; } B opValue(A y) { bb = y.aa - 10; // 'convert' an A to a B return this; } } void main() { A a = new A; B b = new B; writefln("Before %d %d", a.aa, b.bb); a.opValue(b); // aka: a = b; b.opValue(a); // aka: b = a; writefln("After %d %d", a.aa, b.bb); } </code>What's wrong with writing a.opValue(b) or a.copyFrom(b) or something? Why is "=" needed? Are you using templates?
Apr 05 2005
On Tue, 5 Apr 2005 21:48:54 -0400, Ben Hinkle wrote:"Derek Parnell" <derek psych.ward> wrote in message news:9wvklcksh1nr.n1xvda56jdpe$.dlg 40tude.net...Yep.Here's an idea to kick around... In the construct a = <expression>; when 'a' is an aggregate, it is equivalent to coding a.opValue(<expression>); This would make my coding life *so* much easier. It is one way of providing a natural coding style for implicit conversion of classes and structs.I'm confused. By aggregate I assume you mean either a struct or class type.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...See http://www.digitalmars.com/d/archives/23623.html for a thread including a message from Walter explaining why D doens't allow assignment to be overloaded.Yes, I remember this discussion. It was mainly dealing with constructors for structs and deep vs shallow copying. The primary reason (I think) for Walter not liking that, is what happens when assigning class instances between related classes. Eg... class C {} class B:C {} class A:B {} C c; A a; c = a; // This is legal and useful.More context about what you are actually trying to do would help, too.See code below ;-) My emphasis is on making life easier for coders and readers. So sure there is a 'work around', namely explicitly calling opValue(), but I argue that doing so is not as intuitive as the commonly used '=' symbol. So here is a more fuller description of what I think would make coding in D a more pleasant experience. __________________________ In the construct a = <expression>; when 'a' is an aggregate *and* it contains the member function 'opValue', it is equivalent to coding a.opValue(<expression>); otherwise the construct behaves as with the current semantics. __________________________ The idea, is to have a nice way in which a class designer can invent built-in conversion routines for explicit data types, and have people use those conversion routines in a standard, clean and intuitive manner.To make writing and reading coding a more pleasant experience. Imaging being able to doing something like this ... Circle c; Square s; Triangle t; . . . c = s; // Convert the square to a circle. t = c; // Convert the circle to a triangle. . . . In my current project, I need to convert between various classes and structs, and currently it involves lots of white-noise coding. A cleaner, clearer, method of coding this would be appreciated.Here is some sample code to explain what I'd like ... <code> import std.stdio; class A { private int aa; this() { aa = 2; } A opValue(B y) { aa = y.bb + 1; // 'convert' a B to an A return this; } } class B { private int bb; this() { bb = 4; } B opValue(A y) { bb = y.aa - 10; // 'convert' an A to a B return this; } } void main() { A a = new A; B b = new B; writefln("Before %d %d", a.aa, b.bb); a.opValue(b); // aka: a = b; b.opValue(a); // aka: b = a; writefln("After %d %d", a.aa, b.bb); } </code>What's wrong with writing a.opValue(b) or a.copyFrom(b) or something? Why is "=" needed?Are you using templates?Yes, and that too. That fact that you must use different syntax depending on whether you are using a class, a struct, an array or an intrinsic data type is a real PITA. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 6/04/2005 12:54:43 PM
Apr 05 2005
On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed. Regan.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
"Regan Heath" <regan netwin.co.nz> wrote in message news:opsosivfu423k2f5 nrage.netwin.co.nz...On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Yes, that's what I was thinking. To put it another way, the code A a; will initialize a to null and so when you try to run a = b; it will try to run a.opValue(b) which will seg-v. This is slightly different than A a = new A; but basically I'm wondering how a.opValue works when a is null or during initialization.I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed. Regan.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
On Tue, 5 Apr 2005 23:17:53 -0400, Ben Hinkle wrote:"Regan Heath" <regan netwin.co.nz> wrote in message news:opsosivfu423k2f5 nrage.netwin.co.nz...In my way of thinking, when a class is initialized it calls the constructor routine 'this' and so it wouldn't attempt calling opValue. Also, if the class instance is not initialized (ie still null), then opValue couldn't be called. Why are you guys thinking that I'm talking about initialization? I'm just trying to invent a nice way to implement customized data conversions. That is, converting data from an evaluated expression to an instance of a class/struct. class C { C opValue(int x) { . . . return this; } } . . . C myC = new C; . . . myC = 42; // i.e. myC.opValue(42); -- Derek Melbourne, Australia 6/04/2005 2:03:28 PMOn Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Yes, that's what I was thinking. To put it another way, the code A a; will initialize a to null and so when you try to run a = b; it will try to run a.opValue(b) which will seg-v. This is slightly different than A a = new A; but basically I'm wondering how a.opValue works when a is null or during initialization.I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed. Regan.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
On Wed, 6 Apr 2005 14:09:43 +1000, Derek Parnell <derek psych.ward> wrote:On Tue, 5 Apr 2005 23:17:53 -0400, Ben Hinkle wrote:Because as a general rule what you're suggesting appeared to me to effect initialization (after I read Bens response). So, I wanted clarification as to how you thought it would work with initialization, which you've just given above. Some comments:"Regan Heath" <regan netwin.co.nz> wrote in message news:opsosivfu423k2f5 nrage.netwin.co.nz...In my way of thinking, when a class is initialized it calls the constructor routine 'this' and so it wouldn't attempt calling opValue. Also, if the class instance is not initialized (ie still null), then opValue couldn't be called. Why are you guys thinking that I'm talking about initialization?On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Yes, that's what I was thinking. To put it another way, the code A a; will initialize a to null and so when you try to run a = b; it will try to run a.opValue(b) which will seg-v. This is slightly different than A a = new A; but basically I'm wondering how a.opValue works when a is null or during initialization.I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed. Regan.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...In my way of thinking, when a class is initialized it calls the constructor routine 'this' and so it wouldn't attempt calling opValue.My take on this, from my other post: <quote> Well I'm no expert on how this works, but I imagine... A a = new A(); RHS: "new A()" means allocate some memory on the heap, and calls "this" for A in it. <at this stage we have an A class in heap memory assigned to nothing) LHS: "A a" <at this stage we have a null reference to an A on the stack called 'a'> "=" means assign RHS to LHS. <the A in memory is assigned to the 'a' on the stack> </quote>Also, if the class instance is not initialized (ie still null), then opValue couldn't be called.Correct, so what happens? Isn't this like saying: if (a == b) when a is a null reference? which casues a seg-v. Regan
Apr 05 2005
On Wed, 6 Apr 2005 14:09:43 +1000, Derek Parnell wrote:On Tue, 5 Apr 2005 23:17:53 -0400, Ben Hinkle wrote:We might actually need an opValue_r() routine too. void opValue_r(inout int x) { . . . x = ... ; } . . . int y; y = myC; // i.e. myC.opValue_r(y); And if you are concerned by opValue_r not returning anything, (damn C's heritage) you can still do " while ( (y = myC, y) > 0) ... " :D [offtopic: Q. How much of B and BPCL did Richie & Kernighan jettison? A. Enough. Q. How much of C and C++ did Walters jettison? A. Not enough (yet?) ] -- Derek Melbourne, Australia 6/04/2005 2:12:00 PM"Regan Heath" <regan netwin.co.nz> wrote in message news:opsosivfu423k2f5 nrage.netwin.co.nz...In my way of thinking, when a class is initialized it calls the constructor routine 'this' and so it wouldn't attempt calling opValue. Also, if the class instance is not initialized (ie still null), then opValue couldn't be called. Why are you guys thinking that I'm talking about initialization? I'm just trying to invent a nice way to implement customized data conversions. That is, converting data from an evaluated expression to an instance of a class/struct. class C { C opValue(int x) { . . . return this; } } . . . C myC = new C; . . . myC = 42; // i.e. myC.opValue(42);On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Yes, that's what I was thinking. To put it another way, the code A a; will initialize a to null and so when you try to run a = b; it will try to run a.opValue(b) which will seg-v. This is slightly different than A a = new A; but basically I'm wondering how a.opValue works when a is null or during initialization.I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed. Regan.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
On Wed, 06 Apr 2005 15:05:29 +1200, Regan Heath wrote:On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Why? Doesn't the 'new' keyword mean 'call the this() member function'? -- Derek Melbourne, Australia 6/04/2005 1:25:31 PMI think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
On Wed, 6 Apr 2005 13:26:15 +1000, Derek Parnell <derek psych.ward> wrote:On Wed, 06 Apr 2005 15:05:29 +1200, Regan Heath wrote:Well I'm no expert on how this works, but I imagine... A a = new A(); RHS: "new A()" means allocate some memory on the heap, and calls "this" for A in it. <at this stage we have an A class in heap memory assigned to nothing) LHS: "A a" <at this stage we have a null reference to an A on the stack called 'a'> "=" means assign RHS to LHS. <the A in memory is assigned to the 'a' on the stack> Ben's other question is perhaps more important. A a; a = b; <- a is null, this calls a.opValue(b). Does that seg-v or.. ? ReganOn Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Why? Doesn't the 'new' keyword mean 'call the this() member function'?I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...
Apr 05 2005
On Wed, 06 Apr 2005 16:16:05 +1200, Regan Heath wrote:On Wed, 6 Apr 2005 13:26:15 +1000, Derek Parnell <derek psych.ward> wrote:Yep.On Wed, 06 Apr 2005 15:05:29 +1200, Regan Heath wrote:Well I'm no expert on how this works, but I imagine... A a = new A(); RHS: "new A()" means allocate some memory on the heap, and calls "this" for A in it. <at this stage we have an A class in heap memory assigned to nothing)On Wed, 6 Apr 2005 12:57:00 +1000, Derek Parnell <derek psych.ward> wrote:Why? Doesn't the 'new' keyword mean 'call the this() member function'?I think what Ben was trying to say here is that: (assume A is a class) A a = new A(); *is* assigning a value to 'a' so would call "opValue(A a)" in A, if it existed.But with a class a.opValue will seg-v if a is null so how does one initialize a?Huh? Did I mention initializing? See example code below. Classes would still be initialized as normal, with the 'new' keyword. I'm talking about assigning value to a (existing) class/struct based on the value of an expression. Nothing to do with constructors, etc...LHS: "A a" <at this stage we have a null reference to an A on the stack called 'a'>Yep."=" means assign RHS to LHS. <the A in memory is assigned to the 'a' on the stack>Sort of. The "= new" means that 'a' is updated to point to the new A on the heap. I just saying that "a = new <CLASS>" creates a new instance (just like it does now), and "a = <expression>" calls a.opValue(<expression>) if 'a' is already instantiated *and* opValue(typeid(<expression>)) exists as a member function of a. So obviously "A a = new A" could never call "a.opValue(A)" because 'a' is not instantiated yet. But ... A a = new A; A b = new A; a = b; // This could call a.opValue(b) if one was defined. This would be a neat one to customize the simple reference-copy semantics, if one needed to do that.Ben's other question is perhaps more important. A a; a = b; <- a is null, this calls a.opValue(b). Does that seg-v or.. ?seg-v, of course. This is normal behaviour and need not change. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 6/04/2005 2:31:47 PM
Apr 05 2005
On Wed, 6 Apr 2005 15:02:46 +1000, Derek Parnell <derek psych.ward> wrote:On Wed, 06 Apr 2005 16:16:05 +1200, Regan Heath wrote:That's what I said above only I broke it into the 3 steps it takes. This last step simply assigns the reference created by "new A()" to the reference created on the stack by "A a". In other words this last step is identical to the step performed by "=" in "a = b", the only difference here is that "b" is another stack reference and not a "new" one.Well I'm no expert on how this works, but I imagine... A a = new A(); RHS: "new A()" means allocate some memory on the heap, and calls "this" for A in it. <at this stage we have an A class in heap memory assigned to nothing)Yep.LHS: "A a" <at this stage we have a null reference to an A on the stack called 'a'>Yep."=" means assign RHS to LHS. <the A in memory is assigned to the 'a' on the stack>Sort of. The "= new" means that 'a' is updated to point to the new A on the heap.I just saying that "a = new <CLASS>" creates a new instance (just like it does now), and "a = <expression>" calls a.opValue(<expression>) if 'a' is already instantiated *and* opValue(typeid(<expression>)) exists as a member function of a.But... "a = new <CLASS>" is technically "a = <expression>" as "new" is an expression: http://www.digitalmars.com/d/expression.html#NewExpression So "a = new A()" could call "a.opValue(new A())" So you see why Ben and I have been asking about it? Regan
Apr 05 2005
On Wed, 06 Apr 2005 17:38:26 +1200, Regan Heath wrote: [snip]But... "a = new <CLASS>" is technically "a = <expression>" as "new" is an expression: http://www.digitalmars.com/d/expression.html#NewExpression So "a = new A()" could call "a.opValue(new A())" So you see why Ben and I have been asking about it?Yes. It seems that I've (once again) been unable to express myself clearly though. Essentially I'm talking about a change in D's behaviour. I can see that the way D *currently* interprets the syntax, it would not achieve what I'd like to see happen. So, I talk of change. This proposed change to D would not break existing code either, because any code like this is already broken (one gets the 'cannot implicitly cast' message). I'm proposing that instead of automatically getting that message, D checks to see if it can call the appropriate opValue() member function. If it can't then if falls back to the 'implicit cast' error. This means that in my envisioned D, (i.e. not the current one), then syntax in the form ... <CLASS> <IDENT> = new <CLASS> [ ARGLIST ]; be interpreted as *just* an instantiation of the class, and thus this form of 'assignment' would not check for opValue() members. Is that really too much to ask for? Is is really stupid of me to ask for a standard mechanism to enable coders to provide (implicit) casting methods that convert an expression into a form suitable to update a class or struct instance ( or any type would be nice too)? I was hoping to avoid a new operator as those seem harder to implement and usually meet more resistance for a syntax faux pas. So I thought that hijacking something that is currently an error construct, and turning it into something that we could use instead, would be a 'Good Thing'. <AGGREGATEINSTANCE> = <NON_NEW_EXPRESSION> would be interpreted as <AGGREGATEINSTANCE>.opValue( <NON_NEW_EXPRESSION> ) if has a member function opValue( TypeOf (<NON_NEW_EXPRESSION>) ) defined. If this criteria was not present, then the current semantics would apply. Of course, if the instance was null at the time of calling, then the usual run time error would apply. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 6/04/2005 5:02:41 PM
Apr 06 2005
Derek Parnell wrote:On Wed, 06 Apr 2005 17:38:26 +1200, Regan Heath wrote: [snip]Id vote for this.But... "a = new <CLASS>" is technically "a = <expression>" as "new" is an expression: http://www.digitalmars.com/d/expression.html#NewExpression So "a = new A()" could call "a.opValue(new A())" So you see why Ben and I have been asking about it?Yes. It seems that I've (once again) been unable to express myself clearly though. Essentially I'm talking about a change in D's behaviour. I can see that the way D *currently* interprets the syntax, it would not achieve what I'd like to see happen. So, I talk of change. This proposed change to D would not break existing code either, because any code like this is already broken (one gets the 'cannot implicitly cast' message). I'm proposing that instead of automatically getting that message, D checks to see if it can call the appropriate opValue() member function. If it can't then if falls back to the 'implicit cast' error. This means that in my envisioned D, (i.e. not the current one), then syntax in the form ... <CLASS> <IDENT> = new <CLASS> [ ARGLIST ]; be interpreted as *just* an instantiation of the class, and thus this form of 'assignment' would not check for opValue() members. Is that really too much to ask for? Is is really stupid of me to ask for a standard mechanism to enable coders to provide (implicit) casting methods that convert an expression into a form suitable to update a class or struct instance ( or any type would be nice too)? I was hoping to avoid a new operator as those seem harder to implement and usually meet more resistance for a syntax faux pas. So I thought that hijacking something that is currently an error construct, and turning it into something that we could use instead, would be a 'Good Thing'. <AGGREGATEINSTANCE> = <NON_NEW_EXPRESSION> would be interpreted as <AGGREGATEINSTANCE>.opValue( <NON_NEW_EXPRESSION> ) if has a member function opValue( TypeOf (<NON_NEW_EXPRESSION>) ) defined. If this criteria was not present, then the current semantics would apply. Of course, if the instance was null at the time of calling, then the usual run time error would apply.
Apr 06 2005
What about Obj a = ObjFactory.create(); This is quite a common pattern, if you want all the newing of something to happen in one place (so you can easily switch the implementation). Having it your way would destroy this possibility, driving all OO-heads away (me too, I guess :) What about Obj a = cond ? new Something() : oldSth; This is not a NewExpression.. What you're asking is not very feasible, I'm afraid. I think you have better chances by trying for a new operator.. BTW, why opValue() not opSet()? xs0 Derek Parnell wrote:On Wed, 06 Apr 2005 17:38:26 +1200, Regan Heath wrote: [snip]But... "a = new <CLASS>" is technically "a = <expression>" as "new" is an expression: http://www.digitalmars.com/d/expression.html#NewExpression So "a = new A()" could call "a.opValue(new A())" So you see why Ben and I have been asking about it?Yes. It seems that I've (once again) been unable to express myself clearly though. Essentially I'm talking about a change in D's behaviour. I can see that the way D *currently* interprets the syntax, it would not achieve what I'd like to see happen. So, I talk of change. This proposed change to D would not break existing code either, because any code like this is already broken (one gets the 'cannot implicitly cast' message). I'm proposing that instead of automatically getting that message, D checks to see if it can call the appropriate opValue() member function. If it can't then if falls back to the 'implicit cast' error. This means that in my envisioned D, (i.e. not the current one), then syntax in the form ... <CLASS> <IDENT> = new <CLASS> [ ARGLIST ]; be interpreted as *just* an instantiation of the class, and thus this form of 'assignment' would not check for opValue() members. Is that really too much to ask for? Is is really stupid of me to ask for a standard mechanism to enable coders to provide (implicit) casting methods that convert an expression into a form suitable to update a class or struct instance ( or any type would be nice too)? I was hoping to avoid a new operator as those seem harder to implement and usually meet more resistance for a syntax faux pas. So I thought that hijacking something that is currently an error construct, and turning it into something that we could use instead, would be a 'Good Thing'. <AGGREGATEINSTANCE> = <NON_NEW_EXPRESSION> would be interpreted as <AGGREGATEINSTANCE>.opValue( <NON_NEW_EXPRESSION> ) if has a member function opValue( TypeOf (<NON_NEW_EXPRESSION>) ) defined. If this criteria was not present, then the current semantics would apply. Of course, if the instance was null at the time of calling, then the usual run time error would apply.
Apr 06 2005
On Wed, 06 Apr 2005 18:07:25 +0200, xs0 wrote:What about Obj a = ObjFactory.create(); This is quite a common pattern, if you want all the newing of something to happen in one place (so you can easily switch the implementation). Having it your way would destroy this possibility, driving all OO-heads away (me too, I guess :)I'm not sure. I guess you wouldn't have a member function of Obj like "opValue(Obj x)" because that is like saying, 'here is how you convert an Obj to an Obj'. Doesn't make any sense.What about Obj a = cond ? new Something() : oldSth; This is not a NewExpression..True. However, if it is legal in your application, then it's also not a construct that will give you the 'cannot implicitly cast' error. It is *those* constructs I was aiming at doing something with.What you're asking is not very feasible, I'm afraid. I think you have better chances by trying for a new operator..But the concept of wanting to be able to let the compile know how to convert one class into another is still a good one, no? If it's just a syntax issue remaining, I'm sure we can get around that somehow.BTW, why opValue() not opSet()?Dunno. I guess I see it as "The Value of X comes from <Expression>". So I'm focusing on the noun rather than the verb. It doesn't really matter to me. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build 7/04/2005 2:19:05 AM
Apr 06 2005
Derek Parnell wrote:On Wed, 06 Apr 2005 18:07:25 +0200, xs0 wrote:OK, but what if it is FooFactory? If there was opValue() it would seem completely logical, yet it would fail..What about Obj a = ObjFactory.create(); This is quite a common pattern, if you want all the newing of something to happen in one place (so you can easily switch the implementation). Having it your way would destroy this possibility, driving all OO-heads away (me too, I guess :)I'm not sure. I guess you wouldn't have a member function of Obj like "opValue(Obj x)" because that is like saying, 'here is how you convert an Obj to an Obj'. Doesn't make any sense.It's not legal now, but with opValue it would be legal, because you could assign both new Something() or oldSth to a. Now, although that looks normal, it will crash if oldSth or Something are not implicitly castable, but only opValue() castable. I mean, you want to override reference assignment, which either compiles and always works or doesn't compile in the first place, with a function call which may or may not work in runtime..Obj a = cond ? new Something() : oldSth; This is not a NewExpression..True. However, if it is legal in your application, then it's also not a construct that will give you the 'cannot implicitly cast' error. It is *those* constructs I was aiming at doing something with.Well, it is and it isn't.. I'd prefer multiple opCasts, so it's immediately obvious what you're doing.. And isn't this good enough for a shorter syntax: class T { T opShlAssign(Foo c) { /*...*/ return this; } } a<<=b; // almost like a=b, if you ask me I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use.. xs0What you're asking is not very feasible, I'm afraid. I think you have better chances by trying for a new operator..But the concept of wanting to be able to let the compile know how to convert one class into another is still a good one, no? If it's just a syntax issue remaining, I'm sure we can get around that somehow.
Apr 06 2005
rter syntax:class T { T opShlAssign(Foo c) { /*...*/ return this; } } a<<=b; // almost like a=b, if you ask me I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use.. xs0Argh! Surely not! I thought one of the philosophies of D was that operators should _always_ do what you expect. The <<= operator should always shift left & assign. Derek - am I right in saying that you want an assignment operator that doesn't create a new object, but instead alters an existing one? At the moment, when you deal with objects/references, the = operator always means "set this reference to this object". I don't think that it makes sense to overload this meaning, because you then end up with an operator that in some cases does "set this reference to this object" and in other cases "alter the internal data layout of object A, based on the values in object B" And then you end up with a whole lot of special rules to try and remember which assignment operator is applying. Overwriting the contents of an object when you really ment to assign to a new object could ruin your day if you hold multiple references to the object you are stomping on. I am in favour of having an operator that means "take object B, get some values out of it and setup object A accordingly" Something like Foo a = new Foo (); Bar b = new Bar (); a <- b // which calls a.opConvert(b); I guess you could also end up with nasty a = (new Foo())<- b; <- is probably not the operator to choose, probably hard to parse. Maybe someone else can think of a good operator if this functionality is required. Brad
Apr 06 2005
On Thu, 07 Apr 2005 08:45:21 +1200, <brad domain.invalid> wrote:rter syntax:And if they're the same type, it could be used for a "deep-copy"? I think we can combine this casting concern with the deep-copy concern, they seem closely related to me.class T { T opShlAssign(Foo c) { /*...*/ return this; } } a<<=b; // almost like a=b, if you ask me I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use.. xs0Argh! Surely not! I thought one of the philosophies of D was that operators should _always_ do what you expect. The <<= operator should always shift left & assign. Derek - am I right in saying that you want an assignment operator that doesn't create a new object, but instead alters an existing one? At the moment, when you deal with objects/references, the = operator always means "set this reference to this object". I don't think that it makes sense to overload this meaning, because you then end up with an operator that in some cases does "set this reference to this object" and in other cases "alter the internal data layout of object A, based on the values in object B" And then you end up with a whole lot of special rules to try and remember which assignment operator is applying. Overwriting the contents of an object when you really ment to assign to a new object could ruin your day if you hold multiple references to the object you are stomping on. I am in favour of having an operator that means "take object B, get some values out of it and setup object A accordingly"Something like Foo a = new Foo (); Bar b = new Bar (); a <- b // which calls a.opConvert(b); I guess you could also end up with nasty a = (new Foo())<- b;It seems 'correct' if 'ugly', done in 2 steps looks nicer and incurs no additional penalty (that I can see). a = new Foo(); a <- b; this operator is really a "copy RHS into LHS" operator, which implys that LHS must exists beforehand. Or using the "<-" operator could implicitly call new if the LHS is null... not sure how feasible that is.<- is probably not the operator to choose, probably hard to parse. Maybe someone else can think of a good operator if this functionality is required.I agree, I think the main concern against this in Walters case was that implicit conversion when "=" is used can cause subtle behaviour and bugs. (correct me if I am wrong). So, if a new operator was used, eg. ":=" or something then this concern vanishes, as "=" does what it currently does: - shallow copy for arrays. - reference assignment for classes etc - deep copy for value types The new ":=" operator always means "copy RHS into LHS" AKA: - deep copy for arrays (provided items in array have deep-copy method defined) - deep copy for classes (provided class has deep-copy method defined) - same as "=" for value types. Thoughts? Regan
Apr 06 2005
On Thu, 07 Apr 2005 13:34:52 +1200, Regan Heath wrote: [snip]So, if a new operator was used, eg. ":=" or something then this concern vanishes, as "=" does what it currently does: - shallow copy for arrays. - reference assignment for classes etc - deep copy for value types The new ":=" operator always means "copy RHS into LHS" AKA: - deep copy for arrays (provided items in array have deep-copy method defined) - deep copy for classes (provided class has deep-copy method defined) - same as "=" for value types. Thoughts?Ok, an additional operator then. So long as 'value types' also includes the intrinsic data types like int, real, byte, ..., so that we could make useful templates, I could cope with this. Thus ... int a; a = b; and a := b; would behave identically. And, we still need to deal with ... struct Foo {} int a; Foo b; a := b; Maybe Walter will allow us to do ... void opDeepCopy(inout int X, Foo Y) { ... } so that " a := b; " would call opDeepCopy(a,b); Also, I'd like to be able to do deep copies for structs too, even though they are 'value' types. Such that ... struct Foo {} Foo a; a := b; // call a.opDeepCopy(b) or some such. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v1.19 released 04/Apr/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 7/04/2005 12:06:34 PM
Apr 06 2005
Ok, an additional operator then. So long as 'value types' also includes the intrinsic data types like int, real, byte, ..., so that we could make useful templates, I could cope with this. Thus ... int a; a = b; and a := b; would behave identically. And, we still need to deal with ... struct Foo {} int a; Foo b; a := b; Maybe Walter will allow us to do ... void opDeepCopy(inout int X, Foo Y) { ... } so that " a := b; " would call opDeepCopy(a,b); Also, I'd like to be able to do deep copies for structs too, even though they are 'value' types. Such that ... struct Foo {} Foo a; a := b; // call a.opDeepCopy(b) or some such.Forgive me if I ramble a little - just thinking this through. 1) The main point of := is so we can write templated functions that behave well with intrinsics and user defined types, without needing hacks to get them to work. 2) This won't break any new code, and will allow us to be more expressive with D. 3) ":=" represents "deep copy/convert", it may call a function and should be reguarded as a potentially expensive operator 4) ":=" will fail if the LHS is null (or should it resolve to a LHS static opDeepCopy(inout LHS_class x, type RHS) ?) 5) ":=" with intrinsic LHS will call the function opDeepCopy(LHS, RHS) 6) Have two "assignment" operators is potentially confusing - but probably no more than understanding the difference between shallow and deep copy. 7) we not longer need the .dup property?, because we can go int a[]; int b[]; a := b; // which is a deep copy of b into a Brad
Apr 06 2005
On Thu, 07 Apr 2005 14:17:54 +1200, <brad domain.invalid> wrote:This seems a fairly good list of the points so far, plus a few new/reworded ones which I also like. ReganOk, an additional operator then. So long as 'value types' also includes the intrinsic data types like int, real, byte, ..., so that we could make useful templates, I could cope with this. Thus ... int a; a = b; and a := b; would behave identically. And, we still need to deal with ... struct Foo {} int a; Foo b; a := b; Maybe Walter will allow us to do ... void opDeepCopy(inout int X, Foo Y) { ... } so that " a := b; " would call opDeepCopy(a,b); Also, I'd like to be able to do deep copies for structs too, even though they are 'value' types. Such that ... struct Foo {} Foo a; a := b; // call a.opDeepCopy(b) or some such.Forgive me if I ramble a little - just thinking this through. 1) The main point of := is so we can write templated functions that behave well with intrinsics and user defined types, without needing hacks to get them to work. 2) This won't break any new code, and will allow us to be more expressive with D. 3) ":=" represents "deep copy/convert", it may call a function and should be reguarded as a potentially expensive operator 4) ":=" will fail if the LHS is null (or should it resolve to a LHS static opDeepCopy(inout LHS_class x, type RHS) ?) 5) ":=" with intrinsic LHS will call the function opDeepCopy(LHS, RHS) 6) Have two "assignment" operators is potentially confusing - but probably no more than understanding the difference between shallow and deep copy. 7) we not longer need the .dup property?, because we can go int a[]; int b[]; a := b; // which is a deep copy of b into a
Apr 07 2005
brad domain.invalid wrote:rter syntax:Hmm, that philosophy is good and all, but what would you expect to get from shifting ClassA by ClassB? I just chose this operator because it looks as a left arrow (at least to me), which is exactly what you proposed, and I couldn't think of any other use for it with classes/structs.. <- is no good, though: "a<-3" should be "a < -3", not "a.opConvert(3)" As for a new operator for this functionality, I don't think it's necessary. a.set(b) is short enough, it is also much more obvious what's happening, and it's also obvious that a can't be null.. if you don't use opCall for other stuff, you can even just use a(b).. xs0class T { T opShlAssign(Foo c) { /*...*/ return this; } } a<<=b; // almost like a=b, if you ask me I guess in 99.99999% cases, shifting an object to left with another object doesn't make sense anyway, so the operator might as well get another use.. xs0Argh! Surely not! I thought one of the philosophies of D was that operators should _always_ do what you expect. The <<= operator should always shift left & assign.
Apr 07 2005
Hmm, that philosophy is good and all, but what would you expect to get from shifting ClassA by ClassB? I just chose this operator because it looks as a left arrow (at least to me), which is exactly what you proposed, and I couldn't think of any other use for it with classes/structs.. <- is no good, though: "a<-3" should be "a < -3", not "a.opConvert(3)" As for a new operator for this functionality, I don't think it's necessary. a.set(b) is short enough, it is also much more obvious what's happening, and it's also obvious that a can't be null.. if you don't use opCall for other stuff, you can even just use a(b).. xs0Well, to be honest I don't know what to expect from <<= if you override it and make it do things that aren't shift left and assign :) What if my LHS class is an implementation that can be shifted left? Anyhow - I think the main reason for having an assignment operator instead of a.set(b), is that for templates you want the template to work for classes and built in primitives. Brad
Apr 07 2005
Imaging being able to doing something like this ... Circle c; Square s; Triangle t; . . . c = s; // Convert the square to a circle. t = c; // Convert the circle to a triangle. . . . In my current project, I need to convert between various classes and structs, and currently it involves lots of white-noise coding. A cleaner, clearer, method of coding this would be appreciated.I would recommend you use inheritance. If your code involves lots of casting then the inheritance tree probably needs refactoring. As you've written your code above and commented in other parts of this thread the assignment c = s; t = c; will seg-v. Having been coding in Java for a while it's very nice to know exactly what assignment does. It is very simple and it is always the same. No more unexpected surprises with = that can happen in C++. That's actually why I like to overload as little as possible (eg I have grown to avoid static opCast overloads).To my mind this is the only reason to request some language changes - to make a single template easier to use with both primitives and aggregates.Are you using templates?Yes, and that too. That fact that you must use different syntax depending on whether you are using a class, a struct, an array or an intrinsic data type is a real PITA.
Apr 06 2005
Overloading assignment is a semantic minefield to say the least, and has come up here before (Google this newsgroup). Redefining the assignment operator would cripple vectorization efforts, judging by the recent move towards 'static-single-assignment', such as in GCC 4.x, also SAC( single assignment C). Since assignment might mean assignment and other times mean a method call, its hard to convert it to an intermediate SSA representation. Two viable options : - Use the overloaded opCall() which takes different types depending on what you need. - Convince Walter to allow a := operator which would throw NullPointer if the recipient is null or not a variable. -David Derek Parnell wrote:Walter (and anyone else), AAAARRRRRGGGGGHHHH!!!!! (Sorry about that. I'm getting a little frustrated at the hoops D is putting me through). Here's an idea to kick around... In the construct a = <expression>; when 'a' is an aggregate, it is equivalent to coding a.opValue(<expression>); This would make my coding life *so* much easier. It is one way of providing a natural coding style for implicit conversion of classes and structs. Here is some sample code to explain what I'd like ... <code> import std.stdio; class A { private int aa; this() { aa = 2; } A opValue(B y) { aa = y.bb + 1; // 'convert' a B to an A return this; } } class B { private int bb; this() { bb = 4; } B opValue(A y) { bb = y.aa - 10; // 'convert' an A to a B return this; } } void main() { A a = new A; B b = new B; writefln("Before %d %d", a.aa, b.bb); a.opValue(b); // aka: a = b; b.opValue(a); // aka: b = a; writefln("After %d %d", a.aa, b.bb); } </code>
Apr 06 2005
On Wed, 06 Apr 2005 16:57:02 -0400, David Medlock wrote:Overloading assignment is a semantic minefield to say the least, and has come up here before (Google this newsgroup). Redefining the assignment operator would cripple vectorization efforts, judging by the recent move towards 'static-single-assignment', such as in GCC 4.x, also SAC( single assignment C). Since assignment might mean assignment and other times mean a method call, its hard to convert it to an intermediate SSA representation. Two viable options : - Use the overloaded opCall() which takes different types depending on what you need. - Convince Walter to allow a := operator which would throw NullPointer if the recipient is null or not a variable.Currently, I have this concept implemented as a property of the 'receiving' class. eg. class Foo { void Value( Bar x) { . . . } } Foo a = new Foo; Bar b = new Bar; . . . a.Value = b; However, I have two problems with this. The first problem is that I occasionally forget that I'm dealing with classes and code " a = b ", because it feels natural to code that when transferring value from one thing to another, but I get rewarded with an error message about implicit casting. Secondly, it makes designing a single template that covers all data types impossible. I need to have one template for classes and another for intrinsic types, simply because I can't use "a = b" for both situations. Thank you all for this enlightening discussion. I've learned lots from it, but I can't actually see Walter doing anything about this, even in v2.0, so I'll drop it and blunder on. -- Derek Parnell Melbourne, Australia 7/04/2005 7:21:18 AM
Apr 06 2005
I like the idea about := operator. May be one can introduce ":" (opColon) binary operator which in expression a : b evaluates a and b and then returns b. Then (using general rule about "op=") ":=" (opColonAssign) will mean deep-copy and be overloadable ? -- Vladimir
Apr 07 2005