digitalmars.D.learn - Struct "inheritance"
- Vidar Wahlberg (33/33) Feb 04 2012 Good day.
- Trass3r (2/5) Feb 04 2012 The other big difference is value vs. reference type.
- =?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?= (20/53) Feb 04 2012 It seems that what you want is alias this:
- Vidar Wahlberg (61/62) Feb 04 2012 Thank you both, that's exactly what I needed.
- bearophile (15/32) Feb 04 2012 This works:
- =?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?= (20/82) Feb 04 2012 e =
- Vidar Wahlberg (39/46) Feb 04 2012 You are correct, my apologies for not testing more thoroughly.
- =?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?= (14/34) Feb 04 2012 I see. There's a hint in the error message: "function expected [...],
- Vidar Wahlberg (17/24) Feb 05 2012 Sending this again, got an error the first time and it appears like it
- =?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?= (14/26) Feb 05 2012 Not that I know.
- Vidar Wahlberg (16/33) Feb 05 2012 Possibly something that could make the language slightly more newbie
- Daniel Murphy (7/13) Feb 05 2012 The names only need to match if the compiler/build tool has to find the
- Vidar Wahlberg (12/17) Feb 05 2012 Actually, that is what I do. GDC does not seem to figure it out:
- Daniel Murphy (3/20) Feb 05 2012 I guess you've found a bug then. :)
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (39/52) Feb 04 2012 There is also template mixins to inject complete features into the code
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (3/5) Feb 04 2012 That should be "... you could write *ints* everywhere".
Good day. I know "inheritance" is a misleading word as there's no such thing when it comes to structs, but I couldn't think of a better description for this problem: Let's say I got a struct for a location on a 2-dimensional plane: struct Point { int x; int y; } Further I also need to represent a location in a 3-dimensional space: struct Coordinate { int x; int y; int z; } If these were classes instead I could simply make Coordinate inherit from Point and only add "int z;". This would also make the thing I'm trying to achieve much easier; Consider I have a method that does something nifty with "x" and "y", I'd like this method to handle both "Point" and "Coordinate", if they were classes it would be fairly simple: int somethingNifty(Point p) { return p.x + p.y; } So why not just use classes? I've understood it as there may be a performance gain by using structs over classes, and in my program Point and Coordinate are used heavily. Obviously I'm fairly new to both D and structs, I have plenty Java and some C++ experience (I've avoided using structs in C++) and I have "The D Programming Language" book by Andrei which I'm happy to look up in, although I've failed to find an answer to this question in the book, in this newsgroup and on the net. I would greatly appreciate if someone could give me a nudge the the right direction.
Feb 04 2012
So why not just use classes? I've understood it as there may be a performance gain by using structs over classes, and in my program Point and Coordinate are used heavily.The other big difference is value vs. reference type. You can use alias this to achieve something like "struct inheritance".
Feb 04 2012
On Sat, 04 Feb 2012 12:38:30 +0100, Vidar Wahlberg <canidae exent.net> wrote:Good day. I know "inheritance" is a misleading word as there's no such thing when it comes to structs, but I couldn't think of a better description for this problem: Let's say I got a struct for a location on a 2-dimensional plane: struct Point { int x; int y; } Further I also need to represent a location in a 3-dimensional space: struct Coordinate { int x; int y; int z; } If these were classes instead I could simply make Coordinate inherit from Point and only add "int z;". This would also make the thing I'm trying to achieve much easier; Consider I have a method that does something nifty with "x" and "y", I'd like this method to handle both "Point" and "Coordinate", if they were classes it would be fairly simple: int somethingNifty(Point p) { return p.x + p.y; } So why not just use classes? I've understood it as there may be a performance gain by using structs over classes, and in my program Point and Coordinate are used heavily. Obviously I'm fairly new to both D and structs, I have plenty Java and some C++ experience (I've avoided using structs in C++) and I have "The D Programming Language" book by Andrei which I'm happy to look up in, although I've failed to find an answer to this question in the book, in this newsgroup and on the net. I would greatly appreciate if someone could give me a nudge the the right direction.It seems that what you want is alias this: struct Point { int x; int y; } struct Coordinate { Point pt; int z; alias pt this; } void foo( Point p ) {} void main( ) { Coordinate c; foo( c ); c.x = 3; c.y = 4; c.z = 5; }
Feb 04 2012
On 2012-02-04 13:06, Simen Kjærås wrote:It seems that what you want is alias this:Thank you both, that's exactly what I needed. Leeching a bit more on the thread: Going back to the method: int somethingNifty(Point p) { return p.x + p.y; } Let's say I have the following code: for (x; 0 .. 10) { for (y; 0 .. 10) { Point p = {x, y}; somethingNifty(p); } } [How] can you rewrite those two statements inside the loops to a single line? For example (this doesn't work): somethingNifty(Point(x, y)); And finally a question about operator overloading, here's the code for "Coordinate" ("Point" is similar in structure): import Point; struct Coordinate { Point _point; int _z; property auto point() const { return _point; } property auto point(Point point) { return _point = point; } property auto z() const { return _z; } property auto z(int z) { return _z = z; } bool opEquals(ref const Coordinate c) const { return z == c.z && point == c.point; } } Compilation fails with the following error: Coordinate.d:18: Error: function Point.Point.opEquals (ref const const(Point) p) const is not callable using argument types (const(Point)) const Coordinate.d:18: Error: c.point() is not an lvalue Noteworthy the code compiles fine if i replace "point" and "c.point" with "_point" and "c._point", but then I'm referencing _point directly instead of through the property "point" (which may do something else than just return _point in the future). I've looked at http://www.d-programming-language.org/operatoroverloading.html#equals and that page is slightly confusing. It claims that: If structs declare an opEquals member function, it should follow the following form: struct S { int opEquals(ref const S s) { ... } } However, I can't even get the code to compile if I do that, the compiler (gdc-4.6) says: Error: function Coordinate.Coordinate.opEquals type signature should be const bool(ref const(Coordinate)) not int(ref const const(Coordinate) c) I hope it's somewhat clear what I'm trying to achieve.
Feb 04 2012
Vidar Wahlberg:Leeching a bit more on the thread: Going back to the method: int somethingNifty(Point p) { return p.x + p.y; } Let's say I have the following code: for (x; 0 .. 10) { for (y; 0 .. 10) { Point p = {x, y}; somethingNifty(p); } } [How] can you rewrite those two statements inside the loops to a single line? For example (this doesn't work): somethingNifty(Point(x, y));This works: struct Point { int x, y; } int somethingNifty(Point p) { return p.x + p.y; } void main( ) { foreach (x; 0 .. 10) foreach (y; 0 .. 10) somethingNifty(Point(x, y)); } Bye, bearophile
Feb 04 2012
On Sat, 04 Feb 2012 13:55:55 +0100, Vidar Wahlberg <canidae exent.net> = wrote:On 2012-02-04 13:06, Simen Kj=C3=A6r=C3=A5s wrote:e =It seems that what you want is alias this:Thank you both, that's exactly what I needed. Leeching a bit more on the thread: Going back to the method: int somethingNifty(Point p) { return p.x + p.y; } Let's say I have the following code: for (x; 0 .. 10) { for (y; 0 .. 10) { Point p =3D {x, y}; somethingNifty(p); } } [How] can you rewrite those two statements inside the loops to a singl=line? For example (this doesn't work): somethingNifty(Point(x, y));Like bearophile said, Point(x, y) should work - assuming you have defined no other constructors for Point. You can also explicitly define a constructor that does what you want.And finally a question about operator overloading, here's the code for=="Coordinate" ("Point" is similar in structure): import Point; struct Coordinate { Point _point; int _z; property auto point() const { return _point; } property auto point(Point point) { return _point =3D point; } property auto z() const { return _z; } property auto z(int z) { return _z =3D z; } bool opEquals(ref const Coordinate c) const { return z =3D=3D c.z && point =3D=3D c.point; } } Compilation fails with the following error: Coordinate.d:18: Error: function Point.Point.opEquals (ref const =const(Point) p) const is not callable using argument types =(const(Point)) const Coordinate.d:18: Error: c.point() is not an lvalue Noteworthy the code compiles fine if i replace "point" and "c.point" =with "_point" and "c._point", but then I'm referencing _point directly==instead of through the property "point" (which may do something else =than just return _point in the future). I've looked at =http://www.d-programming-language.org/operatoroverloading.html#equals ==and that page is slightly confusing. It claims that: If structs declare an opEquals member function, it should follow the =following form: struct S { int opEquals(ref const S s) { ... } } However, I can't even get the code to compile if I do that, the compil=er =(gdc-4.6) says: Error: function Coordinate.Coordinate.opEquals type signature should b=e =const bool(ref const(Coordinate)) not int(ref const const(Coordinate) =c)I hope it's somewhat clear what I'm trying to achieve.It is. The problem is that bool opEquals(ref const Point) expects a Poin= t by reference, and the return value from your property is a temporary, fr= om which we can get no reference. The solution is to remove the ref: bool opEquals(const Point). The only reason to use ref here is to cut do= wn on copying, and might be worthwhile on larger structures.
Feb 04 2012
On 2012-02-04 14:45, Simen Kjærås wrote:Like bearophile said, Point(x, y) should work - assuming you have defined no other constructors for Point.You are correct, my apologies for not testing more thoroughly. Let me try again, explaining the real issue: I have 3 files: -- Bar.d -- import Foo; import Struct; class Bar { Foo _foo; this() { _foo = new Foo(Struct(1)); } } void main() { new Bar(); } -- Foo.d -- import Struct; class Foo { Struct _s; this(Struct s) { _s = s; } } -- Struct.d -- struct Struct { int baz; } This code does not compile: Bar.d:6: Error: function expected before (), not module Struct of type void Bar.d:6: Error: constructor Foo.Foo.this (Struct s) is not callable using argument types (_error_) Why is that?It is. The problem is that bool opEquals(ref const Point) expects a Point by reference, and the return value from your property is a temporary, from which we can get no reference. The solution is to remove the ref: bool opEquals(const Point). The only reason to use ref here is to cut down on copying, and might be worthwhile on larger structures.I've tried removing the "ref", but I get other errors in return then: Point.d:19: Error: function Point.Point.opEquals type signature should be const bool(ref const(Point)) not const bool(const const(Point) p) Coordinate.d:20: Error: function Coordinate.Coordinate.opEquals type signature should be const bool(ref const(Coordinate)) not const bool(const const(Coordinate) c)
Feb 04 2012
On Sat, 04 Feb 2012 15:04:50 +0100, Vidar Wahlberg <canidae exent.net> wrote:This code does not compile: Bar.d:6: Error: function expected before (), not module Struct of type void Bar.d:6: Error: constructor Foo.Foo.this (Struct s) is not callable using argument types (_error_) Why is that?I see. There's a hint in the error message: "function expected [...], not module". Struct is the name of a module, so the compiler thinks you want to access something inside it. If you want 'Struct' to refer to the type, you must use selective import[1]: import Struct : Struct; This says 'I want only the type Struct from the module Struct, not everything else in there.' The other solution is to simply use different names for the type and the module.I cannot seem to recreate this error message. Which version of the compiler are you using? [1]: http://www.d-programming-language.org/module.html#ImportDeclarationIt is. The problem is that bool opEquals(ref const Point) expects a Point by reference, and the return value from your property is a temporary, from which we can get no reference. The solution is to remove the ref: bool opEquals(const Point). The only reason to use ref here is to cut down on copying, and might be worthwhile on larger structures.I've tried removing the "ref", but I get other errors in return then: Point.d:19: Error: function Point.Point.opEquals type signature should be const bool(ref const(Point)) not const bool(const const(Point) p) Coordinate.d:20: Error: function Coordinate.Coordinate.opEquals type signature should be const bool(ref const(Coordinate)) not const bool(const const(Coordinate) c)
Feb 04 2012
Sending this again, got an error the first time and it appears like it was not sent. On 2012-02-04 21:48, Simen Kjærås wrote:I see. There's a hint in the error message: "function expected [...], not module". Struct is the name of a module, so the compiler thinks you want to access something inside it. If you want 'Struct' to refer to the type, you must use selective import[1]: import Struct : Struct;I see, thanks, that does solve the problem. It is slightly confusing that you don't get this kind of error for "Foo" in "Bar.d", though (compiler seems to understand that I mean the class "Foo" rather than the module "Foo" in this code: "_foo = new Foo(Struct(1))"). Also, is this really ambiguous? Are there any cases where you can have a module name followed by a parentheses, i.e. "<module>("?I cannot seem to recreate this error message. Which version of the compiler are you using?I'm using gdc-4.6 (Debian 4.6.2-4). Using the Struct from above I can easily recreate the error: struct Struct { int baz; bool opEquals(const Struct s) const { return baz == s.baz; } }
Feb 05 2012
On Sun, 05 Feb 2012 11:58:40 +0100, Vidar Wahlberg <canidae exent.net> wrote:Also, is this really ambiguous? Are there any cases where you can have a module name followed by a parentheses, i.e. "<module>("?Not that I know.> I cannot seem to recreate this error message. Which version of the > compiler are you using? I'm using gdc-4.6 (Debian 4.6.2-4). Using the Struct from above I can easily recreate the error: struct Struct { int baz; bool opEquals(const Struct s) const { return baz == s.baz; } }Ah. That's the equivalent of DMD 2.054. I don't have that installed, but it may be that this feature was not added until after that. Fix: install GDC 4.6.1: https://bitbucket.org/goshawk/gdc/downloads Workaround: Use a templated opEquals: struct Struct { int baz; bool opEquals()(const Struct s) const { return baz == s.baz; } } Hope this works.
Feb 05 2012
On 2012-02-05 14:16, Simen Kjærås wrote:On Sun, 05 Feb 2012 11:58:40 +0100, Vidar Wahlberg <canidae exent.net> wrote:Possibly something that could make the language slightly more newbie friendly here, then. For now I'll just keep the filenames in lowercase so i "import struct;" rather than "import Struct;" (I see the norm for D is to keep the filenames in lowercase, might as well follow it). Adding a note about GDC (4.6.2) here: It appears like it ignores "module <name>;" and always use the filename for module name (or I've misunderstood what "module" is used for). If I create a file "Foo.d" which contains "module foo;", then in any other file I wish to include module "foo" in I must write "include Foo;", not "include foo;".Also, is this really ambiguous? Are there any cases where you can have a module name followed by a parentheses, i.e. "<module>("?Not that I know.I'm running GDC 4.6.2, not 4.6.0 (I just pasted output from "gdc-4.6 --version", I could've made it clearer), downgrading probably won't help me.I'm using gdc-4.6 (Debian 4.6.2-4).Ah. That's the equivalent of DMD 2.054. I don't have that installed, but it may be that this feature was not added until after that. Fix: install GDC 4.6.1: https://bitbucket.org/goshawk/gdc/downloadsWorkaround: Use a templated opEquals: struct Struct { int baz; bool opEquals()(const Struct s) const { return baz == s.baz; } } Hope this works.Yes, it does. I have to read a bit about templating as I don't understand exactly what that "()" means, but it did solve my problem, thanks!
Feb 05 2012
"Vidar Wahlberg" <canidae exent.net> wrote in message news:jgm2qk$c2g$1 digitalmars.com...Adding a note about GDC (4.6.2) here: It appears like it ignores "module <name>;" and always use the filename for module name (or I've misunderstood what "module" is used for). If I create a file "Foo.d" which contains "module foo;", then in any other file I wish to include module "foo" in I must write "include Foo;", not "include foo;".The names only need to match if the compiler/build tool has to find the module itself. If you call the compiler with all modules listed: gdc bar.d Foo.d etc.d then it should be able to work it out. (This is how it works with dmd, anyway. GDC is probably the same)
Feb 05 2012
On 2012-02-05 15:19, Daniel Murphy wrote:The names only need to match if the compiler/build tool has to find the module itself. If you call the compiler with all modules listed: gdc bar.d Foo.d etc.d then it should be able to work it out. (This is how it works with dmd, anyway. GDC is probably the same)Actually, that is what I do. GDC does not seem to figure it out: naushika:~/tmp> cat Foo.d module foo; ... naushika:~/tmp> gdc-4.6 bar.d Foo.d baz.d bar.d:2: Error: module foo is in file 'foo.d' which cannot be read import path[0] = /usr/include/d2/4.6/x86_64-linux-gnu import path[1] = /usr/include/d2/4.6 naushika:~/tmp> mv Foo.d foo.d naushika:~/tmp> gdc-4.6 bar.d foo.d baz.d naushika:~/tmp>
Feb 05 2012
I guess you've found a bug then. :) "Vidar Wahlberg" <canidae exent.net> wrote in message news:jgm7sh$k4u$1 digitalmars.com...On 2012-02-05 15:19, Daniel Murphy wrote:The names only need to match if the compiler/build tool has to find the module itself. If you call the compiler with all modules listed: gdc bar.d Foo.d etc.d then it should be able to work it out. (This is how it works with dmd, anyway. GDC is probably the same)Actually, that is what I do. GDC does not seem to figure it out: naushika:~/tmp> cat Foo.d module foo; ... naushika:~/tmp> gdc-4.6 bar.d Foo.d baz.d bar.d:2: Error: module foo is in file 'foo.d' which cannot be read import path[0] = /usr/include/d2/4.6/x86_64-linux-gnu import path[1] = /usr/include/d2/4.6 naushika:~/tmp> mv Foo.d foo.d naushika:~/tmp> gdc-4.6 bar.d foo.d baz.d naushika:~/tmp>
Feb 05 2012
On 02/04/2012 03:38 AM, Vidar Wahlberg wrote:Let's say I got a struct for a location on a 2-dimensional plane: struct Point { int x; int y; } Further I also need to represent a location in a 3-dimensional space: struct Coordinate { int x; int y; int z; } If these were classes instead I could simply make Coordinate inherit from Point and only add "int z;".There is also template mixins to inject complete features into the code (similar to C macros but without their gotchas). The following templatizes the coordinate types, but you could use put write everywhere: import std.stdio; template Point2D(T) { T x; T y; void foo2D() { writefln("Using (%s,%s)", x, y); } } struct Coordinate(T) { mixin Point2D!T; // <-- Inject x, y, and foo2D() here T z; this(T x, T y, T z) { this.x = x; this.y = y; this.z = z; } } void main() { auto c = Coordinate!double(1.1, 2.2, 3.3); c.foo2D(); } You could insert the following line in any other scope and you would have x, y, foo2D() inserted right there as well: if (someCondition) { mixin Point2D!T; // <-- Inject x, y, and foo2D() here // ... use the local x, y, and foo2D() here } Of course 'static if' may be even more suitable in other cases. Ali
Feb 04 2012
On 02/04/2012 08:25 AM, Ali Çehreli wrote:The following templatizes the coordinate types, but you could use put write everywhere:That should be "... you could write *ints* everywhere". Ali
Feb 04 2012