www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - object oriented value type

reply Ender KaShae <astrothayne gmail.com> writes:
I find it a little disappointing that D does not have any support for the C++
way of object oriented value types, both c# and D have structs that pass by
value but do not support inheritance and classes passed by reference that do
support inheritance, D adds injury to insult by prohibiting hidden members in
structs.  But what about when you need a type that passes by value and supports
inheritance, I don't think that the structs necessarily need to be changed,
rathe I think that a new type should be created as a combination of a struct
and a class.  This would be particularly useful in inheriting from primitave
types.  Another example is having a mixedFraction inherit from fraction.
Jun 25 2007
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
What's the point? There's no way to refer to a subtype by the supertype (since
the compiler wouldn't know what size the struct would be), so the only OO
feature you'd get is mere aggregation, which should be explicit anyway.

You can have private struct functions/members - all the privacy concerns are at
the module level, so a private struct member is module-private, just as a
private class member is.

I do think having a syntax to add properties to primitive types is a good idea,
though, in the same way as the funky array syntax works now.

Ender KaShae Wrote:

 I find it a little disappointing that D does not have any support for the C++
way of object oriented value types, both c# and D have structs that pass by
value but do not support inheritance and classes passed by reference that do
support inheritance, D adds injury to insult by prohibiting hidden members in
structs.  But what about when you need a type that passes by value and supports
inheritance, I don't think that the structs necessarily need to be changed,
rathe I think that a new type should be created as a combination of a struct
and a class.  This would be particularly useful in inheriting from primitave
types.  Another example is having a mixedFraction inherit from fraction.
Jun 25 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Robert,

 I do think having a syntax to add properties to primitive types is a
 good idea, though, in the same way as the funky array syntax works
 now.
how about |typedef int myInt |{ | static addCount=0; // static members? why not? | | myInt opAdd(myInt that) | { | addCount++; | return this+that; // this is int | } | private opMod(); // forbid mod on myInt |} added in template typedefs: |typedef real SIuint(int dist, int mass, int time) |{ | SIuint!(dist+T.dist, mass+T.mass, time+T.time) opMull(T)(T p) // in-lining reduces to same as normal mul | { | return this*p; | } |} and some really cool stuff starts happening
Jun 25 2007
next sibling parent reply Henning Hasemann <hhasemann web.de> writes:
BCS <ao pathlink.com> schrieb (Mon, 25 Jun 2007 19:10:54 +0000 (UTC)):
 Reply to Robert,
 
 I do think having a syntax to add properties to primitive types is a
 good idea, though, in the same way as the funky array syntax works
 now.
Wouldnt it be more straigtforward if there were no basic types at all? Ok, you then run into the OO-value-type question again, but somithing like (to follow the example below) // No special syntax needed to declare that this is a value type as it // inherits from one (int) class MyInt : int { static addCount = 0; MyInt opAdd(MyInt that) { addCount++; return this.value + that.value; } }
 how about 
 
 |typedef int myInt
 |{
 |  static addCount=0; // static members? why not?
 |
 |  myInt opAdd(myInt that)
 |  {
 |     addCount++;
 |     return this+that; // this is int
That would be a bit confusing at it looks like recursion.
 |  }
 |  private opMod(); // forbid mod on myInt
 |}
 
 added in template typedefs:
 
 |typedef real SIuint(int dist, int mass, int time)
 |{
 |   SIuint!(dist+T.dist, mass+T.mass, time+T.time) opMull(T)(T p)  //
 in-lining reduces to same as normal mul
 |   {
 |      return this*p;
 |   }
 |}
I must confess I dont think that I understand your example. Would that allow multiplying integers with units? Henning -- GPG Public Key: http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
Jun 25 2007
parent BCS <ao pathlink.com> writes:
Reply to Henning,

 BCS <ao pathlink.com> schrieb (Mon, 25 Jun 2007 19:10:54 +0000 (UTC)):
 
 Reply to Robert,
 
 I do think having a syntax to add properties to primitive types is a
 good idea, though, in the same way as the funky array syntax works
 now.
 
Wouldnt it be more straigtforward if there were no basic types at all? Ok, you then run into the OO-value-type question again, but somithing like (to follow the example below) // No special syntax needed to declare that this is a value type as it // inherits from one (int) class MyInt : int { static addCount = 0; MyInt opAdd(MyInt that) { addCount++; return this.value + that.value; } }
that would be vary hard to make work well in a systems language. the point of the typedef I J {...} would be to let the user change (at compile time) the semantics of the the built in types.
 how about
 
 |typedef int myInt
 |{
 |  static addCount=0; // static members? why not?
 |
 |  myInt opAdd(myInt that)
 |  {
 |     addCount++;
 |     return this+that; // this is int
That would be a bit confusing as it looks like recursion.
okay make it: return cast(int)this+cast(int)that;
 |  }
 |  private opMod(); // forbid mod on myInt
 |}
 added in template typedefs:
 
 |typedef real SIuint(int dist, int mass, int time)
 |{
 |   SIuint!(dist+T.dist, mass+T.mass, time+T.time) opMull(T)(T p)
 |      // in-lining reduces to same as normal mul
 |   {
 |      return this*p;
 |   }
 |}
I must confess I dont think that I understand your example. Would that allow multiplying integers with units?
Oh please don't nit pick <g> I just slaped that togehter. SIuint!(dist+Tdist, mass+Tmass, time+Ttime) opMull(int Tdist, int Tmass, int Ttime)(SIunit!(Tdist, Tmass, Ttime) p) some sort of int == SIUnit!(0,0,0) would be needed to.
Jun 25 2007
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Interesting, interesting... There are more than a few places I've used a struct
to wrap a single primitive value/enum so that I could make it typesafe and add
methods to it, so I guess that isn't too fundamentally different, though it's
much cleaner.

Still, the advantage of giving array-function-style syntax can be seen when
it's used on a literal. Consider something like:

void times(int n, void delegate() action)
{
    for(int i = 0; i < n; i++)
        action();
}

3.times({writefln("Why, hello there!");});

...or, perhaps more useful

Very Ruby-esque, but clean in its own way. It reads quite like English,
actually. Well, except for all those funky brackets & semicolons...

BCS Wrote:

 how about 
 
 |typedef int myInt
 |{
 |  static addCount=0; // static members? why not?
 |
 |  myInt opAdd(myInt that)
 |  {
 |     addCount++;
 |     return this+that; // this is int
 |  }
 |  private opMod(); // forbid mod on myInt
 |}
 
 added in template typedefs:
 
 |typedef real SIuint(int dist, int mass, int time)
 |{
 |   SIuint!(dist+T.dist, mass+T.mass, time+T.time) opMull(T)(T p)  //
in-lining 
 reduces to same as normal mul
 |   {
 |      return this*p;
 |   }
 |}
 
 and  some really cool stuff starts happening
 
 
Jun 26 2007
prev sibling next sibling parent reply Ender KaShae <astrothayne gmail.com> writes:
Robert Fraser Wrote:

 What's the point? There's no way to refer to a subtype by the supertype (since
the compiler wouldn't know what size the struct would be), so the only OO
feature you'd get is mere aggregation, which should be explicit anyway.
Then how does c++ do it?
 Ender KaShae Wrote:
 
   But what about when you need a type that passes by value and supports
inheritance, I don't think that the structs necessarily need to be changed,
rather I think that a new type should be created as a combination of a struct
and a class.  This would be particularly useful in inheriting from primitave
types.  Another example is having a mixedFraction inherit from fraction.
maybe a copy constructer and assignment overloading for classes would solve the problem, though there should be a keyword (say passbyvalue) that autamates the constructor the way c++ does.
Jun 29 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Ender KaShae Wrote:

 Robert Fraser Wrote:
 
 What's the point? There's no way to refer to a subtype by the supertype (since
the compiler wouldn't know what size the struct would be), so the only OO
feature you'd get is mere aggregation, which should be explicit anyway.
Then how does c++ do it?
C++ slices off subclass fields if assigned to a superclass type. If class Foo has a field x and class Bar, which extends Foo, has a field y, then: Foo f = Bar(); will only store the value of x, not y.
Jun 29 2007
prev sibling next sibling parent Ender KaShae <astrothayne gmail.com> writes:
The easiest solution I can see is to use reflection to autamaticly generate
opAssign() to assign a deep copy.
Jun 29 2007
prev sibling next sibling parent reply Tristam MacDonald <swiftcoder gmail.com> writes:
Maybe inheritance is not so useful, but constructor/destructor/opAssign for
structs would be nice, as lightweight value types with the ability to manage
resources are very handy...

Robert Fraser Wrote:
 What's the point? There's no way to refer to a subtype by the supertype (since
the compiler wouldn't know what size the struct would be), so the only OO
feature you'd get is mere aggregation, which should be explicit anyway.
 
 You can have private struct functions/members - all the privacy concerns are
at the module level, so a private struct member is module-private, just as a
private class member is.
 
 I do think having a syntax to add properties to primitive types is a good
idea, though, in the same way as the funky array syntax works now.
 
 Ender KaShae Wrote:
 
 I find it a little disappointing that D does not have any support for the C++
way of object oriented value types, both c# and D have structs that pass by
value but do not support inheritance and classes passed by reference that do
support inheritance, D adds injury to insult by prohibiting hidden members in
structs.  But what about when you need a type that passes by value and supports
inheritance, I don't think that the structs necessarily need to be changed,
rathe I think that a new type should be created as a combination of a struct
and a class.  This would be particularly useful in inheriting from primitave
types.  Another example is having a mixedFraction inherit from fraction.
Jun 30 2007
next sibling parent Johan Granberg <lijat.meREM OVEgmail.com> writes:
Tristam MacDonald wrote:

 Maybe inheritance is not so useful, but constructor/destructor/opAssign
 for structs would be nice, as lightweight value types with the ability to
 manage resources are very handy...
I totally agree and hope that this gets added.
Jun 30 2007
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Tristam MacDonald" <swiftcoder gmail.com> wrote in message 
news:f666iv$2r1m$1 digitalmars.com...
 Maybe inheritance is not so useful, but constructor/destructor/opAssign 
 for structs would be nice, as lightweight value types with the ability to 
 manage resources are very handy...
The current behavior of opAssign not what you need? Ctors/dtors for structs are supposedly coming, but who knows when..
Jun 30 2007
prev sibling parent reply Ender KaShae <astrothayne gmail.com> writes:
From the replies to this thread I can see that my object oriented struct would
be very difficult if not impossible to implement so I am suggesting the
following instead:

1. either:
    a) a copy construtor [ this(classtype value) ] that is called durring
assignment
   or b) opAssign can be used for the same class
2. ability to inherit from primative types 
Jul 02 2007
parent reply Reiner Pope <some address.com> writes:
Ender KaShae wrote:
 From the replies to this thread I can see that my object oriented struct would
be very difficult if not impossible to implement so I am suggesting the
following instead:
 
 1. either:
     a) a copy construtor [ this(classtype value) ] that is called durring
assignment
    or b) opAssign can be used for the same class
 2. ability to inherit from primative types 
I'm not sure what's wrong with genuine struct inheritance -- but not for polymorphism, just for code reuse. This would just be syntactic sugar for template mixins. Instead of: template impl { int x; bool xEven() { return (x % 2) == 0; } } struct Foo { mixin impl; } struct Bar { mixin impl; int y; } (which currently works in D) why not allow struct Foo { int x; bool xEven() { return (x % 2) == 0; } } struct Bar : Foo { int y; } Actually, this could be implemented better than a wrapper for mixins, because you don't need the source-code available. The compiler could effectively convert the above snippet into struct Bar { private Foo __f; alias __f.x x; alias __f.xEven xEven; int y; } (Although those aliases don't currently work in D, I think they capture the idea.) And primitive types work naturally as structs, so inheriting from them is fine as well. -- Reiner
Jul 12 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Reiner,

 I'm not sure what's wrong with genuine struct inheritance -- but not
 for polymorphism, just for code reuse. This would just be syntactic
 sugar for template mixins. Instead of:
 
This would even act more or less as expected if everything is implicitly un overrideable. Cast to base type, OK (and implicit). Cast to derived type, Do at your own risk (no null on bad cast).
 
 And primitive types work naturally as structs, so inheriting from them
 is fine as well.
OOhhhh. Cool. <g>
 
 -- Reiner
 
Jul 12 2007
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
That is a _really_ good idea, and doesn't sound that hard to implement. votes++

Reiner Pope Wrote:

 Ender KaShae wrote:
 From the replies to this thread I can see that my object oriented struct would
be very difficult if not impossible to implement so I am suggesting the
following instead:
 
 1. either:
     a) a copy construtor [ this(classtype value) ] that is called durring
assignment
    or b) opAssign can be used for the same class
 2. ability to inherit from primative types 
I'm not sure what's wrong with genuine struct inheritance -- but not for polymorphism, just for code reuse. This would just be syntactic sugar for template mixins. Instead of: template impl { int x; bool xEven() { return (x % 2) == 0; } } struct Foo { mixin impl; } struct Bar { mixin impl; int y; } (which currently works in D) why not allow struct Foo { int x; bool xEven() { return (x % 2) == 0; } } struct Bar : Foo { int y; } Actually, this could be implemented better than a wrapper for mixins, because you don't need the source-code available. The compiler could effectively convert the above snippet into struct Bar { private Foo __f; alias __f.x x; alias __f.xEven xEven; int y; } (Although those aliases don't currently work in D, I think they capture the idea.) And primitive types work naturally as structs, so inheriting from them is fine as well. -- Reiner
Jul 13 2007