www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Lack of struct ctors + overloads

reply "Ben Harper" <ben gls.co.za> writes:
Why should structs not be allowed to have special constructors and 
overloaded operators?
I simply cannot use a language where I cannot say, for instance,
vec3 b = radius * vec3( cos(th), sin(th), 0 );
Now one can do this with classes, so why not with structs? Lack of power for 
value types is a severe shortcoming of a language intended for all-round 
use. It is precisely the point where my interest in D waned.

Ben
May 16 2005
next sibling parent reply xs0 <xs0 xs0.com> writes:
Ben Harper wrote:
 Why should structs not be allowed to have special constructors and 
 overloaded operators?
 I simply cannot use a language where I cannot say, for instance,
 vec3 b = radius * vec3( cos(th), sin(th), 0 );
 Now one can do this with classes, so why not with structs? Lack of power for 
 value types is a severe shortcoming of a language intended for all-round 
 use. It is precisely the point where my interest in D waned.

Why can't you say that? struct vec3 { double x,y,z; public static vec3 opCall(double x, double y, double z) { vec3 result; result.x=x; result.y=y; result.z=z; return result; } public vec3 opMul_r(double a) { vec3 result; result.x=x*a; result.y=y*a; result.z=z*a; return result; } }
May 16 2005
parent "Ben Harper" <ben gls.co.za> writes:
Thanks!
I didn't realize all that.

"xs0" <xs0 xs0.com> wrote in message news:d6a5t6$1oed$1 digitaldaemon.com...
 Ben Harper wrote:
 Why should structs not be allowed to have special constructors and 
 overloaded operators?
 I simply cannot use a language where I cannot say, for instance,
 vec3 b = radius * vec3( cos(th), sin(th), 0 );
 Now one can do this with classes, so why not with structs? Lack of power 
 for value types is a severe shortcoming of a language intended for 
 all-round use. It is precisely the point where my interest in D waned.

Why can't you say that? struct vec3 { double x,y,z; public static vec3 opCall(double x, double y, double z) { vec3 result; result.x=x; result.y=y; result.z=z; return result; } public vec3 opMul_r(double a) { vec3 result; result.x=x*a; result.y=y*a; result.z=z*a; return result; } }

May 16 2005
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 16 May 2005 14:40:44 +0200, Ben Harper wrote:

 Why should structs not be allowed to have special constructors and 
 overloaded operators?
 I simply cannot use a language where I cannot say, for instance,
 vec3 b = radius * vec3( cos(th), sin(th), 0 );
 Now one can do this with classes, so why not with structs? Lack of power for 
 value types is a severe shortcoming of a language intended for all-round 
 use. It is precisely the point where my interest in D waned.

I know what you mean. I have a project that I started out with structs because they are essentially value types being used. However, because I lost a lot of the expressiveness of classes, I converted them to classes. Now I have some non-class-like behaviour happening because to use D effectively I have to. And performance went way down. -- Derek Parnell Melbourne, Australia 16/05/2005 11:21:22 PM
May 16 2005
parent reply "Ben Harper" <ben gls.co.za> writes:
What kind of behaviour do you need? xs0 showed me all I needed to know.

"Derek Parnell" <derek psych.ward> wrote in message 
news:1i39i20d9u84t.1e9owx9xzt1l2.dlg 40tude.net...
 On Mon, 16 May 2005 14:40:44 +0200, Ben Harper wrote:

 Why should structs not be allowed to have special constructors and
 overloaded operators?
 I simply cannot use a language where I cannot say, for instance,
 vec3 b = radius * vec3( cos(th), sin(th), 0 );
 Now one can do this with classes, so why not with structs? Lack of power 
 for
 value types is a severe shortcoming of a language intended for all-round
 use. It is precisely the point where my interest in D waned.

I know what you mean. I have a project that I started out with structs because they are essentially value types being used. However, because I lost a lot of the expressiveness of classes, I converted them to classes. Now I have some non-class-like behaviour happening because to use D effectively I have to. And performance went way down. -- Derek Parnell Melbourne, Australia 16/05/2005 11:21:22 PM

May 16 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 16 May 2005 15:36:12 +0200, Ben Harper wrote:

 What kind of behaviour do you need? xs0 showed me all I needed to know.

What I wanted to code was ... atom A; sequence B; . . . A = 42; B = "test value"; but what I ended up with was ... atom A = new atom; sequence B = new sequence; . . . A.Value = 42; B.Value = "test value"; -- Derek Parnell Melbourne, Australia 16/05/2005 11:38:48 PM
May 16 2005
parent reply "Uwe Salomon" <post uwesalomon.de> writes:
 What I wanted to code was ...

   atom A;
   sequence B;
   . . .
   A = 42;
   B = "test value";

 but what I ended up with was ...

   atom A = new atom;
   sequence B = new sequence;
   . . .
   A.Value = 42;
   B.Value = "test value";

Hmm, you could have used structs with the second syntax as well, couldn't you? struct Atom { private: int m_value = -1; public: void value(int v) { m_value = v; } } That would lead to code like: Atom a; a.value = 42; Another, more constructor-like possibility are functions like these: struct Atom { Atom opCall(int v) { Atom result; result.m_value = v; return result; } // or, better IMO: Atom fromNumber(int v) { Atom result; result.m_value = v; return result; } } Which leads to: Atom a = Atom(42); // or: Atom a = Atom.fromNumber(42); But the property solution will be faster most of the time, i think. Ciao uwe
May 16 2005
parent "Charlie" <charles jwavro.com> writes:
 But the property solution will be faster most of the time, i think.

Or we could get Walter to optimize static opCall , if he hasn't already :). Charlie "Uwe Salomon" <post uwesalomon.de> wrote in message news:op.sqvfrewx6yjbe6 sandmann.maerchenwald.net...
 What I wanted to code was ...

   atom A;
   sequence B;
   . . .
   A = 42;
   B = "test value";

 but what I ended up with was ...

   atom A = new atom;
   sequence B = new sequence;
   . . .
   A.Value = 42;
   B.Value = "test value";

Hmm, you could have used structs with the second syntax as well, couldn't you? struct Atom { private: int m_value = -1; public: void value(int v) { m_value = v; } } That would lead to code like: Atom a; a.value = 42; Another, more constructor-like possibility are functions like these: struct Atom { Atom opCall(int v) { Atom result; result.m_value = v; return result; } // or, better IMO: Atom fromNumber(int v) { Atom result; result.m_value = v; return result; } } Which leads to: Atom a = Atom(42); // or: Atom a = Atom.fromNumber(42); But the property solution will be faster most of the time, i think. Ciao uwe

May 16 2005
prev sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
Walter is it possible to add this
static opCall trick
on the page in doc describing structs?
It is so common that it make sense to explain it there.

Something like:
There are no constructors but you always can emulate
them by static factory alike methods .... including static opCall.

Huh?

Andrew.
May 16 2005
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:d6avah$2h3i$1 digitaldaemon.com...
 Walter is it possible to add this
 static opCall trick
 on the page in doc describing structs?
 It is so common that it make sense to explain it there.

 Something like:
 There are no constructors but you always can emulate
 them by static factory alike methods .... including static opCall.

 Huh?

 Andrew.

Personally I stopped using the "static opCall" trick since it is basically a hack that doesn't always do the right thing. For example it won't be applied when used with "new" (see example below). Plus it just doesn't look nice to have "static opCall" in a struct definition. It's worse than overloading << and >> to do input/output. If I need something like static opCall I use top-level functions. struct Foo { int y; static Foo opCall(int x){ Foo t; t.y = x; return t; } } int main() { Foo* o = new Foo(10); printf("%d\n",o.y); Foo o2 = Foo(10); printf("%d\n",o2.y); return 0; }
May 16 2005
parent reply "Uwe Salomon" <post uwesalomon.de> writes:
 Personally I stopped using the "static opCall" trick since it is  
 basically a
 hack that doesn't always do the right thing.

Yep, as i pointed out in my example, it is *much* better to use static functions like "fromXXX()", because they clearly say what they are doing. And you just have to type ~10 characters more... Ciao uwe
May 16 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Uwe Salomon" <post uwesalomon.de> wrote in message 
news:op.sqv171hy6yjbe6 sandmann.maerchenwald.net...
 Personally I stopped using the "static opCall" trick since it is 
 basically a hack that doesn't always do the right thing.

Yep, as i pointed out in my example, it is *much* better to use static functions like "fromXXX()", because they clearly say what they are doing. And you just have to type ~10 characters more...

That works fine but I actually prefer top-level functions toFoo or even functions with totally different names. For example in MinWin a rectangle is a struct wrapper around the platform-specific rectangle type. Since I can never remember which platform uses top-left-width-height and which use top-left-bottom-right I have two top-level functions Rect LTWH(int left, int top, int width, int right) {...} Rect LTRB(int left, int top, int right, int bottom) {...} that do the transformation on a platform-specific basis. Same thing applies to the Color type Color RGB(int red, int blue, int green) {...} When there isn't a natural top-level function name like those I like toFoo: struct Foo { ... } Foo toFoo(...) {...}
May 16 2005
next sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
  Rect LTWH(int left, int top, int width, int right) {...}
  Rect LTRB(int left, int top, int right, int bottom) {...}
  Color RGB(int red, int blue, int green) {...}

obvious type-replacement transformation to get what I meant.. sorry!
May 16 2005
prev sibling parent reply "Uwe Salomon" <post uwesalomon.de> writes:
 That works fine but I actually prefer top-level functions toFoo or even
 functions with totally different names.

That does the same of course. For types like rectangles and colors this is a fine solution, especially if this is some part of your own program. But if you wrote a library, i would prefer the static member functions, because they do not pollute the top-level namespace (of course this only applies if you not put the functions into an enclosing struct anyways, like Kris in Mango). Imagine a String class for example, with a lot of static toString() functions, they will collide with Phobos' toString(). A static member fromNumber() will never collide. Loose naming is ok for one library, but if you use 4 of 'em, and they were all written this way, you will have some trouble. Perhaps even parts of Phobos need to be rethought, taking that into account? Ciao uwe
May 17 2005
parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Uwe Salomon" <post uwesalomon.de> wrote in message 
news:op.sqwspjir6yjbe6 sandmann.maerchenwald.net...
 That works fine but I actually prefer top-level functions toFoo or even
 functions with totally different names.

That does the same of course. For types like rectangles and colors this is a fine solution, especially if this is some part of your own program. But if you wrote a library, i would prefer the static member functions, because they do not pollute the top-level namespace (of course this only applies if you not put the functions into an enclosing struct anyways, like Kris in Mango). Imagine a String class for example, with a lot of static toString() functions, they will collide with Phobos' toString(). A static member fromNumber() will never collide. Loose naming is ok for one library, but if you use 4 of 'em, and they were all written this way, you will have some trouble.

The names I use like LTWH, RGB and toFoo shouldn't conflict because the only place toFoo appears is in the module defnining Foo. A function like toString is different since the definitions of toString are spread out across many modules and so I agree conflicts will come up more often for them. Personally I've only had a toString conflict when defining a toString method in a class or struct and in that case .toString always solved the problem.
 Perhaps even parts of Phobos need to be rethought, taking that into 
 account?

 Ciao
 uwe 

May 17 2005