DMD 0.177 release

Pragma ericanderton at yahoo.removeme.com
Tue Dec 12 07:29:55 PST 2006


Stewart Gordon wrote:
> Pragma wrote:
> <snip>
>> But I'd like to echo the other comments in this thread regarding 
>> structs.  IMO, we're not there yet.  I think folks are looking for a 
>> solution that does this:
>>
>> - A ctor like syntax for creating a new struct
>> - No more forced copy of the entire struct on creation
> 
> What do you mean by this?

I'm glad you asked. :)

Static opCall() is not a ctor.  It never was.  People have been 
clamoring to be able to use this() inside of a struct, much like they 
can with classes and modules.  But the desire here goes beyond mere 
symmetry between type definitions.

The forced copy issue is something that is an artifact of emulating a 
constructor for a struct.  Take the standard approach for example:

struct Foo{
   int a,b,c;
}

Foo f = {a:1, b:2, c:3};
Foo f = {1,2,3}; // more succinct version

So here we create a struct in place, and break encapsulation in the 
process.  What we really want is an opaque type, that has a little more 
smarts on creation.  Taking advantage of in/body/out would be nice too. 
  No problem, we'll just use opCall():

struct Foo{
   int a,b,c;
   static Foo opCall(int a,int b,int c){
     Foo _this;
     _this.a = a;
     _this.b = b;
     _this.c = c;
     return _this;
   }
}

Foo f = Foo(1,2,3);

That's better, but look at what's really happening here.  Inlining and 
compiler optimization aside, the 'constructor' here creates a Foo on the 
stack which is then returned and *copied* to the destination 'f'.

To most, that won't ever seem like a problem. But for folks who are 
working with Vector types or Matrix implementations, that's something to 
scream about.  In a nutshell, any struct wider than a register that is 
populated in the 100's to 1000's is wasting cycles needlessly.

So that brings us to something like this:

struct Foo{
   int a,b,c;
   this(int a,int b,int c){
     this.a = a;
     this.b = b;
     this.c = c;
   }
}

Foo f = Foo(1,2,3);

Ambiguity aside, this fixes encapsulation, gives a familiar syntax, and 
almost fixes the allocation issues.  (see below)

> 
>> - Something that is disambiguated from static opCall
> <snip>
> 
> Do you mean that constructors for structs should have a notation
> distinct from S(...)?
> 

Well, I think it's one of the reasons why we don't have ctors for 
structs right now.  The preferred syntax for a "struct ctor" would 
probably be this:

S foo = S(a,b,c);

Which is indistinct from "static opCall".  Throwing 'new' in there 
wouldn't work either, since that would be a dynamic allocation:

S* foo = new S(a,b,c);

So that leaves us with "something else" that provides both a way to 
invoke a ctor, yet allocates the data on the stack and doesn't force you 
to create an additional copy:

S foo(a,b,c);  // c++ style
S foo = stackalloc S(a,b,c); // alloca() style (in place of new)
S foo = new(stack) S(a,b,c): // another idea

-- 
- EricAnderton at yahoo



More information about the Digitalmars-d-announce mailing list