Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 16, 2006 "inout return type" and "inout variable" | ||||
---|---|---|---|---|
| ||||
Thanks everyone here for your great work in D, especially Walter who makes it all happen. Here I am requesting a feature, which is "inout variable" and "inout return type" Rationale, for the example below, struct Foo { int x, int y, int z; } class Bar { private: Foo m_foo; public: Foo foo() { return m_foo; } Foo foo(Foo value) { return m_foo = value; } } now if i want to change the value of m_foo.x to 5, i have to do Foo foo = bar.foo; foo.x = 5; bar.foo = foo; it would be nice if I can define a return type as "inout Foo" inout Foo foo() { return m_foo;} To extend it further, one might want to define inout variables as inout Foo foo = bar.foo; Advantages: 1. efficiency, one can directly change the states of the struct instead of making a copy first, change the copy, and put the result back to the struct 2. less buggy, having to type 3 lines always increases chance of bugs, also, someone might inadvertantly do bar.foo.x = 5 and forgot that he is working on a copy 3. reduce the use of pointers, the above can be achieved using pointers, but it means defining two versions of the same method every time a struct property is written. |
March 16, 2006 Re: "inout return type" and "inout variable" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hong Wing | In article <dvb0tq$1ptf$1@digitaldaemon.com>, Hong Wing says... > >Thanks everyone here for your great work in D, especially Walter who makes it >all happen. >Here I am requesting a feature, which is "inout variable" and "inout return >type" >Rationale, for the example below, > >struct Foo >{ >int x, int y, int z; >} > >class Bar >{ >private: >Foo m_foo; >public: >Foo foo() { return m_foo; } >Foo foo(Foo value) { return m_foo = value; } >} > >now if i want to change the value of m_foo.x to 5, i have to do > >Foo foo = bar.foo; >foo.x = 5; >bar.foo = foo; > >it would be nice if I can define a return type as "inout Foo" >inout Foo foo() { return m_foo;} > >To extend it further, one might want to define inout variables as inout Foo foo = bar.foo; > >Advantages: > >1. efficiency, one can directly change the states of the struct instead of making a copy first, change the copy, and put the result back to the struct > >2. less buggy, having to type 3 lines always increases chance of bugs, also, someone might inadvertantly do bar.foo.x = 5 and forgot that he is working on a copy > >3. reduce the use of pointers, the above can be achieved using pointers, but it means defining two versions of the same method every time a struct property is written. > > This is a good suggestion imho and is probably fairly easy for Walter to implement as well. |
March 16, 2006 Re: "inout return type" and "inout variable" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hong Wing | On Thu, 16 Mar 2006 06:34:34 +0000 (UTC), Hong Wing <Hong_member@pathlink.com> wrote: > Thanks everyone here for your great work in D, especially Walter who makes it > all happen. > Here I am requesting a feature, which is "inout variable" and "inout return > type" > Rationale, for the example below, > > struct Foo > { > int x, int y, int z; > } > > class Bar > { > private: > Foo m_foo; > public: > Foo foo() { return m_foo; } > Foo foo(Foo value) { return m_foo = value; } > } > > now if i want to change the value of m_foo.x to 5, i have to do > > Foo foo = bar.foo; > foo.x = 5; > bar.foo = foo; > > it would be nice if I can define a return type as "inout Foo" > inout Foo foo() { return m_foo;} > > To extend it further, one might want to define inout variables as > inout Foo foo = bar.foo; > > Advantages: > > 1. efficiency, one can directly change the states of the struct instead of > making a copy first, change the copy, and put the result back to the struct > > 2. less buggy, having to type 3 lines always increases chance of bugs, also, > someone might inadvertantly do bar.foo.x = 5 and forgot that he is working on a > copy > > 3. reduce the use of pointers, the above can be achieved using pointers, but it > means defining two versions of the same method every time a struct property is > written. You're essentially asking for the ability to have variables which are references to structs (at least during assignment) and to return references to structs, all without using the pointer syntax. I think these things are un-necessary, and I think what you want can be achieved with pointers, without the penalty you mention in #3 above, see: import std.string; import std.stdio; struct Foo { int x; int y; int z; char[] toString() { return "("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; } } class Bar { private: Foo m_foo; public: Foo* foo() { return &m_foo; } Foo* foo(Foo* value) { m_foo = *value; return foo(); } Foo* foo(Foo value) { m_foo = value; return foo(); } } void main() { Bar b = new Bar(); Bar c = new Bar(); Foo t; b.foo.x = 1; b.foo.y = 2; b.foo.z = 3; writefln(b.foo.toString()); c.foo = b.foo; writefln(c.foo.toString()); t.x = 4; t.y = 5; t.z = 6; writefln(t.toString()); b.foo = t; writefln(b.foo.toString()); } Note: The explicit "toString" calls are required because otherwise it prints the pointer address. Regan |
March 17, 2006 Re: | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | There are 3 drawbacks with the pointer approach 1. Noticed that you have 2 versions of the same method, one takes Foo in by pointer and one takes in by value. 2. returning pointer would break client code if a field is changed to a property. 3. you cannot call operators from pointers, without adding in * everywhere. In article <ops6i24bii23k2f5@nrage.netwin.co.nz>, Regan Heath says... > >On Thu, 16 Mar 2006 06:34:34 +0000 (UTC), Hong Wing <Hong_member@pathlink.com> wrote: >> Thanks everyone here for your great work in D, especially Walter who >> makes it >> all happen. >> Here I am requesting a feature, which is "inout variable" and "inout >> return >> type" >> Rationale, for the example below, >> >> struct Foo >> { >> int x, int y, int z; >> } >> >> class Bar >> { >> private: >> Foo m_foo; >> public: >> Foo foo() { return m_foo; } >> Foo foo(Foo value) { return m_foo = value; } >> } >> >> now if i want to change the value of m_foo.x to 5, i have to do >> >> Foo foo = bar.foo; >> foo.x = 5; >> bar.foo = foo; >> >> it would be nice if I can define a return type as "inout Foo" >> inout Foo foo() { return m_foo;} >> >> To extend it further, one might want to define inout variables as inout Foo foo = bar.foo; >> >> Advantages: >> >> 1. efficiency, one can directly change the states of the struct instead >> of >> making a copy first, change the copy, and put the result back to the >> struct >> >> 2. less buggy, having to type 3 lines always increases chance of bugs, >> also, >> someone might inadvertantly do bar.foo.x = 5 and forgot that he is >> working on a >> copy >> >> 3. reduce the use of pointers, the above can be achieved using pointers, >> but it >> means defining two versions of the same method every time a struct >> property is >> written. > >You're essentially asking for the ability to have variables which are references to structs (at least during assignment) and to return references to structs, all without using the pointer syntax. I think these things are un-necessary, and I think what you want can be achieved with pointers, without the penalty you mention in #3 above, see: > >import std.string; >import std.stdio; > >struct Foo >{ > int x; > int y; > int z; > char[] toString() { return >"("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; >} >} > >class Bar >{ >private: > Foo m_foo; >public: > Foo* foo() { return &m_foo; } > Foo* foo(Foo* value) { m_foo = *value; return foo(); } > Foo* foo(Foo value) { m_foo = value; return foo(); } >} > >void main() >{ > Bar b = new Bar(); > Bar c = new Bar(); > Foo t; > > b.foo.x = 1; > b.foo.y = 2; > b.foo.z = 3; > writefln(b.foo.toString()); > > c.foo = b.foo; > writefln(c.foo.toString()); > > t.x = 4; > t.y = 5; > t.z = 6; > writefln(t.toString()); > > b.foo = t; > writefln(b.foo.toString()); >} > >Note: The explicit "toString" calls are required because otherwise it prints the pointer address. > >Regan |
March 18, 2006 Re: Re: | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hong Wing | On Fri, 17 Mar 2006 06:17:41 +0000 (UTC), Hong Wing <Hong_member@pathlink.com> wrote: > There are 3 drawbacks with the pointer approach > > 1. Noticed that you have 2 versions of the same method, one takes Foo in by pointer and one takes in by value. That is an option, not a drawback. It gives you the _option_ of passing either a pointer to a Foo or a Foo directly. It's more than you could do previously :) > 2. returning pointer would break client code if a field is changed to a > property. How? Can you give me an example of some code, written to use a field, which fails when it becomes a property? (assuming of course that the required operator overloads are added, like the one I show below) If I add: public Foo ffoo; to Bar, I can say: b.ffoo = t; b.ffoo.x = 5; which looks the same as: b.foo = t; b.foo.x = 5; > 3. you cannot call operators from pointers, without adding in * everywhere. Partially true, i.e. when you're trying to add two Foo* together, however you can add the following to the Foo struct to add a Foo* to a Foo: Foo opAdd(Foo rhs) { Foo n; n.x = x+rhs.x; n.y = y+rhs.y; n.z = z+rhs.z; } Foo opAdd(Foo* rhs) { return opAdd(*rhs); } Regan > In article <ops6i24bii23k2f5@nrage.netwin.co.nz>, Regan Heath says... >> >> On Thu, 16 Mar 2006 06:34:34 +0000 (UTC), Hong Wing >> <Hong_member@pathlink.com> wrote: >>> Thanks everyone here for your great work in D, especially Walter who >>> makes it >>> all happen. >>> Here I am requesting a feature, which is "inout variable" and "inout >>> return >>> type" >>> Rationale, for the example below, >>> >>> struct Foo >>> { >>> int x, int y, int z; >>> } >>> >>> class Bar >>> { >>> private: >>> Foo m_foo; >>> public: >>> Foo foo() { return m_foo; } >>> Foo foo(Foo value) { return m_foo = value; } >>> } >>> >>> now if i want to change the value of m_foo.x to 5, i have to do >>> >>> Foo foo = bar.foo; >>> foo.x = 5; >>> bar.foo = foo; >>> >>> it would be nice if I can define a return type as "inout Foo" >>> inout Foo foo() { return m_foo;} >>> >>> To extend it further, one might want to define inout variables as >>> inout Foo foo = bar.foo; >>> >>> Advantages: >>> >>> 1. efficiency, one can directly change the states of the struct instead >>> of >>> making a copy first, change the copy, and put the result back to the >>> struct >>> >>> 2. less buggy, having to type 3 lines always increases chance of bugs, >>> also, >>> someone might inadvertantly do bar.foo.x = 5 and forgot that he is >>> working on a >>> copy >>> >>> 3. reduce the use of pointers, the above can be achieved using pointers, >>> but it >>> means defining two versions of the same method every time a struct >>> property is >>> written. >> >> You're essentially asking for the ability to have variables which are >> references to structs (at least during assignment) and to return >> references to structs, all without using the pointer syntax. I think these >> things are un-necessary, and I think what you want can be achieved with >> pointers, without the penalty you mention in #3 above, see: >> >> import std.string; >> import std.stdio; >> >> struct Foo >> { >> int x; >> int y; >> int z; >> char[] toString() { return >> "("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; >> } >> } >> >> class Bar >> { >> private: >> Foo m_foo; >> public: >> Foo* foo() { return &m_foo; } >> Foo* foo(Foo* value) { m_foo = *value; return foo(); } >> Foo* foo(Foo value) { m_foo = value; return foo(); } >> } >> >> void main() >> { >> Bar b = new Bar(); >> Bar c = new Bar(); >> Foo t; >> >> b.foo.x = 1; >> b.foo.y = 2; >> b.foo.z = 3; >> writefln(b.foo.toString()); >> >> c.foo = b.foo; >> writefln(c.foo.toString()); >> >> t.x = 4; >> t.y = 5; >> t.z = 6; >> writefln(t.toString()); >> >> b.foo = t; >> writefln(b.foo.toString()); >> } >> >> Note: The explicit "toString" calls are required because otherwise it >> prints the pointer address. >> >> Regan > > |
March 18, 2006 Re: Re: | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | On Sat, 18 Mar 2006 23:14:46 +1300, Regan Heath <regan@netwin.co.nz> wrote: >> 3. you cannot call operators from pointers, without adding in * everywhere. I should mention that some operators, i.e. += don't work so well either. So, yeah, there are some problems with the pointer syntax. I think if you're running into these sorts of things you should consider using a class instead of a struct. Regan > Partially true, i.e. when you're trying to add two Foo* together, however you can add the following to the Foo struct to add a Foo* to a Foo: > > Foo opAdd(Foo rhs) > { > Foo n; > > n.x = x+rhs.x; > n.y = y+rhs.y; > n.z = z+rhs.z; > } > > Foo opAdd(Foo* rhs) > { > return opAdd(*rhs); > } > > Regan > > >> In article <ops6i24bii23k2f5@nrage.netwin.co.nz>, Regan Heath says... >>> >>> On Thu, 16 Mar 2006 06:34:34 +0000 (UTC), Hong Wing >>> <Hong_member@pathlink.com> wrote: >>>> Thanks everyone here for your great work in D, especially Walter who >>>> makes it >>>> all happen. >>>> Here I am requesting a feature, which is "inout variable" and "inout >>>> return >>>> type" >>>> Rationale, for the example below, >>>> >>>> struct Foo >>>> { >>>> int x, int y, int z; >>>> } >>>> >>>> class Bar >>>> { >>>> private: >>>> Foo m_foo; >>>> public: >>>> Foo foo() { return m_foo; } >>>> Foo foo(Foo value) { return m_foo = value; } >>>> } >>>> >>>> now if i want to change the value of m_foo.x to 5, i have to do >>>> >>>> Foo foo = bar.foo; >>>> foo.x = 5; >>>> bar.foo = foo; >>>> >>>> it would be nice if I can define a return type as "inout Foo" >>>> inout Foo foo() { return m_foo;} >>>> >>>> To extend it further, one might want to define inout variables as >>>> inout Foo foo = bar.foo; >>>> >>>> Advantages: >>>> >>>> 1. efficiency, one can directly change the states of the struct instead >>>> of >>>> making a copy first, change the copy, and put the result back to the >>>> struct >>>> >>>> 2. less buggy, having to type 3 lines always increases chance of bugs, >>>> also, >>>> someone might inadvertantly do bar.foo.x = 5 and forgot that he is >>>> working on a >>>> copy >>>> >>>> 3. reduce the use of pointers, the above can be achieved using pointers, >>>> but it >>>> means defining two versions of the same method every time a struct >>>> property is >>>> written. >>> >>> You're essentially asking for the ability to have variables which are >>> references to structs (at least during assignment) and to return >>> references to structs, all without using the pointer syntax. I think these >>> things are un-necessary, and I think what you want can be achieved with >>> pointers, without the penalty you mention in #3 above, see: >>> >>> import std.string; >>> import std.stdio; >>> >>> struct Foo >>> { >>> int x; >>> int y; >>> int z; >>> char[] toString() { return >>> "("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; >>> } >>> } >>> >>> class Bar >>> { >>> private: >>> Foo m_foo; >>> public: >>> Foo* foo() { return &m_foo; } >>> Foo* foo(Foo* value) { m_foo = *value; return foo(); } >>> Foo* foo(Foo value) { m_foo = value; return foo(); } >>> } >>> >>> void main() >>> { >>> Bar b = new Bar(); >>> Bar c = new Bar(); >>> Foo t; >>> >>> b.foo.x = 1; >>> b.foo.y = 2; >>> b.foo.z = 3; >>> writefln(b.foo.toString()); >>> >>> c.foo = b.foo; >>> writefln(c.foo.toString()); >>> >>> t.x = 4; >>> t.y = 5; >>> t.z = 6; >>> writefln(t.toString()); >>> >>> b.foo = t; >>> writefln(b.foo.toString()); >>> } >>> >>> Note: The explicit "toString" calls are required because otherwise it >>> prints the pointer address. >>> >>> Regan >> >> > |
March 18, 2006 Re: Re:"inout return type" and "inout variable" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | Hi, yes! exactly that's the problem for me, I am writing a protein modeling software and use vector and matrices heavily, and I start to see things like: *result = (*v1) + (*v2) * (*v3) notice how all the * * * starts to make things very cluttered. The problem also came about when I try to use DTL with structs, I cannot find a way to change a matrix inside a vector efficiently without copying the whole matrix out and copy it back. minTL supports lookup method to get a pointer to the struct, on top of it's [] method. Efficiency is essential for me, Hong Wing In article <ops6lufyj923k2f5@nrage.netwin.co.nz>, Regan Heath says... > >On Sat, 18 Mar 2006 23:14:46 +1300, Regan Heath <regan@netwin.co.nz> wrote: >>> 3. you cannot call operators from pointers, without adding in * everywhere. > >I should mention that some operators, i.e. += don't work so well either. > >So, yeah, there are some problems with the pointer syntax. I think if you're running into these sorts of things you should consider using a class instead of a struct. > >Regan > >> Partially true, i.e. when you're trying to add two Foo* together, however you can add the following to the Foo struct to add a Foo* to a Foo: >> >> Foo opAdd(Foo rhs) >> { >> Foo n; >> >> n.x = x+rhs.x; >> n.y = y+rhs.y; >> n.z = z+rhs.z; >> } >> >> Foo opAdd(Foo* rhs) >> { >> return opAdd(*rhs); >> } >> >> Regan >> >> >>> In article <ops6i24bii23k2f5@nrage.netwin.co.nz>, Regan Heath says... >>>> >>>> On Thu, 16 Mar 2006 06:34:34 +0000 (UTC), Hong Wing >>>> <Hong_member@pathlink.com> wrote: >>>>> Thanks everyone here for your great work in D, especially Walter who >>>>> makes it >>>>> all happen. >>>>> Here I am requesting a feature, which is "inout variable" and "inout >>>>> return >>>>> type" >>>>> Rationale, for the example below, >>>>> >>>>> struct Foo >>>>> { >>>>> int x, int y, int z; >>>>> } >>>>> >>>>> class Bar >>>>> { >>>>> private: >>>>> Foo m_foo; >>>>> public: >>>>> Foo foo() { return m_foo; } >>>>> Foo foo(Foo value) { return m_foo = value; } >>>>> } >>>>> >>>>> now if i want to change the value of m_foo.x to 5, i have to do >>>>> >>>>> Foo foo = bar.foo; >>>>> foo.x = 5; >>>>> bar.foo = foo; >>>>> >>>>> it would be nice if I can define a return type as "inout Foo" >>>>> inout Foo foo() { return m_foo;} >>>>> >>>>> To extend it further, one might want to define inout variables as inout Foo foo = bar.foo; >>>>> >>>>> Advantages: >>>>> >>>>> 1. efficiency, one can directly change the states of the struct >>>>> instead >>>>> of >>>>> making a copy first, change the copy, and put the result back to the >>>>> struct >>>>> >>>>> 2. less buggy, having to type 3 lines always increases chance of bugs, >>>>> also, >>>>> someone might inadvertantly do bar.foo.x = 5 and forgot that he is >>>>> working on a >>>>> copy >>>>> >>>>> 3. reduce the use of pointers, the above can be achieved using >>>>> pointers, >>>>> but it >>>>> means defining two versions of the same method every time a struct >>>>> property is >>>>> written. >>>> >>>> You're essentially asking for the ability to have variables which are >>>> references to structs (at least during assignment) and to return >>>> references to structs, all without using the pointer syntax. I think >>>> these >>>> things are un-necessary, and I think what you want can be achieved with >>>> pointers, without the penalty you mention in #3 above, see: >>>> >>>> import std.string; >>>> import std.stdio; >>>> >>>> struct Foo >>>> { >>>> int x; >>>> int y; >>>> int z; >>>> char[] toString() { return >>>> "("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; >>>> } >>>> } >>>> >>>> class Bar >>>> { >>>> private: >>>> Foo m_foo; >>>> public: >>>> Foo* foo() { return &m_foo; } >>>> Foo* foo(Foo* value) { m_foo = *value; return foo(); } >>>> Foo* foo(Foo value) { m_foo = value; return foo(); } >>>> } >>>> >>>> void main() >>>> { >>>> Bar b = new Bar(); >>>> Bar c = new Bar(); >>>> Foo t; >>>> >>>> b.foo.x = 1; >>>> b.foo.y = 2; >>>> b.foo.z = 3; >>>> writefln(b.foo.toString()); >>>> >>>> c.foo = b.foo; >>>> writefln(c.foo.toString()); >>>> >>>> t.x = 4; >>>> t.y = 5; >>>> t.z = 6; >>>> writefln(t.toString()); >>>> >>>> b.foo = t; >>>> writefln(b.foo.toString()); >>>> } >>>> >>>> Note: The explicit "toString" calls are required because otherwise it prints the pointer address. >>>> >>>> Regan >>> >>> >> > |
March 18, 2006 Re: Re:"inout return type" and "inout variable" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hong Wing | On Sat, 18 Mar 2006 11:02:53 +0000 (UTC), Hong Wing <Hong_member@pathlink.com> wrote: > Hi, yes! exactly that's the problem for me, I am writing a protein modeling software and use vector and matrices heavily, and I start to see things like:*result = (*v1) + (*v2) * (*v3) > > notice how all the * * * starts to make things very cluttered. Yeah, I see the problem. You could call the operator overloads directly, eg. result = v1.opAdd(v2.opMul(v3)); but that's almost as bad. If you have opAdd(T *) and opMul(T *) then doesn't this work: *result = v1 + *v2 * v3; I just tried it, and it seems to (example below). However, isn't your bigger problem all the temporary structs being created and copied in the examples above? eg. (*v2) * (*v3) produces a temporary struct, which is then added to (*v1) producing another temporary struct, which is then copied to *result. Can the compiler ever optimise any of those temporaries away? Example: *result = (*v1) + (*v2) * (*v3) could be rewritten: *result = *v3; //copy struct *result *= v2; //opMulAssign(T *rhs) *result += v1; //opAddAssign(T *rhs) Here the opXAssign operators can access the rhs and add/mul them to/with result directly to avoid the temporary struct copy. Example: import std.string; import std.stdio; struct Foo { int x; int y; int z; char[] toString() { return "("~std.string.toString(x)~","~std.string.toString(y)~","~std.string.toString(z)~")"; } Foo opAdd(Foo rhs) { return opAdd(&rhs); } Foo opAdd(Foo* rhs) { Foo n; n.x = x+rhs.x; n.y = y+rhs.y; n.z = z+rhs.z; return n; } Foo opMul(Foo rhs) { return opAdd(&rhs); } Foo opMul(Foo* rhs) { Foo n; n.x = x*rhs.x; n.y = y*rhs.y; n.z = z*rhs.z; return n; } Foo* opAddAssign(Foo *rhs) { x += rhs.x; y += rhs.y; z += rhs.z; return this; } Foo* opMulAssign(Foo *rhs) { x *= rhs.x; y *= rhs.y; z *= rhs.z; return this; } } class Bar { private: Foo m_foo; public: Foo* foo() { return &m_foo; } Foo* foo(Foo* value) { m_foo = *value; return foo(); } Foo* foo(Foo value) { m_foo = value; return foo(); } } void main() { Foo* a = new Foo(); Bar b = new Bar(); Bar c = new Bar(); Bar d = new Bar(); b.foo.x = 1; b.foo.y = 1; b.foo.z = 1; c.foo.x = 2; c.foo.y = 2; c.foo.z = 2; d.foo.x = 3; d.foo.y = 3; d.foo.z = 3; *a = b.foo + *c.foo * d.foo; writefln("%s",(*a).toString()); *a = *d.foo; *a *= c.foo; *a += b.foo; writefln("%s",(*a).toString()); } Regan |
Copyright © 1999-2021 by the D Language Foundation