digitalmars.D - "inout return type" and "inout variable"
- Hong Wing (34/34) Mar 15 2006 Thanks everyone here for your great work in D, especially Walter who mak...
- Ben Phillips (3/37) Mar 16 2006 This is a good suggestion imho and is probably fairly easy for Walter to
- Regan Heath (52/94) Mar 16 2006 You're essentially asking for the ability to have variables which are
- Hong Wing (7/111) Mar 16 2006 There are 3 drawbacks with the pointer approach
- Regan Heath (33/155) Mar 18 2006 That is an option, not a drawback. It gives you the _option_ of passing ...
- Regan Heath (6/143) Mar 18 2006 I should mention that some operators, i.e. += don't work so well either.
- Hong Wing (11/159) Mar 18 2006 Hi, yes! exactly that's the problem for me, I am writing a protein model...
- Regan Heath (116/120) Mar 18 2006 Yeah, I see the problem.
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.
Mar 15 2006
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.
Mar 16 2006
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 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.str ng.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
Mar 16 2006
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 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.str ng.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
Mar 16 2006
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); } ReganIn 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 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
Mar 18 2006
On Sat, 18 Mar 2006 23:14:46 +1300, Regan Heath <regan netwin.co.nz> wrote: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. Regan3. 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); } ReganIn 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 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
Mar 18 2006
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: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. Regan3. 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); } ReganIn 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 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
Mar 18 2006
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.str ng.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
Mar 18 2006