www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Auto constructor [Was: Archetype language]

reply bearophile <bearophileHUGS lycos.com> writes:
Among the things I've listed about Archetype there's one interesting thing.
Class instances aren't PODs, but sometimes I prefer reference semantics and to
populate fields in a plain way, expecially for simple classes.

Time ago I and other people have suggested a syntax like (this also to avoid a
class of bugs http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


class Foo {
  string x;
  int y = 1;
  this(this.x, this.y) {}
}
void main() {
  Foo f3 = new Foo("hello", 10);
}


A simpler solution are classes with automatic constructors:

class Foo {
  string x;
  int y = 1;
}
void main() {
  Foo f1 = new Foo(); // Good
  Foo f2 = new Foo("hello"); // Good
  Foo f3 = new Foo("hello", 10); // Good
}


What kind of problems are caused by this? :-)


Currently that syntax is supported for structs created as values, but not for
structs created by pointer:

struct Foo {
  string x;
  int y = 1;
}
void main() {
  Foo* f1 = new Foo(); // OK
  Foo* f2 = new Foo("hello"); // Error: no constructor for Foo
  Foo* f3 = new Foo("hello", 10); // Error: no constructor for Foo
}

Bye,
bearophile
Mar 20 2011
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Have you tried doing this with a string mixin? It looks like
it'd be trivial.
Mar 20 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Have you tried doing this with a string mixin? It looks like
 it'd be trivial.

It's probably trivial with a string mixin, but no thanks. I don't like them a lot. Bye, bearophile
Mar 20 2011
prev sibling next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Am 21.03.2011 00:55, schrieb bearophile:
 Among the things I've listed about Archetype there's one interesting thing.
Class instances aren't PODs, but sometimes I prefer reference semantics and to
populate fields in a plain way, expecially for simple classes.

 Time ago I and other people have suggested a syntax like (this also to avoid a
class of bugs http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
    string x;
    int y = 1;
    this(this.x, this.y) {}
 }
 void main() {
    Foo f3 = new Foo("hello", 10);
 }

Yeah, I still like that idea ;)
 A simpler solution are classes with automatic constructors:

 class Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo f1 = new Foo(); // Good
    Foo f2 = new Foo("hello"); // Good
    Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)

You'd have to know the order in that the members are defined in the class (and you may not change the order). Just imagine class Foo { int bla; int baz; } new Foo(42, 3); // what is bla, what is baz? and then you decide "uh I'd prefer to have my class members ordered alphabetically" and *bamm* all you code silently breaks. having a this(this.bla, this.baz) {} would clearly document which argument in the constructor belongs to which class member and the class members ordering wouldn't matter. Cheers, - Daniel
Mar 20 2011
parent reply Don <nospam nospam.com> writes:
Daniel Gibson wrote:
 Am 21.03.2011 00:55, schrieb bearophile:
 Among the things I've listed about Archetype there's one interesting 
 thing. Class instances aren't PODs, but sometimes I prefer reference 
 semantics and to populate fields in a plain way, expecially for simple 
 classes.

 Time ago I and other people have suggested a syntax like (this also to 
 avoid a class of bugs 
 http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
    string x;
    int y = 1;
    this(this.x, this.y) {}
 }
 void main() {
    Foo f3 = new Foo("hello", 10);
 }

Yeah, I still like that idea ;)
 A simpler solution are classes with automatic constructors:

 class Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo f1 = new Foo(); // Good
    Foo f2 = new Foo("hello"); // Good
    Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)

You'd have to know the order in that the members are defined in the class (and you may not change the order). Just imagine class Foo { int bla; int baz; } new Foo(42, 3); // what is bla, what is baz? and then you decide "uh I'd prefer to have my class members ordered alphabetically" and *bamm* all you code silently breaks. having a this(this.bla, this.baz) {} would clearly document which argument in the constructor belongs to which class member and the class members ordering wouldn't matter. Cheers, - Daniel

I agree. But unfortunately, the idea is a relatively complicated feature with a lot of special cases. For example, this(this.bla, this.bla){} and what if the class contains a union and you set multiple members of it? The whole thing is actually quite messy. It's not _terrible_, but it's far from trivial, and it's more complicated than some far more powerful and useful language features.
Mar 21 2011
next sibling parent Daniel Gibson <metalcaedes gmail.com> writes:
Am 21.03.2011 09:17, schrieb Don:
 Daniel Gibson wrote:
 Am 21.03.2011 00:55, schrieb bearophile:
 Among the things I've listed about Archetype there's one interesting thing.
 Class instances aren't PODs, but sometimes I prefer reference semantics and
 to populate fields in a plain way, expecially for simple classes.

 Time ago I and other people have suggested a syntax like (this also to avoid
 a class of bugs http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
    string x;
    int y = 1;
    this(this.x, this.y) {}
 }
 void main() {
    Foo f3 = new Foo("hello", 10);
 }

Yeah, I still like that idea ;)
 A simpler solution are classes with automatic constructors:

 class Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo f1 = new Foo(); // Good
    Foo f2 = new Foo("hello"); // Good
    Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)

You'd have to know the order in that the members are defined in the class (and you may not change the order). Just imagine class Foo { int bla; int baz; } new Foo(42, 3); // what is bla, what is baz? and then you decide "uh I'd prefer to have my class members ordered alphabetically" and *bamm* all you code silently breaks. having a this(this.bla, this.baz) {} would clearly document which argument in the constructor belongs to which class member and the class members ordering wouldn't matter. Cheers, - Daniel

I agree. But unfortunately, the idea is a relatively complicated feature with a lot of special cases. For example, this(this.bla, this.bla){} and what if the class contains a union and you set multiple members of it? The whole thing is actually quite messy. It's not _terrible_, but it's far from trivial, and it's more complicated than some far more powerful and useful language features.

Isn't it guaranteed that function arguments (and I guess it's the same for constructors) are evaluated from left to right [1]? So if somebody is stupid enough to supply multiple arguments for a union the rightmost argument "wins" (he'd have the same problem with conventional constructors, only that the last assignment in the body would win). The same could be applied for this(this.bla, this.bla){} - the righ this.bla wins. But in this case a check that enforces that each class member may only occur *once* doesn't sound that hard to me - but I don't know anything about DMDs internals ;) Also I don't know if there are other special cases. Cheers, - Daniel [1] hmm I can't find anything about that right now, but I seem to remember it has been mentioned. Also it seems to be true in simple tests like: import std.stdio; int tf(int x) { writefln("testfun was called with %s", x); return x; } void myfun(int a, int b, int c) { writefln("a: %s b: %s c: %s", a, b, c); } void main() { myfun(tf(1), tf(3), tf(2)); }
Mar 21 2011
prev sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Mar 21, 11 16:17, Don wrote:
 Daniel Gibson wrote:
 Am 21.03.2011 00:55, schrieb bearophile:
 Among the things I've listed about Archetype there's one interesting
 thing. Class instances aren't PODs, but sometimes I prefer reference
 semantics and to populate fields in a plain way, expecially for
 simple classes.

 Time ago I and other people have suggested a syntax like (this also
 to avoid a class of bugs
 http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
 string x;
 int y = 1;
 this(this.x, this.y) {}
 }
 void main() {
 Foo f3 = new Foo("hello", 10);
 }

Yeah, I still like that idea ;)
 A simpler solution are classes with automatic constructors:

 class Foo {
 string x;
 int y = 1;
 }
 void main() {
 Foo f1 = new Foo(); // Good
 Foo f2 = new Foo("hello"); // Good
 Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)

You'd have to know the order in that the members are defined in the class (and you may not change the order). Just imagine class Foo { int bla; int baz; } new Foo(42, 3); // what is bla, what is baz? and then you decide "uh I'd prefer to have my class members ordered alphabetically" and *bamm* all you code silently breaks. having a this(this.bla, this.baz) {} would clearly document which argument in the constructor belongs to which class member and the class members ordering wouldn't matter. Cheers, - Daniel

I agree. But unfortunately, the idea is a relatively complicated feature with a lot of special cases. For example, this(this.bla, this.bla){}

'int f(int x, int x) {}' is a syntax error. So should 'this(this.x, this.x){}'.
 and what if the class contains a union and you set multiple members of it?
 The whole thing is actually quite messy. It's not _terrible_, but it's
 far from trivial, and it's more complicated than some far more powerful
 and useful language features.

The syntax this(args, this.x.y.z, args, this.p.q.r = s, arg = t) { statements; } could just lower to this(args, typeof(this.x.y.z) z, args, typeof(this.p.q.r) r = s, arg = t) { this.x.y.z = z; this.p.q.r = r; statements; } Would this be too complicated? (Not that I like this idea... But I think it is not really that messy)
Mar 21 2011
parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Am 21.03.2011 11:09, schrieb KennyTM~:
 On Mar 21, 11 16:17, Don wrote:
 I agree. But unfortunately, the idea is a relatively complicated feature
 with a lot of special cases. For example, this(this.bla, this.bla){}

'int f(int x, int x) {}' is a syntax error. So should 'this(this.x, this.x){}'.

and probably this(this.x, x){}
Mar 21 2011
next sibling parent reply Don <nospam nospam.com> writes:
Daniel Gibson wrote:
 Am 21.03.2011 11:09, schrieb KennyTM~:
 On Mar 21, 11 16:17, Don wrote:
 I agree. But unfortunately, the idea is a relatively complicated feature
 with a lot of special cases. For example, this(this.bla, this.bla){}


and probably this(this.x, x){}

Exactly. That's why it's messier than it first appears. My point is -- people tend to think things like this are trivial features because they are not very powerful; and conversely, they think that powerful features must be complicated. But that's really misleading. 'pure', for example, is roughly the same level of implementation complexity as this feature.
Mar 21 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Don:

 'pure', for example, is roughly the same level of 
 implementation complexity as this feature.

If this is true, then this is amazing :-) Considering that pure is probably about 60-70% implemented in D (no way to perform conditional purity, no good management of special cases, your last patch for lazy arguments, etc). Bye, bearophile
Mar 21 2011
prev sibling parent KennyTM~ <kennytm gmail.com> writes:
On Mar 21, 11 18:26, Daniel Gibson wrote:
 Am 21.03.2011 11:09, schrieb KennyTM~:
 On Mar 21, 11 16:17, Don wrote:
 I agree. But unfortunately, the idea is a relatively complicated feature
 with a lot of special cases. For example, this(this.bla, this.bla){}

'int f(int x, int x) {}' is a syntax error. So should 'this(this.x, this.x){}'.

and probably this(this.x, x){}

Yes. This is handled by the AST transform (lowering) too. this(this.x, int x) { statements; } becomes this(typeof(this.x) x, int x) { this.x = x; statements; } which will complain Error: constructor x.Foo.this parameter this.x is already defined as expected.
Mar 21 2011
prev sibling parent reply spir <denis.spir gmail.com> writes:
On 03/21/2011 12:55 AM, bearophile wrote:
 Among the things I've listed about Archetype there's one interesting thing.
Class instances aren't PODs, but sometimes I prefer reference semantics and to
populate fields in a plain way, expecially for simple classes.

 Time ago I and other people have suggested a syntax like (this also to avoid a
class of bugs http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
    string x;
    int y = 1;
    this(this.x, this.y) {}
 }
 void main() {
    Foo f3 = new Foo("hello", 10);
 }


 A simpler solution are classes with automatic constructors:

 class Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo f1 = new Foo(); // Good
    Foo f2 = new Foo("hello"); // Good
    Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)


 Currently that syntax is supported for structs created as values, but not for
structs created by pointer:

 struct Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo* f1 = new Foo(); // OK
    Foo* f2 = new Foo("hello"); // Error: no constructor for Foo
    Foo* f3 = new Foo("hello", 10); // Error: no constructor for Foo
 }

I definitely want some feature like that in D. Have no idea why a default seems complicated for classes while structs have it. On the other hand, the syntax using "this.p" constructor parameter names is more general since it allows custom constructors: class Point { float x,y; float dist; this(this.x, this.y) { this.dist = square(x*x + y*y); } } Ideally, I would like this feature without "this." parameters, but it requires named arguments...: auto p = new Point(x=1, y=2); --> auto assign to members by name, then perform additional constructor tasks. Denis -- _________________ vita es estrany spir.wikidot.com
Mar 21 2011
parent Don <nospam nospam.com> writes:
spir wrote:
 On 03/21/2011 12:55 AM, bearophile wrote:
 Among the things I've listed about Archetype there's one interesting 
 thing. Class instances aren't PODs, but sometimes I prefer reference 
 semantics and to populate fields in a plain way, expecially for simple 
 classes.

 Time ago I and other people have suggested a syntax like (this also to 
 avoid a class of bugs 
 http://d.puremagic.com/issues/show_bug.cgi?id=3878 ):


 class Foo {
    string x;
    int y = 1;
    this(this.x, this.y) {}
 }
 void main() {
    Foo f3 = new Foo("hello", 10);
 }


 A simpler solution are classes with automatic constructors:

 class Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo f1 = new Foo(); // Good
    Foo f2 = new Foo("hello"); // Good
    Foo f3 = new Foo("hello", 10); // Good
 }


 What kind of problems are caused by this? :-)


 Currently that syntax is supported for structs created as values, but 
 not for structs created by pointer:

 struct Foo {
    string x;
    int y = 1;
 }
 void main() {
    Foo* f1 = new Foo(); // OK
    Foo* f2 = new Foo("hello"); // Error: no constructor for Foo
    Foo* f3 = new Foo("hello", 10); // Error: no constructor for Foo
 }

I definitely want some feature like that in D. Have no idea why a default seems complicated for classes while structs have it.

It's not that it's complicated, it's that for structs, the ordering of their members is part of the public interface. For classes, the members are not public.
Mar 21 2011