www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Nicer syntax for constructors

reply Trailzz <email example.com> writes:
This situation happens *very* often in object oriented 
programming:
```
this(string a, int b, char c, float d, uint e, bool f)
{
     this.a = a;
     this.b = b;
     this.c = c;
     this.d = d;
     this.e = e;
     this.f = f;
}
```

It would save a lot of code bloat if there was a simpler syntax 
for this, perhaps something like this:
```
this(string this.a, int this.b, char this.c, float this.d, uint 
this.e, bool this.f)
{
}
```

It would be very easy to infer the types here, so this could also 
work
```
this(this.a, this.b, this.c, this.d, this.e, this.f)
{
}
```

I'm not sure exactly what the syntax would be like, but I just 
wanted to know what other people think about this. Would it be 
worth creating a DIP for this?
Nov 18 2018
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Sunday, 18 November 2018 at 19:09:16 UTC, Trailzz wrote:
 This situation happens *very* often in object oriented 
 programming:
 ```
 this(string a, int b, char c, float d, uint e, bool f)
 {
     this.a = a;
     this.b = b;
     this.c = c;
     this.d = d;
     this.e = e;
     this.f = f;
 }
 ```

 It would save a lot of code bloat if there was a simpler syntax 
 for this, perhaps something like this:
 ```
 this(string this.a, int this.b, char this.c, float this.d, uint 
 this.e, bool this.f)
 {
 }
 ```

 It would be very easy to infer the types here, so this could 
 also work
 ```
 this(this.a, this.b, this.c, this.d, this.e, this.f)
 {
 }
 ```

 I'm not sure exactly what the syntax would be like, but I just 
 wanted to know what other people think about this. Would it be 
 worth creating a DIP for this?
Have tried to use templates/string mixin for this? Don't rush to a DIP yet, until you exhaust other options.
Nov 18 2018
parent reply Trailzz <email example.com> writes:
On Sunday, 18 November 2018 at 19:25:09 UTC, 12345swordy wrote:
 Have tried to use templates/string mixin for this? Don't rush 
 to a DIP yet, until you exhaust other options.
how would you use templates/string mixin for this?
Nov 18 2018
parent reply Jacob Carlborg <doob me.com> writes:
On 2018-11-18 20:26, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:25:09 UTC, 12345swordy wrote:
 Have tried to use templates/string mixin for this? Don't rush to a DIP 
 yet, until you exhaust other options.
how would you use templates/string mixin for this?
Something like this: import std.traits : ParameterIdentifierTuple; class Foo { int a; int b; this(int a, int b) { static foreach (name ; ParameterIdentifierTuple!(__ctor)) __traits(getMember, this, name) = mixin(name); } } void main() { auto f = new Foo(2, 3); assert(f.a == 2); assert(f.b == 3); } -- /Jacob Carlborg
Nov 18 2018
parent reply Trailzz <email example.com> writes:
On Sunday, 18 November 2018 at 19:47:26 UTC, Jacob Carlborg wrote:
     this(int a, int b)
     {
         static foreach (name ; 
 ParameterIdentifierTuple!(__ctor))
             __traits(getMember, this, name) = mixin(name);
     }
 }
This is still very clunky and hard to understand.
Nov 18 2018
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 18.11.18 20:52, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:47:26 UTC, Jacob Carlborg wrote:
     this(int a, int b)
     {
         static foreach (name ; ParameterIdentifierTuple!(__ctor))
             __traits(getMember, this, name) = mixin(name);
     }
 }
This is still very clunky and hard to understand.
--- module util; enum assignFields=q{{ import std.traits; static foreach(x;ParameterIdentifierTuple!(__traits(parent,{}))) static if(__traits(hasMember, this, x)) __traits(getMember,this,x)=mixin(x); }}; --- --- module app; import util; class C{ string a; int b; char c; float d; uint e; bool f; this(string a, int b, char c, float d, uint e, bool f){ mixin(assignFields); } } void main(){ import std.stdio; writeln((new C("1",2,'3',4.0,5,true).tupleof)); } ---
Nov 18 2018
next sibling parent reply Trailzz <email example.com> writes:
On Sunday, 18 November 2018 at 19:59:27 UTC, Timon Gehr wrote:
 On 18.11.18 20:52, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:47:26 UTC, Jacob Carlborg 
 wrote:
 [...]
This is still very clunky and hard to understand.
--- module util; enum assignFields=q{{ import std.traits; static foreach(x;ParameterIdentifierTuple!(__traits(parent,{}))) static if(__traits(hasMember, this, x)) __traits(getMember,this,x)=mixin(x); }}; --- --- module app; import util; class C{ string a; int b; char c; float d; uint e; bool f; this(string a, int b, char c, float d, uint e, bool f){ mixin(assignFields); } } void main(){ import std.stdio; writeln((new C("1",2,'3',4.0,5,true).tupleof)); } ---
This is arguably more clunky than just lots of `this.foo = foo`.
Nov 18 2018
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 18.11.18 21:06, Trailzz wrote:
 ...
 
 This is arguably more clunky than just lots of `this.foo = foo`.
? Define clunky.
Nov 18 2018
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 11/18/18 3:06 PM, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:59:27 UTC, Timon Gehr wrote:
 On 18.11.18 20:52, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:47:26 UTC, Jacob Carlborg wrote:
 [...]
This is still very clunky and hard to understand.
--- module util; enum assignFields=q{{     import std.traits;     static foreach(x;ParameterIdentifierTuple!(__traits(parent,{})))         static if(__traits(hasMember, this, x))             __traits(getMember,this,x)=mixin(x); }}; --- --- module app; import util; class C{     string a;     int b;     char c;     float d;     uint e;     bool f;     this(string a, int b, char c, float d, uint e, bool f){         mixin(assignFields);     } } void main(){     import std.stdio;     writeln((new C("1",2,'3',4.0,5,true).tupleof)); } ---
This is arguably more clunky than just lots of `this.foo = foo`.
Maybe you didn't notice that util module is written *once*, and then imported where used. All you would have to do is the one `mixin(assignFields)` line in the places you wanted this boiler plate. To me, this is an elegant, simple solution, and IMO, actually nicer than any proposed language syntax changes (I find having to put `this` in front of all the parameter names just as clunky as doing the assignments). -Steve
Nov 19 2018
prev sibling parent dayllenger <dayllenger protonmail.com> writes:
On Sunday, 18 November 2018 at 19:59:27 UTC, Timon Gehr wrote:
 class C{
     string a;
     int b;
     char c;
     float d;
     uint e;
     bool f;
     this(string a, int b, char c, float d, uint e, bool f){
         mixin(assignFields);
     }
 }
It is not good when there is one parameter, you probably will write usual assignment for readability. In most of cases - 1 or 2 parameters - this solution improves nothing. On the other hand, members with _ or m_ in the name will force parameters to have the same names in the OP syntax.
Nov 18 2018
prev sibling parent aberba <karabutaworld gmail.com> writes:
On Sunday, 18 November 2018 at 19:52:48 UTC, Trailzz wrote:
 On Sunday, 18 November 2018 at 19:47:26 UTC, Jacob Carlborg 
 wrote:
     this(int a, int b)
     {
         static foreach (name ; 
 ParameterIdentifierTuple!(__ctor))
             __traits(getMember, this, name) = mixin(name);
     }
 }
This is still very clunky and hard to understand.
I'm not sure if you get it but to understand some D code, there's some amount of language features you need to know about first like mixins, stuff in std.traits and what they do... and CTFE...a few others too. Otherwise, D code might look very weird to you. But once you get it, you'll smile to D code for its modelling power. The combination of these features can be mentally tasking if you don't understand each of them. I'll recommend the "Programming in D" book if you haven't read it already (http://ddili.org/ders/d.en/index.html). "I can do anything! with D."
Nov 20 2018
prev sibling next sibling parent Neia Neutuladh <neia ikeran.org> writes:
On Sun, 18 Nov 2018 19:09:16 +0000, Trailzz wrote:
 It would be very easy to infer the types here, so this could also work
 ```
 this(this.a, this.b, this.c, this.d, this.e, this.f)
 ```
Dart does this, for reference. Some random code I happened to have lying around: class Stat { StatType type; ShipToValue shipToValue; Stat(this.type, this.shipToValue); } So does CoffeeScript: class Animal constructor: ( name) -> C++ has initializer lists, which are clunkier, and I think they avoid invoking a copy constructor or something.
Nov 18 2018
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
class A {
   int a;
   string b;
   float c;

   this(typeof(this.tupleof) args) {
     this.tupleof = args;
   }
}


auto a = new A(4, "foo", 1.5);


Of course, that assumes none of the internal types are const, 
that complicates things, and it assumes you want to set them all 
at once. It also doesn't work quite right with inheritance, but 
you can make that work by combining the base class tuple if you 
want.

Keep in mind you can also slice tuples if you want a subset of 
the members.
Nov 18 2018
parent reply bauss <jj_1337 live.dk> writes:
On Sunday, 18 November 2018 at 20:20:50 UTC, Adam D. Ruppe wrote:
 class A {
   int a;
   string b;
   float c;

   this(typeof(this.tupleof) args) {
     this.tupleof = args;
   }
 }


 auto a = new A(4, "foo", 1.5);


 Of course, that assumes none of the internal types are const, 
 that complicates things, and it assumes you want to set them 
 all at once. It also doesn't work quite right with inheritance, 
 but you can make that work by combining the base class tuple if 
 you want.

 Keep in mind you can also slice tuples if you want a subset of 
 the members.
The problem with your solution is if you just want a and b assigned.
Nov 19 2018
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 19 November 2018 at 16:15:38 UTC, bauss wrote:
 The problem with your solution is if you just want a and b 
 assigned.
That's why I said you can slice tuples. Of course, slice needs them to be contiguous but still. Though tbh I think this whole thing is folly - for pod, use struct and things just work. If your class has a group of pod stuff... use a struct!
Nov 19 2018
prev sibling next sibling parent FeepingCreature <feepingcreature gmail.de> writes:
On Sunday, 18 November 2018 at 19:09:16 UTC, Trailzz wrote:
 This situation happens *very* often in object oriented 
 programming:
 ```
 this(string a, int b, char c, float d, uint e, bool f)
 {
     this.a = a;
     this.b = b;
     this.c = c;
     this.d = d;
     this.e = e;
     this.f = f;
 }
 ```

 It would save a lot of code bloat if there was a simpler syntax 
 for this, perhaps something like this:
 ```
 this(string this.a, int this.b, char this.c, float this.d, uint 
 this.e, bool this.f)
 {
 }
 ```

 It would be very easy to infer the types here, so this could 
 also work
 ```
 this(this.a, this.b, this.c, this.d, this.e, this.f)
 {
 }
 ```

 I'm not sure exactly what the syntax would be like, but I just 
 wanted to know what other people think about this. Would it be 
 worth creating a DIP for this?
You can use my boilerplate library https://code.dlang.org/packages/boilerplate to automatically generate constructors for pod classes. Just mixin(GenerateThis);
Nov 18 2018
prev sibling next sibling parent reply NoMoreBugs <NoMoreBugs gmail.com> writes:
On Sunday, 18 November 2018 at 19:09:16 UTC, Trailzz wrote:
 I'm not sure exactly what the syntax would be like, but I just 
 wanted to know what other people think about this. Would it be 
 worth creating a DIP for this?
Well, let's step back a bit, from the so called 'code bloat', and have a look at the definition of a function: return-type function-name(parameter declarations, if any) { declarations statements } What you are suggesting, is, in order to save a few keystrokes, that D changes the definition of a function (or a constructor function in this case). No language that has functions allows you do initialize variables in the section where you declare your parameters - at least, no language that I am aware of. Lets not surprise newcomers to D, anymore than they are already going to be surprised. Its bad enough you can't have a private member within a module! Initializing variables in the parameter section of the function would be a step too far.
Nov 19 2018
parent reply Erik van Velzen <erik evanv.nl> writes:
On Monday, 19 November 2018 at 12:30:20 UTC, NoMoreBugs wrote:
 On Sunday, 18 November 2018 at 19:09:16 UTC, Trailzz wrote:
 I'm not sure exactly what the syntax would be like, but I just 
 wanted to know what other people think about this. Would it be 
 worth creating a DIP for this?
Well, let's step back a bit, from the so called 'code bloat', and have a look at the definition of a function: return-type function-name(parameter declarations, if any) { declarations statements } What you are suggesting, is, in order to save a few keystrokes, that D changes the definition of a function (or a constructor function in this case). No language that has functions allows you do initialize variables in the section where you declare your parameters - at least, no language that I am aware of.
TypeScript: class MyClass { constructor( readonly myValue: number, myArgument: number, ) {} } also Kotlin: class MyClass( val myValue: Int, myArgument: String ) {}
 Lets not surprise newcomers to D, anymore than they are already 
 going to be surprised.

 Its bad enough you can't have a private member within a module!

 Initializing variables in the parameter section of the function 
 would be a step too far.
Nov 19 2018
parent NoMoreBugs <NoMoreBugs gmail.com> writes:
On Monday, 19 November 2018 at 21:36:32 UTC, Erik van Velzen 
wrote:
 TypeScript:

 class MyClass {
     constructor(
         readonly myValue: number,
         myArgument: number,
     ) {}
 }

 also Kotlin:

 class MyClass(
     val myValue: Int,
     myArgument: String
 ) {}
Well, I do not 'know' either of Typescript or Kotlin - so my statement stands correct ;-) Of course, my argument is more about consistency, and less about how a particular language implements a constructor. Consistency makes code easier to write, easier to understand, and easier to maintain. Sadly, D, like many languages, lets you do the same things in any number of ways - which just places more burden on programmers. Go-lang has kinda addressed this issue.. It's also about modularity/encapsulation I guess. The function definition is really a definition of its parts, what those parts do, and how they work together to form the desired 'functionality'. Lets keep 'the parts' - please. ----- return-type function-name(parameter declarations, if any) { declarations statements } ----
Nov 19 2018
prev sibling parent reply JN <666total wp.pl> writes:
On Sunday, 18 November 2018 at 19:09:16 UTC, Trailzz wrote:
 I'm not sure exactly what the syntax would be like, but I just 
 wanted to know what other people think about this. Would it be 
 worth creating a DIP for this?
Personally I am a huge fan of this feature. Dart has it and I've used it a lot.
Nov 24 2018
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Saturday, 24 November 2018 at 13:11:39 UTC, JN wrote:
 Personally I am a huge fan of this feature. Dart has it and 
 I've used it a lot.
TypeScript has it as well.
Dec 03 2018