Thread overview
[Issue 10404] New: Class!T should be the class version of type T
Jun 19, 2013
irritate
June 18, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404

           Summary: Class!T should be the class version of type T
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: andrei@erdani.com


--- Comment #0 from Andrei Alexandrescu <andrei@erdani.com> 2013-06-18 07:39:05 PDT ---
Given a struct S with state and methods, Class!S should be a type that:

* is a class type
* contains exactly one member, having type S
* has constructors that forward to S's constructors
* has the same methods as S, with implementations that forward to the member's
methods

This offers an immediate means to convert a struct into a class that has the same functionality but typical class semantics (heap allocation, reference semantics, overridable methods etc).

Further ideas:

* define a clone() method that duplicates the state by copying the S member
* allow S to be a primitive type
* offer flags such as "all methods should be overridable" or "all methods
should be final", i.e. Class!(S, ClassOptions.allOverridable) vs. Class!(S,
ClassOptions.allFinal).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404


bearophile_hugs@eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs@eml.cc


--- Comment #1 from bearophile_hugs@eml.cc 2013-06-19 05:25:03 PDT ---
(In reply to comment #0)

> Given a struct S with state and methods, Class!S should be a type that:

Can you list some use cases?


> * contains exactly one member, having type S

Is this going to waste some space because of struct alignment sometimes being higher than the alignment of its members?

Also D classes are free to reorder their fields to pack them (see Issue 8873 ), but if you put the whole D inside the class you lose that optimization.

-----------------

Is it a good idea to also add optional interfaces to Class, as shown below?


import std.stdio, std.math;

interface Shape {}

struct CircleS { int x, y, r; }
alias Circle = Class!(CircleS, Shape);

struct RectS { int x, y, w, h; }
alias Rect = Circle!(RectS, Shape);

real area(in Shape s) {
    if (cast(Circle)s) {
        const c = cast(Circle)s;
        return c.r ^^ 2 * PI;
    } else {
        const r = cast(Rect)s;
        return r.w * r.h;
    }
}

void main() {
    new Circle(5, 10, 20).area.writeln;
}


This is a bit like an Algebraic(Circle, Rect) where Circle and Rect are by
reference...

-----------------

Similarly this is a ClassTuple, it's defined with the syntax of std.typecon.Tuple:

alias Circle2 = ClassTuple!(int,"x", int,"y", int,"r");

But probably this is enough, no need for a ClassTuple:

alias Circle3 = Class!(Tuple!(int,"x", int,"y", int,"r"));

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404


irritate <irritate@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |irritate@gmail.com


--- Comment #2 from irritate <irritate@gmail.com> 2013-06-19 06:13:57 PDT ---
>  has the same methods as S, with implementations that forward to the member's
methods

I think this idea deserves some independent consideration.  It would be nice to have some generic tools for wrapping one type around another with flexibility to automatically override-with-forwarding some/all of its members.

Some brain dump I have about this:

1.  For example, it's very common in Phobos to wrap one range with another.
I'd like to be able to get automatic forwarding members (and custom ones; and
hide some; all at my option) so that my wrapper range can provide the same
functions as my wrapped range without the boilerplate.
2.  In particular I'd like the qualifiers on my wrapper type's members to be
the same as the wrapped ones.  So if my inner range has a const length
property, mine will be made const at instantiation, etc.  (This reminds me of
inout for function parameters).  Maybe this would obviate the need for some of
the rampant Unqual that goes on when wrapping ranges.
3.  I tried to use __traits to creating a wrapping template, but I am an
amateur at this.  I also could not find a good way to define a member with the
same qualifiers as another type's member.
4.  Getting generic functionality for wrapping would align with "prefer
composition to inheritance".

Sorry if I am speaking out of turn.  I have just started looking at issues in Phobos and have already run into these problems with boilerplate/qualifiers with wrapping ranges.  And when I saw this issue for Class!T, I thought maybe wrapping a struct in a class was just a special case of what I wanted with wrapping one type in another.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 19, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404



--- Comment #3 from Andrei Alexandrescu <andrei@erdani.com> 2013-06-19 12:29:39 PDT ---
Update: if a method returns an S by value, the Class!S corresponding wrapper should return a new instance of Class!S with S as payload.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 20, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404


monarchdodra@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra@gmail.com


--- Comment #4 from monarchdodra@gmail.com 2013-06-19 23:34:08 PDT ---
(In reply to comment #3)
> Update: if a method returns an S by value, the Class!S corresponding wrapper should return a new instance of Class!S with S as payload.

I think we're fucked in a lot more cases than just that actually:
- What about functions that take an S by value as an argument? DO we change it
to Class!S, and duplicate the class on receive (pass by value) ?
- Or functions that take an S by ref?
- Or return S by Ref (return this)?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
June 20, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=10404



--- Comment #5 from Andrei Alexandrescu <andrei@erdani.com> 2013-06-20 04:52:34 PDT ---
(In reply to comment #4)
> (In reply to comment #3)
> > Update: if a method returns an S by value, the Class!S corresponding wrapper should return a new instance of Class!S with S as payload.
> 
> I think we're fucked in a lot more cases than just that actually:
> - What about functions that take an S by value as an argument? DO we change it
> to Class!S, and duplicate the class on receive (pass by value) ?
> - Or functions that take an S by ref?
> - Or return S by Ref (return this)?

It's all about reasoning through the cases. We may conservatively not generate wrappers for such functions, or generate them with a specific semantics.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------