www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Feature request - simpler constructors

reply "Janice Caron" <caron800 googlemail.com> writes:
Please could we let

 this(auto n) {}
 T n;

be syntactic sugar for

 this(T n)
 {
     this.n = n;
 }
 T n;

I've lost count of the number of times I've written constructors which
do nothing but copy function parameters into member variables. If you
have a lot of variables, it gets very tedious, especially when you
have to do it over and over again. I tend to give my constructor
paramters different names to avoid typing "this." all the time, but I
still end up with, for example:

 class MyDate
 {
     this(int year_, int month_, int day_, int hour_, int minute_, int second_)
     {
         year = year_;
         month = month_;
         day = day_;
         hour = hour_;
         minute = minute_;
         second = second_;
     }

     int year;
     int month;
     int day;
     int hour;
     int minute;
     int second;
 }

Just think how much nicer it would be if instead I could just type

 class MyDate
 {
     this(auto year, auto month, auto day, auto hour, auto minute, auto second)
     {
     }

     int year;
     int month;
     int day;
     int hour;
     int minute;
     int second;
 }

That would be /so cool/. "auto" can have no other possible meaning in
this context. Plus, it would make writing constructors just a little
bit safer, because if the constructor calls some other function which
relies on the variable having been initialised, it will have been, and
if the constructor calls some non-member function, we'll be able to
call it as f(year) instead of f(year_) with no fear of year being
uninitialised.
Sep 20 2007
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Janice Caron wrote:
 Please could we let
 
  this(auto n) {}
  T n;
 
 be syntactic sugar for
 
  this(T n)
  {
      this.n = n;
  }
  T n;
 
 I've lost count of the number of times I've written constructors which
 do nothing but copy function parameters into member variables. If you
 have a lot of variables, it gets very tedious, especially when you
 have to do it over and over again. I tend to give my constructor
 paramters different names to avoid typing "this." all the time, but I
 still end up with, for example:
 

 
 That would be /so cool/. "auto" can have no other possible meaning in
 this context.

So true. vote++
Sep 20 2007
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
 Please could we let

 this(auto n) {}
 T n;

 be syntactic sugar for

 this(T n)
 {
     this.n = n;
 }
 T n;

Good idea. vote = vote + 1; // just realized, vote could be a property :) -Steve
Sep 20 2007
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.277.1190282755.16939.digitalmars-d puremagic.com...
 Please could we let

 this(auto n) {}
 T n;

 be syntactic sugar for

 this(T n)
 {
     this.n = n;
 }
 T n;

I liek!
Sep 20 2007
prev sibling next sibling parent reply Matti Niemenmaa <see_signature for.real.address> writes:
Janice Caron wrote:
 Please could we let
 
  this(auto n) {}
  T n;
 
 be syntactic sugar for
 
  this(T n)
  {
      this.n = n;
  }
  T n;

Has nobody thought of this before? It's so obvious, and such a good idea. votes = votes.max; -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 20 2007
next sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Matti Niemenmaa wrote:
 Janice Caron wrote:
 Please could we let

  this(auto n) {}
  T n;

 be syntactic sugar for

  this(T n)
  {
      this.n = n;
  }
  T n;


 votes = votes.max;

votes++; // Oh noez! -- Oskar
Sep 20 2007
prev sibling parent Jeff Nowakowski <jeff dilacero.org> writes:
Matti Niemenmaa wrote:
 
 Has nobody thought of this before? It's so obvious, and such a good idea.

http://en.wikipedia.org/wiki/Algebraic_data_type
Sep 20 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 Please could we let
 
  this(auto n) {}
  T n;
 
 be syntactic sugar for
 
  this(T n)
  {
      this.n = n;
  }
  T n;
 
 I've lost count of the number of times I've written constructors which
 do nothing but copy function parameters into member variables. If you
 have a lot of variables, it gets very tedious, especially when you
 have to do it over and over again. I tend to give my constructor
 paramters different names to avoid typing "this." all the time, but I
 still end up with, for example:
 
  class MyDate
  {
      this(int year_, int month_, int day_, int hour_, int minute_, int second_)
      {
          year = year_;
          month = month_;
          day = day_;
          hour = hour_;
          minute = minute_;
          second = second_;
      }
 
      int year;
      int month;
      int day;
      int hour;
      int minute;
      int second;
  }
 
 Just think how much nicer it would be if instead I could just type
 
  class MyDate
  {
      this(auto year, auto month, auto day, auto hour, auto minute, auto second)
      {
      }
 
      int year;
      int month;
      int day;
      int hour;
      int minute;
      int second;
  }
 
 That would be /so cool/. "auto" can have no other possible meaning in
 this context. Plus, it would make writing constructors just a little
 bit safer, because if the constructor calls some other function which
 relies on the variable having been initialised, it will have been, and
 if the constructor calls some non-member function, we'll be able to
 call it as f(year) instead of f(year_) with no fear of year being
 uninitialised.

I like the idea but I'm not wild about the syntax you've chosen. I'd like to be able to read off the types of the parameters from the function signature without having to dig around in the class for where the memebers are defined. What about something like prefixing the name with a dot? this(int .year, int .month, int .day, int .hour, int .minute, int .second) The thing I've always wished were possible with parameter lists was to omit types that are repeated like in other variable declarations. So you could have: foo(int year, month, day, hour, minute, second) { ... } It might be less error-prone to combine this with ; to terminate a list (also like in normal declarations): foo(int year, month, day, hour, minute, second; float fraction) { ... } ANSI C parameter declarations were in some was a step back from K&R where you could do: foo(year, month, day, hour, minute, second, fraction) int year,month,day,hour,minute; float fraction; { ... } Er .. nevermind. On second thought, K&R sucked. --bb
Sep 20 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Bill Baxter" wrote
 I like the idea but I'm not wild about the syntax you've chosen.  I'd like 
 to be able to read off the types of the parameters from the function 
 signature without having to dig around in the class for where the memebers 
 are defined.  What about something like prefixing the name with a dot?


    this(int .year, int .month, int .day, int .hour, int .minute, int 
 .second)

Personally, I like Janice's idea better. It should be up to the IDE to tell you what the types are for the constructor. Imagine a situation like this: class X { int y; this(int .y) {} } Now the author decides y should be a long: class X { long y; this(int .y) {} } Oops, forgot to update the constructor. But the compiler won't complain because this.y = y is valid. With Janice's syntax, this doesn't happen. -Steve
Sep 20 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Steven Schveighoffer wrote:
 "Bill Baxter" wrote
 I like the idea but I'm not wild about the syntax you've chosen.  I'd like 
 to be able to read off the types of the parameters from the function 
 signature without having to dig around in the class for where the memebers 
 are defined.  What about something like prefixing the name with a dot?


    this(int .year, int .month, int .day, int .hour, int .minute, int 
 .second)

Personally, I like Janice's idea better. It should be up to the IDE to tell you what the types are for the constructor. Imagine a situation like this: class X { int y; this(int .y) {} } Now the author decides y should be a long: class X { long y; this(int .y) {} } Oops, forgot to update the constructor. But the compiler won't complain because this.y = y is valid. With Janice's syntax, this doesn't happen. -Steve

I guess the main worry lurking in the back of my mind is that we may actually want to use auto in parameter lists someday to mean more or less what it means in declarations: void foo(auto y = "hi there", auto x = 23.f, const z = ABigNamedStruct()) {. . . } And having it mean something slightly different for 'this' methods than for an ordinary 'foo' method would just be confusing. --bb
Sep 20 2007
next sibling parent Matti Niemenmaa <see_signature for.real.address> writes:
Bill Baxter wrote:
 I guess the main worry lurking in the back of my mind is that we may
 actually want to use auto in parameter lists someday to mean more or
 less what it means in declarations:
 
     void foo(auto y = "hi there",
              auto x = 23.f,
              const z = ABigNamedStruct())
     {. . . }
 
 And having it mean something slightly different for 'this' methods than
 for an ordinary 'foo' method would just be confusing.

The precise syntax isn't that important. It could just as well be either of the following, for instance (using 'a' and 'b' as parameters which you don't want to be automatically handled): this(a, auto [x, y, z], b) {} this(a, auto: (x, y, z), b) {} -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 20 2007
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
Bill Baxter escribió:
 Steven Schveighoffer wrote:
 "Bill Baxter" wrote
 I like the idea but I'm not wild about the syntax you've chosen.  I'd 
 like to be able to read off the types of the parameters from the 
 function signature without having to dig around in the class for 
 where the memebers are defined.  What about something like prefixing 
 the name with a dot?


    this(int .year, int .month, int .day, int .hour, int .minute, int 
 .second)

Personally, I like Janice's idea better. It should be up to the IDE to tell you what the types are for the constructor. Imagine a situation like this: class X { int y; this(int .y) {} } Now the author decides y should be a long: class X { long y; this(int .y) {} } Oops, forgot to update the constructor. But the compiler won't complain because this.y = y is valid. With Janice's syntax, this doesn't happen. -Steve

I guess the main worry lurking in the back of my mind is that we may actually want to use auto in parameter lists someday

Well, it could be the keyword "this", and it also has a closer meaning to what's actually done. class Point { int x; int y; this(this x, this y) { } }
Sep 20 2007
next sibling parent Matti Niemenmaa <see_signature for.real.address> writes:
Ary Manzana:

Your system clock appears to be skewed by one hour.

-- 
E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 20 2007
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Ary Manzana wrote:
 Bill Baxter escribió:
 Steven Schveighoffer wrote:
 "Bill Baxter" wrote
 I like the idea but I'm not wild about the syntax you've chosen.  
 I'd like to be able to read off the types of the parameters from the 
 function signature without having to dig around in the class for 
 where the memebers are defined.  What about something like prefixing 
 the name with a dot?


    this(int .year, int .month, int .day, int .hour, int .minute, int 
 .second)

Personally, I like Janice's idea better. It should be up to the IDE to tell you what the types are for the constructor. Imagine a situation like this: class X { int y; this(int .y) {} } Now the author decides y should be a long: class X { long y; this(int .y) {} } Oops, forgot to update the constructor. But the compiler won't complain because this.y = y is valid. With Janice's syntax, this doesn't happen. -Steve

I guess the main worry lurking in the back of my mind is that we may actually want to use auto in parameter lists someday

Well, it could be the keyword "this", and it also has a closer meaning to what's actually done. class Point { int x; int y; this(this x, this y) { } }

Ooh. I do like that a lot better. --bb
Sep 20 2007
prev sibling next sibling parent reply kris <foo bar.com> writes:
Bill Baxter wrote:
 
 I guess the main worry lurking in the back of my mind is that we may 
 actually want to use auto in parameter lists someday to mean more or 
 less what it means in declarations:
 
     void foo(auto y = "hi there",
              auto x = 23.f,
              const z = ABigNamedStruct())
     {. . . }
 
 And having it mean something slightly different for 'this' methods than 
 for an ordinary 'foo' method would just be confusing.
 
 --bb

I agree, and there more. The example given suggested # this(auto year, auto month, auto day, auto hour, auto minute, auto second) in such a case, one is invariably also going to provide something like: # set (int year, int month, int day, int hour, int minute, int second) or a combination of: # date (int year, int month, int day) # time (int hour, int minute, int second) Hence, the ctor should actually be: # this (int year, int month, int day, int hour, int minute, int second) # { # date (year, month, day); # time (hour, minute, second); # } Having the compiler "fill in the gaps" here is just sloppy IMO. Do it right the first time. Further, it's common practice (in D) to name local vars somewhat different than the parameter names, so that DDoc has something nicer to show (recall that ppl often use prefix/postfix decoration on member vars, to avoid name conflict with internal functions). This 'auto' notion would simply increase the level of brittleness involved. There's other reasons too, but all in all I suspect this notion is borne from pure laziness rather than from an engineering perspective?
Sep 20 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"kris" wrote
 I agree, and there more. The example given suggested

 # this(auto year, auto month, auto day, auto hour, auto minute, auto 
 second)

 in such a case, one is invariably also going to provide something like:

 # set (int year, int month, int day, int hour, int minute, int second)

 or a combination of:

 # date (int year, int month, int day)
 # time (int hour, int minute, int second)

 Hence, the ctor should actually be:

 # this (int year, int month, int day, int hour, int minute, int second)
 # {
 #    date (year, month, day);
 #    time (hour, minute, second);
 # }

 Having the compiler "fill in the gaps" here is just sloppy IMO. Do it 
 right the first time.

This is not always the case. A class with immutable members comes to mind, such as an immutable string class. I don't see this as any different than the C++ syntax: Class(int x, int y) : x(x), y(y) { } But it's less typing :)
 Further, it's common practice (in D) to name local vars somewhat different 
 than the parameter names, so that DDoc has something nicer to show (recall 
 that ppl often use prefix/postfix decoration on member vars, to avoid name 
 conflict with internal functions). This 'auto' notion would simply 
 increase the level of brittleness involved. There's other reasons too, but 
 all in all I suspect this notion is borne from pure laziness rather than 
 from an engineering perspective?

I can see what you are saying, but there is always the old way of doing it :) Nobody says you have to do it this way. What I find common is creating a class that has public members, but instead of doing this: class X { int m1, m2, m3; } X x = new X; x.m1 = 1; x.m2 = 2; x.m3 = 3; I create a constructor to do that for me so I get: X x = new X(1,2,3). Invariably the constructor ends up looking like: this(int m1, int m2, int m3) { this.m1 = m1; this.m2 = m2; this.m3 = m3; } Of course, this is a simplistic example, but it does occur quite often for me. -Steve
Sep 20 2007
prev sibling parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak+news utu.fi.invalid> writes:
Bill Baxter wrote:

 I guess the main worry lurking in the back of my mind is that we may
 actually want to use auto in parameter lists someday to mean more or
 less what it means in declarations:
 
      void foo(auto y = "hi there",
               auto x = 23.f,
               const z = ABigNamedStruct())
      {. . . }
 
 And having it mean something slightly different for 'this' methods than
 for an ordinary 'foo' method would just be confusing.

Exactly. When the macros come, I expect to be able to say initMembers(a,b,c); and the compiler to turn that into: this.a = a; this.b = b; this.c = c; I find it a bit dangerous to add new features without taking into account all semantics. The assignment part is pretty simple compared to the parameter type inference. Still, what about the order of assignments? What if it should be different than the order or parameters (e.g. because of side effects)?
Sep 20 2007
prev sibling parent Robert Fraser <fraserofthenight gmail.com > writes:
On the other hand, this way you could do some best things like requiring a
particular subclass to be assigned to a sipreclass type (useful if you have two
related class hierarchies.

Steven Schveighoffer Wrote:

 
 "Bill Baxter" wrote
 I like the idea but I'm not wild about the syntax you've chosen.  I'd like 
 to be able to read off the types of the parameters from the function 
 signature without having to dig around in the class for where the memebers 
 are defined.  What about something like prefixing the name with a dot?


    this(int .year, int .month, int .day, int .hour, int .minute, int 
 .second)

Personally, I like Janice's idea better. It should be up to the IDE to tell you what the types are for the constructor. Imagine a situation like this: class X { int y; this(int .y) {} } Now the author decides y should be a long: class X { long y; this(int .y) {} } Oops, forgot to update the constructor. But the compiler won't complain because this.y = y is valid. With Janice's syntax, this doesn't happen. -Steve

Sep 20 2007
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 20 Sep 2007 11:05:40 +0100, Janice Caron wrote:

 Please could we let
 
  this(auto n) {}
  T n;
 
 be syntactic sugar for
 
  this(T n)
  {
      this.n = n;
  }
  T n;

This looks exactly like a problem that AST macros could solve. This is only one example of a more generic construct, in which the code writer lists a set of names and each name is used to create an assignment from one variable to another variable whose name is based on the target variable's name. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 20 2007
parent Matti Niemenmaa <see_signature for.real.address> writes:
Derek Parnell wrote:
 On Thu, 20 Sep 2007 11:05:40 +0100, Janice Caron wrote:
 
 Please could we let

  this(auto n) {}
  T n;

 be syntactic sugar for

  this(T n)
  {
      this.n = n;
  }
  T n;

This looks exactly like a problem that AST macros could solve. This is only one example of a more generic construct, in which the code writer lists a set of names and each name is used to create an assignment from one variable to another variable whose name is based on the target variable's name.

What if you have a constructor in which you don't want some of the variables to be automatically assigned? I.e.: this(int a, auto x, auto y, auto z, int b) { // code which handles a and b } You could, of course, write a simple macro within the constructor which automatically does "this.x = x; this.y = y; this.z = z;" but you're losing the main advantage (in my eyes), which is that the types of the variables need to be specified only once. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 20 2007
prev sibling next sibling parent Regan Heath <regan netmail.co.nz> writes:
Alternate syntax suggestion:

class Point {
   int x;
   int y;
   int foo;  //not implicitly assigned any value

   this(int x, int y, int bar):(x,y)  //bar is not assigned to anything
   {
     //super constructor calls go here
     //members are assigned here (_after_ calling super)
     //first line of user code goes here
     if (x > 5) {}  //refers to member 'x' not parameter 'x'
   }
}

The idea(s) here being:

1. If you want to implicitly assign parameters to members you must give 
the parameters 'exactly' the same name as the member.  (I find myself 
wanting to do this anyway)

2. If you use the member/parameter name inside the constructor you will 
be referring to the member, and not the paramter.  (Essentially the 
parameter ceases to exist the moment it has been assigned to the member)

3. The variables to be assigned are specified by name (only) in the :() 
part of the constructor.  (The compiler will verify these 
members/parameters exist - requires verifying members in base classes too)

4. Assignments happen after calls to super* but before the first line of 
constructor code.  This ensures they 'overwrite' any values assigned in 
super calls.  In the case of an explicit super call assignments happen 
before the first line of constructor code, before the explicit super call.

This syntax gives a bit more flexibility that the original idea at the 
cost of some verbosity but I think it's still fairly clean and clear.

Regan
Sep 20 2007
prev sibling next sibling parent reply "Craig Black" <cblack ara.com> writes:
Another idea:

this(auto ...) {}

Could do all the parameters.  So even less typing. 
Sep 20 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Craig Black wrote:
 Another idea:
 
 this(auto ...) {}
 
 Could do all the parameters.  So even less typing. 

I think that's too much of a niche case. --bb
Sep 20 2007
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Craig Black" <cblack ara.com> wrote in message 
news:fcuggd$575$1 digitalmars.com...
 Another idea:

 this(auto ...) {}

 Could do all the parameters.  So even less typing.

template AutoCtor() { this(typeof(typeof(this).tupleof) args) { foreach(i, val; args) this.tupleof[i] = val; } } class A { int x, y, z; float w; mixin AutoCtor; } void main() { scope a = new A(4, 5, 6, 7.8); Stdout.formatln("{} {} {} {}", a.x, a.y, a.z, a.w); } Templates are just.. too cool.
Sep 20 2007
next sibling parent Xinok <xnknet gmail.com> writes:
How about this?

this(this.a, this.b, this.c)

This clearly shows that you're initializing a variable in the object.

I don't like the use of auto here because:
this(auto a)
I read this as:
this(T)(T a)


Another idea I've had for a while is creating a list of members to 
generate a tuple. Take for example:

obj.(a, b, c)

This would generate a tuple with members a, b, and c.

This same syntax could be applied here:

this(this.(a, b, c))
Sep 20 2007
prev sibling next sibling parent "Craig Black" <cblack ara.com> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:fcurrh$ofa$1 digitalmars.com...
 "Craig Black" <cblack ara.com> wrote in message 
 news:fcuggd$575$1 digitalmars.com...
 Another idea:

 this(auto ...) {}

 Could do all the parameters.  So even less typing.

template AutoCtor() { this(typeof(typeof(this).tupleof) args) { foreach(i, val; args) this.tupleof[i] = val; } } class A { int x, y, z; float w; mixin AutoCtor; } void main() { scope a = new A(4, 5, 6, 7.8); Stdout.formatln("{} {} {} {}", a.x, a.y, a.z, a.w); } Templates are just.. too cool.

I agree. That is VERY cool.
Sep 21 2007
prev sibling parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
Jarrett Billingsley wrote:
 class A
 {
     int x, y, z;
     float w;
 
     mixin AutoCtor;
 }

 Templates are just.. too cool.

Yes, but unfortunately template mixin constructors will not overload with other constructors. With normal functions you can use alias to work around it, but for constructors mixin AutoCtor myautoctor; alias myautoctor.this this; fails. I think you will have to use string mixins to make this work right... Christian
Sep 22 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Christian Kamm" <kamm.incasoftware shift-at-left-and-remove-this.de> wrote 
in message news:fd2pb0$1g3m$1 digitalmars.com...

 Yes, but unfortunately template mixin constructors will not overload with
 other constructors. With normal functions you can use alias to work around
 it, but for constructors

 mixin AutoCtor myautoctor;
 alias myautoctor.this this;

 fails. I think you will have to use string mixins to make this work 
 right...

RRRRRRRRRRRRRRRRRRGGGGGGGHHHHHHHH.
Sep 22 2007
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 Please could we let

I think it's a good idea, but I think using the function signature for it probably is not the best idea (as the function signature is for the interface, not the internals).
Sep 20 2007
next sibling parent reply kris <foo bar.com> writes:
Janice Caron wrote:
 On 9/21/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Please could we let

it probably is not the best idea (as the function signature is for the interface, not the internals).

Ah, well since that initial idea, lots of people have come up with different alternatives, and the one suggested by Regan Heath is really nice: class Point { int x; int y; int foo; //not implicitly assigned any value this(int x, int y, int bar):(x,y) //bar is not assigned to anything { //super constructor calls go here //members are assigned here (_after_ calling super) //first line of user code goes here if (x > 5) {} //refers to member 'x' not parameter 'x' } } It's sort of similar to C++'s approach, but less typing and you don't have to pick two different names for each variable, and if you wrote the colon bit on the next line, it wouldn't be in the function signature. (And if you didn't like the overuse of colon, you could always use a keyword like you do for in, out and body). What I like about it is that you can do this: this(int x, int y, int bar):(y,x) //first assign y, then assign x in case there are side-effects to assignment order. Even better would be to allow this(int x, int y, int bar):(...) to be equivalent to this(int x, int y, int bar):(x,y,bar) as between them, that set of possibilities seems to cover every need suggested so far, including your need of not using the function signature.

Wow All of that extra learning, indirection, and potential for confusion just to avoid typing a relatively minuscule number of characters within the ctor of a class: # this.x = x, this.y = y; I'm just knocked out. Really. Here's a thought for everyone to consider. Please take a look at a large and /practical/ body of code, written in D, by capable programmers, and actually count the number of times this would even be applied? Now, take that number and calculate a percentage against the size of the code body. There's plenty of code in dsource to validate this notion against, rather than speculating on a fictional basis. FWIW: I'm quite familiar with at least two rather large bodies of code there, and I can take a quick guess that neither body would apply something like this even once, because there's simply no need for it. Naturally, that doesn't cover every scenario or even a wide set of tastes. However, it does indicate rather well that the notably few "speshul" cases where this /might/ ever get used would likely cause confusion to the reader or maintainer: *because it's not used often enough to remember* That spells "Feature Creep to The Max" Just wow
Sep 20 2007
next sibling parent Derek Parnell <derek psych.ward> writes:
On Thu, 20 Sep 2007 23:24:09 -0700, kris wrote:

 
 Wow
 
 All of that extra learning, indirection, and potential for confusion 
 just to avoid typing a relatively minuscule number of characters within 
 the ctor of a class ...

I admit that this is not something that I'd ever use. I guess I've been burned enough in my 30+ years of programming to know that many "shortcuts" are usually deep cuts that hurt you eventually. I think the first time I came across this concept was the similar one in COBOL - the MOVE CORRESPONDING construct. Seemed like a good idea at first, until some changed the underlying structures and suddenly strange things would happen. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 21 2007
prev sibling next sibling parent Lars Ivar Igesund <larsivar igesund.net> writes:
Janice Caron wrote:

 I tried to look at tango source code, but I can't seem to connect to
 dsource.org right now. Hopefully that's a transient problem.
 
 I know that Sun's official Java tutorial (see
 http://java.sun.com/docs/books/tutorial/java/javaOO/constructors.html)
 tells you to do exactly what I've been talking about. I quote:
 
  public Bicycle(int startCadence, int startSpeed, int startGear) {
      gear = startGear;
      cadence = startCadence;
      speed = startSpeed;
  }
 
 C++'s syntax for doing this is rather complicated and confusing, but I
 should add that the full blown C++ mechanism of allowing member
 variables to be assigned with arbitrary expressions in not needed in
 D. It is needed in C++ because everything is passed by copy, meaning
 that copy constructors and destructors have to be run as values are
 copied to and from functions. That would not be needed in D because
 classes are copied by reference, and structs require no copy
 constructor. Thus
 
  : (x,y,z)
 
 would suffice for us. I think it would be marvellous.

I'm pretty sure that Kris is saying that the assigning to member variables in constructors is such a simple and trivial thing to do, that adding possibly confusing, implicit syntax for it is unnecessary. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Sep 21 2007
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Fri, 21 Sep 2007 08:43:41 +0100, Janice Caron wrote:

 I tried to look at tango source code, but I can't seem to connect to
 dsource.org right now. Hopefully that's a transient problem.
 
 I know that Sun's official Java tutorial (see
 http://java.sun.com/docs/books/tutorial/java/javaOO/constructors.html)
 tells you to do exactly what I've been talking about. I quote:
 
  public Bicycle(int startCadence, int startSpeed, int startGear) {
      gear = startGear;
      cadence = startCadence;
      speed = startSpeed;
  }

It's just that I'm more likely to do something like ... this(int startCadence, int startSpeed, int startGear) { if (startGear > 0 && startGear <= Bicycle.maxGear) this.gear = startGear; else this.gear = Bicycle.defaultGear; // or exception if (startCadence > 0 && startCadence <= Bicycle.maxCadence) this.Cadence = startCadence; else this.Cadence = Bicycle.defaultCadence; // or exception if (startSpeed > 0 && startSpeed <= Bicycle.maxSpeed(this.gear, this.Cadence)) this.Speed = startSpeed; else this.Speed = Bicycle.calcSpeed(this.gear, this.Cadence); } than just a simple set of assignments. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 21 2007
prev sibling next sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 On 9/21/07, kris <foo bar.com> wrote:
 Here's a thought for everyone to consider. Please take a look at a large
 and /practical/ body of code, written in D, by capable programmers, and
 actually count the number of times this would even be applied?

Are you saying it's /rare/ to assign a member variable from a constructor parameter? Or are you just saying it's rare to use the "this.x" notation. I know I usually give my member variables different names from parameter names to avoid having to do that. I don't have a large body of D to look at, but I certainly see T(U x_, V y_) : x(x_), y(y_) {} a lot in C++ (as well as initialisation by assignment within the constructor body, by less experienced programmers).

IMHO kris is right regarding this idea. we should try to keep the size of the language to a minimum and not add unnecessary language constructs just for the sake of it. each such feature complicates the language and makes D that much more difficult to learn. this thread already contains an implementation of such a construct using existing language features and when D gets macros everyone could add whatever she wants to the language just like you do with Java annotations.
Sep 21 2007
prev sibling next sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
kris wrote:
 Janice Caron wrote:
 On 9/21/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Please could we let

it probably is not the best idea (as the function signature is for the interface, not the internals).

Ah, well since that initial idea, lots of people have come up with different alternatives, and the one suggested by Regan Heath is really nice: class Point { int x; int y; int foo; //not implicitly assigned any value this(int x, int y, int bar):(x,y) //bar is not assigned to anything { //super constructor calls go here //members are assigned here (_after_ calling super) //first line of user code goes here if (x > 5) {} //refers to member 'x' not parameter 'x' } } It's sort of similar to C++'s approach, but less typing and you don't have to pick two different names for each variable, and if you wrote the colon bit on the next line, it wouldn't be in the function signature. (And if you didn't like the overuse of colon, you could always use a keyword like you do for in, out and body). What I like about it is that you can do this: this(int x, int y, int bar):(y,x) //first assign y, then assign x in case there are side-effects to assignment order. Even better would be to allow this(int x, int y, int bar):(...) to be equivalent to this(int x, int y, int bar):(x,y,bar) as between them, that set of possibilities seems to cover every need suggested so far, including your need of not using the function signature.

Wow All of that extra learning, indirection, and potential for confusion just to avoid typing a relatively minuscule number of characters within the ctor of a class: # this.x = x, this.y = y; I'm just knocked out. Really. Here's a thought for everyone to consider. Please take a look at a large and /practical/ body of code, written in D, by capable programmers, and actually count the number of times this would even be applied? Now, take that number and calculate a percentage against the size of the code body. There's plenty of code in dsource to validate this notion against, rather than speculating on a fictional basis. FWIW: I'm quite familiar with at least two rather large bodies of code there, and I can take a quick guess that neither body would apply something like this even once, because there's simply no need for it. Naturally, that doesn't cover every scenario or even a wide set of tastes. However, it does indicate rather well that the notably few "speshul" cases where this /might/ ever get used would likely cause confusion to the reader or maintainer: *because it's not used often enough to remember* That spells "Feature Creep to The Max" Just wow

I've often been running into this situation of creating constructors that assign their parameters to fields, but still I agree that it doesn't seem worth it to add new syntax just for this minor issue, at least not any of the syntax proposals presented here. I can't argue any further other than re-state that I'm on the side that thinks the language should be kept _as simple as reasonable_. And this goes regardless of the fact that D has meta-programming capabilities that could allow implementing some feature like this outside of the language itself. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 21 2007
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
kris wrote:
 That spells "Feature Creep to The Max"

You do have a very good point. It doesn't add any expressive power, just saves some typing. It may not be worth the 'cognitive load' and inevitable bugs.
Sep 21 2007
prev sibling parent James Dennett <jdennett acm.org> writes:
Janice Caron wrote:
 I tried to look at tango source code, but I can't seem to connect to
 dsource.org right now. Hopefully that's a transient problem.
 
 I know that Sun's official Java tutorial (see
 http://java.sun.com/docs/books/tutorial/java/javaOO/constructors.html)
 tells you to do exactly what I've been talking about. I quote:
 
  public Bicycle(int startCadence, int startSpeed, int startGear) {
      gear = startGear;
      cadence = startCadence;
      speed = startSpeed;
  }
 
 C++'s syntax for doing this is rather complicated and confusing, but I
 should add that the full blown C++ mechanism of allowing member
 variables to be assigned with arbitrary expressions in not needed in
 D. It is needed in C++ because everything is passed by copy, meaning
 that copy constructors and destructors have to be run as values are
 copied to and from functions. That would not be needed in D because
 classes are copied by reference, and structs require no copy
 constructor. Thus
 
  : (x,y,z)
 
 would suffice for us. I think it would be marvellous.

It's nothing to do with the need to copy by-value objects in C++, and everything to do with the difference between initialization and assignment. Many C++ entities cannot be assigned to (references, const objects, objects of class types which don't allow assignment), and C++ needs syntax to initialize them. The body of the constructor is too late. -- James
Sep 21 2007
prev sibling next sibling parent Jascha Wetzel <firstname mainia.de> writes:
Walter Bright wrote:
 Janice Caron wrote:
 Please could we let

I think it's a good idea, but I think using the function signature for it probably is not the best idea (as the function signature is for the interface, not the internals).

maybe macros could sort this one out. they'd need variadic or tuple parameters: macro thisInit(T...) { foreach ( t; T ) this.t = t; } this(int a, float b) { thisInit(a,b); } ...or similar.
Sep 21 2007
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2007-09-21 00:57:01 -0400, "Janice Caron" <caron800 googlemail.com> said:

   this(int x, int y, int bar):(x,y)  //bar is not assigned to anything
   {
     //super constructor calls go here
     //members are assigned here (_after_ calling super)
     //first line of user code goes here
     if (x > 5) {}  //refers to member 'x' not parameter 'x'
   }

I think you are illustrating a point of ambiguity in this syntax. You're saying on the last line that since there's an auto-assignment before the body 'x' now represents the member variable. I find that odd, an potentially confusing. I understand why it makes sense, because once the parameter has been assigned there's generally no need to reuse it, but you may still want to access the member. Still, I don't like it since the pretty innocuous thing in the head (the auto-assignment) changes the standard semantics of the function. Another confusing thing is that members are not assigned before the constructor call, despite that assignment being specified way up in the code. So I'd like to propose something else. Let's begin with a basic concept which I call "group-assignment": this(int x, int y, int bar) { this = { x: x, y: y }; if (x > 5) {} // refers to parameter 'x' as usual. } The group-assignment "this = {}" would assign values to members using the same syntax as for statically initializing a struct. The mass assignment happen exactly where you put it in the code and, in the case above, is equivalent to writing this: this.x = x; this.y = y; If you need to call super, it can be done either before or after the assignment (as you can do now with regular assignment). You can also change one of the variables prior the group-assignment if you wish. Then, to remove the need to type each variable twice, a shortcut could be added to that syntax, perhaps like this: this(int x, int y, int bar) { this = { :x, :y }; if (x > 5) {} // refers to parameter 'x' as usual. } Basically: if you omit the member name but the value is still preceded by a colon, and that value is a variable of the same name as the member, you have an assignment to that member. Oh, and the group-assigment syntax doesn't need to apply only to constructors, it can work in all member functions, and really everywhere if you use something else than 'this' on the left. For instance: myPoint = { :x, :y } would simply read as a shorthand for this: myPoint.x = x; myPoint.y = y; What do you think? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 21 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 to be equivalent to
 
   this(int x, int y, int bar):(x,y,bar)
 
 as between them, that set of possibilities seems to cover every need
 suggested so far, including your need of not using the function
 signature.

You're still typing the name twice! To fix it, gotta fix it all the way.
Sep 21 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 9/21/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Please could we let

I think it's a good idea, but I think using the function signature for it probably is not the best idea (as the function signature is for the interface, not the internals).

Ah, well since that initial idea, lots of people have come up with different alternatives, and the one suggested by Regan Heath is really nice: class Point { int x; int y; int foo; //not implicitly assigned any value this(int x, int y, int bar):(x,y) //bar is not assigned to anything { //super constructor calls go here //members are assigned here (_after_ calling super) //first line of user code goes here if (x > 5) {} //refers to member 'x' not parameter 'x' } } It's sort of similar to C++'s approach, but less typing and you don't have to pick two different names for each variable, and if you wrote the colon bit on the next line, it wouldn't be in the function signature. (And if you didn't like the overuse of colon, you could always use a keyword like you do for in, out and body). What I like about it is that you can do this: this(int x, int y, int bar):(y,x) //first assign y, then assign x in case there are side-effects to assignment order. Even better would be to allow this(int x, int y, int bar):(...) to be equivalent to this(int x, int y, int bar):(x,y,bar) as between them, that set of possibilities seems to cover every need suggested so far, including your need of not using the function signature.
Sep 20 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
I tried to look at tango source code, but I can't seem to connect to
dsource.org right now. Hopefully that's a transient problem.

I know that Sun's official Java tutorial (see
http://java.sun.com/docs/books/tutorial/java/javaOO/constructors.html)
tells you to do exactly what I've been talking about. I quote:

 public Bicycle(int startCadence, int startSpeed, int startGear) {
     gear = startGear;
     cadence = startCadence;
     speed = startSpeed;
 }

C++'s syntax for doing this is rather complicated and confusing, but I
should add that the full blown C++ mechanism of allowing member
variables to be assigned with arbitrary expressions in not needed in
D. It is needed in C++ because everything is passed by copy, meaning
that copy constructors and destructors have to be run as values are
copied to and from functions. That would not be needed in D because
classes are copied by reference, and structs require no copy
constructor. Thus

 : (x,y,z)

would suffice for us. I think it would be marvellous.
Sep 21 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 9/21/07, kris <foo bar.com> wrote:
 Here's a thought for everyone to consider. Please take a look at a large
 and /practical/ body of code, written in D, by capable programmers, and
 actually count the number of times this would even be applied?

Are you saying it's /rare/ to assign a member variable from a constructor parameter? Or are you just saying it's rare to use the "this.x" notation. I know I usually give my member variables different names from parameter names to avoid having to do that. I don't have a large body of D to look at, but I certainly see T(U x_, V y_) : x(x_), y(y_) {} a lot in C++ (as well as initialisation by assignment within the constructor body, by less experienced programmers).
Sep 21 2007
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
This is just silly.  There's no reason to make this a *language*
feature.  I mean, we have templates and mixins for a reason!  To whit:

module lazy_janice;

import std.metastrings;
import std.stdio : writefln;
import std.string : format;

template Tuple(T...)
{
    alias T Tuple;
}

template lazyJaniceInit(uint i)
{
    const lazyJaniceInit = "";
}

template lazyJaniceInit(uint i, alias Member, Members...)
{
    const lazyJaniceInit =
        Member.stringof~" = args["~ToString!(i)~"];\n"
        ~ lazyJaniceInit!(i+1,Members);
}

template lazyJaniceArgs()
{
    alias Tuple!() lazyJaniceArgs;
}

template lazyJaniceArgs(alias Member, Members...)
{
    alias Tuple!(typeof(Member), lazyJaniceArgs!(Members))
            lazyJaniceArgs;
}

template lazyJanice(Members...)
{
    this(lazyJaniceArgs!(Members) args)
    {
        mixin(lazyJaniceInit!(0, Members));
    }
}

class Foo
{
    int a;
    float b;

    mixin lazyJanice!(a,b);

    string toString()
    {
        return "Foo(%s,%s)".format(a,b);
    }
}

void main()
{
    auto foo = new Foo(42,3.1413);
    writefln(foo);
}

Easy as can be.  You might want to rename the template, though... :3

	-- Daniel
Sep 21 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Daniel Keep Wrote:

 
 This is just silly.  There's no reason to make this a *language*
 feature.  I mean, we have templates and mixins for a reason!  To whit:
 
 module lazy_janice;
 
 import std.metastrings;
 import std.stdio : writefln;
 import std.string : format;
 
 template Tuple(T...)
 {
     alias T Tuple;
 }
 
 template lazyJaniceInit(uint i)
 {
     const lazyJaniceInit = "";
 }
 
 template lazyJaniceInit(uint i, alias Member, Members...)
 {
     const lazyJaniceInit =
         Member.stringof~" = args["~ToString!(i)~"];\n"
         ~ lazyJaniceInit!(i+1,Members);
 }
 
 template lazyJaniceArgs()
 {
     alias Tuple!() lazyJaniceArgs;
 }
 
 template lazyJaniceArgs(alias Member, Members...)
 {
     alias Tuple!(typeof(Member), lazyJaniceArgs!(Members))
             lazyJaniceArgs;
 }
 
 template lazyJanice(Members...)
 {
     this(lazyJaniceArgs!(Members) args)
     {
         mixin(lazyJaniceInit!(0, Members));
     }
 }
 
 class Foo
 {
     int a;
     float b;
 
     mixin lazyJanice!(a,b);
 
     string toString()
     {
         return "Foo(%s,%s)".format(a,b);
     }
 }
 
 void main()
 {
     auto foo = new Foo(42,3.1413);
     writefln(foo);
 }
 
 Easy as can be.  You might want to rename the template, though... :3
 
 	-- Daniel

Not a fan of the whole CTFE craze?
Sep 21 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Robert Fraser wrote:
 Daniel Keep Wrote:
 
 This is just silly.  There's no reason to make this a *language*
 feature.  I mean, we have templates and mixins for a reason!  To whit:

 [...]

 Easy as can be.  You might want to rename the template, though... :3

 	-- Daniel

Not a fan of the whole CTFE craze?

Whatever gives you that impression? Code I've actually written: import engine.engine : Engine; import util.ctfe.ctstrings; import util.ctfe.string; // You better believe *this* uses CTFE; it's parsing a damn .ini file! // It becomes something like `const ROOT_CLASS = "game.foo.Bar";` mixin ctString!("strings.ini", "ROOT_CLASS"); mixin("static import "~ctfe_module(ROOT_CLASS)~";"); int main(string[] args) { return Engine.main(args, ROOT_CLASS); } And that actually worked, too. Lost interest since rebuild wouldn't follow the mixined import, tho :3 I just didn't need my evil CTFE powers on this one ;) -- Daniel
Sep 21 2007