www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - double -> double[]... | feature or bug?

reply Andrej Mitrovic <none none.none> writes:
DMD 2.051 with -unittest:

import std.algorithm, std.range, std.stdio : writeln;

void main() {}

void average(double[]) { writeln("non-variadic"); }
void average(double[]...) { writeln("variadic"); }

unittest {
    average(1.5);   // writes "variadic"
}
Dec 22 2010
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, December 22, 2010 12:05:18 Andrej Mitrovic wrote:
 DMD 2.051 with -unittest:
 
 import std.algorithm, std.range, std.stdio : writeln;
 
 void main() {}
 
 void average(double[]) { writeln("non-variadic"); }
 void average(double[]...) { writeln("variadic"); }
 
 unittest {
     average(1.5);   // writes "variadic"
 }

What's the confusion? You gave it a double. That matches the variadic version, no tthe array version. If you gave it an array of doubles, then it would match the array version. That seems entirely straightforward. What's surprising about it? - Jonathan M Davis
Dec 22 2010
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I thought the variadic version would only take this type:

average([1.5], [2.5]);

So a variable number of *array* of doubles, not a variable number of doubles.

On 12/22/10, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 On Wednesday, December 22, 2010 12:05:18 Andrej Mitrovic wrote:
 DMD 2.051 with -unittest:

 import std.algorithm, std.range, std.stdio : writeln;

 void main() {}

 void average(double[]) { writeln("non-variadic"); }
 void average(double[]...) { writeln("variadic"); }

 unittest {
     average(1.5);   // writes "variadic"
 }

What's the confusion? You gave it a double. That matches the variadic version, no tthe array version. If you gave it an array of doubles, then it would match the array version. That seems entirely straightforward. What's surprising about it? - Jonathan M Davis

Dec 22 2010
parent reply Christopher Nicholson-Sauls <ibisbasenji gmail.com> writes:
On 12/22/10 15:06, Andrej Mitrovic wrote:
 Oooh. That cought me off guard, sorry.
 
 Thanks Steve.
 

I'll concede that the syntax can be odd at first, but it also enables some interesting things. For example, this works: class Foo { this (int i, double f) { /*...*/ } /*...*/ } void someFunc ( Foo foo ... ) { /*...*/ } someFunc( 5, 3.14 ); Basically, given a class (and I think struct's work as well) as the variadic type, it will accept either an instance of said class, or any combination of values which can be mapped to a constructor of that class. It can be convenient sometimes. -- Chris N-S
Dec 22 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 While I understand some may consider this a nice feature, for me this is an
enormous bug. A great way toward code obfuscation. I like D among other reasons
because it's rather clear compared to other languages of the family.

The main problem here is that I have never felt the need of that feature, so for me it's useless. Has Walter added it after a good number of people have asked for this feature? Has any one here needed it? Bye, bearophile
Dec 23 2010
parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 spir:
 
 While I understand some may consider this a nice feature, for me this is an
enormous bug. A great way toward code obfuscation. I like D among other reasons
because it's rather clear compared to other languages of the family.

The main problem here is that I have never felt the need of that feature, so for me it's useless. Has Walter added it after a good number of people have asked for this feature? Has any one here needed it? Bye, bearophile

I'm almost certain that the behaviour is not intentional.
Dec 23 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

 This feature brings absolutely nothing to the table IMO.

Added as issue 5368. Bye, bearophile
Dec 24 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 22 Dec 2010 15:46:01 -0500, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 I thought the variadic version would only take this type:

 average([1.5], [2.5]);

 So a variable number of *array* of doubles, not a variable number of  
 doubles.

No, that's not it. T[] arg... is a typesafe variadic argument of type T. The docs describe it here: http://www.digitalmars.com/d/2.0/function.html (search for typesafe) Hopefully that helps? If you were looking for something to accept your above args, it would be: double[][] arg... -Steve
Dec 22 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Oooh. That cought me off guard, sorry.

Thanks Steve.

On 12/22/10, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 On Wed, 22 Dec 2010 15:46:01 -0500, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 I thought the variadic version would only take this type:

 average([1.5], [2.5]);

 So a variable number of *array* of doubles, not a variable number of
 doubles.

No, that's not it. T[] arg... is a typesafe variadic argument of type T. The docs describe it here: http://www.digitalmars.com/d/2.0/function.html (search for typesafe) Hopefully that helps? If you were looking for something to accept your above args, it would be: double[][] arg... -Steve

Dec 22 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Thu, 23 Dec 2010 00:34:41 -0600
Christopher Nicholson-Sauls <ibisbasenji gmail.com> wrote:

 On 12/22/10 15:06, Andrej Mitrovic wrote:
 Oooh. That cought me off guard, sorry.
=20
 Thanks Steve.
=20

I'll concede that the syntax can be odd at first, but it also enables some interesting things. For example, this works: =20 class Foo { this (int i, double f) { /*...*/ } /*...*/ } =20 void someFunc ( Foo foo ... ) { /*...*/ } =20 someFunc( 5, 3.14 ); =20 Basically, given a class (and I think struct's work as well) as the variadic type, it will accept either an instance of said class, or any combination of values which can be mapped to a constructor of that class. It can be convenient sometimes.

While I understand some may consider this a nice feature, for me this is an= enormous bug. A great way toward code obfuscation. I like D among other re= asons because it's rather clear compared to other languages of the family. = There should be no automagic constructor call (at least in this case, when = the type is not even mentionned on the caller side). This may even lead to very naughty bugs. And what if Foo has subtypes, and = the one actually invoked is the one intended by the user? Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 23 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/23/10, bearophile <bearophileHUGS lycos.com> wrote:
 spir:

 While I understand some may consider this a nice feature, for me this is
 an enormous bug. A great way toward code obfuscation. I like D among other
 reasons because it's rather clear compared to other languages of the
 family.

The main problem here is that I have never felt the need of that feature, so for me it's useless. Has Walter added it after a good number of people have asked for this feature? Has any one here needed it? Bye, bearophile

You should probably ask in d-general. It looks like a dangerous feature to have. If you have that function laying in another imported module you might not even realize that you're constructing an object. Consider this: void test(int x, int y, string z); // your module which you accidentally forgot to import void test(int x, Foo f ...); // some other module that *is* imported test(1, 4, "def"); // calling site that constructs a Foo object Maybe it takes more typing, but I prefer this: test(1, new Foo(4, "def")); It's explicit and you can reason about it without having to inspect other modules.
Dec 23 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Dec 2010 12:34:45 -0500, Don <nospam nospam.com> wrote:

 bearophile wrote:
 spir:

 While I understand some may consider this a nice feature, for me this  
 is an enormous bug. A great way toward code obfuscation. I like D  
 among other reasons because it's rather clear compared to other  
 languages of the family.

feature, so for me it's useless. Has Walter added it after a good number of people have asked for this feature? Has any one here needed it? Bye, bearophile

I'm almost certain that the behaviour is not intentional.

From http://www.digitalmars.com/d/2.0/function.html : "Typesafe variadic functions are used when the variable argument portion of the arguments are used to construct an array >>>> or class object <<<<." (emphasis added) And it goes on to show a similar example as to what has been discussed here. I think it's intentional, and I agree that I've never used or thought "gee, I wish D did this". I wouldn't be sorry to see it go. In fact, I'd advocate for getting rid of it. It creates a hidden allocation, which I'm very much against. -Steve
Dec 23 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Thu, 23 Dec 2010 13:38:30 -0500
"Steven Schveighoffer" <schveiguy yahoo.com> wrote:

 I think it's intentional, and I agree that I've never used or thought =20
 "gee, I wish D did this".  I wouldn't be sorry to see it go.  In fact, I'=

 advocate for getting rid of it.  It creates a hidden allocation, which I'=

 very much against.

Agreed. Not only hidden allocation, but the "feature" may be unintentionall= y used, leading to hard-to-find bugs. There should never by (user) type ins= tanciation without explicite mention of the type (if only on the left side = of an assignment). Surprise --> bugs. Denis - -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 23 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 23 Dec 2010 14:51:02 -0500, spir <denis.spir gmail.com> wrote:

 On Thu, 23 Dec 2010 13:38:30 -0500
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote:

 I think it's intentional, and I agree that I've never used or thought
 "gee, I wish D did this".  I wouldn't be sorry to see it go.  In fact,  
 I'd
 advocate for getting rid of it.  It creates a hidden allocation, which  
 I'm
 very much against.

Agreed. Not only hidden allocation, but the "feature" may be unintentionally used, leading to hard-to-find bugs. There should never by (user) type instanciation without explicite mention of the type (if only on the left side of an assignment). Surprise --> bugs.

To drive the point home, we can examine the problem that typesafe variadic args solves. Take an array example. If we didn't have typesafe variadic args for arrays, this code: void foo(int[] args...); foo(1, 2, 3); would become: void foo(int[] args); int[3] x; x[0] = 1; x[1] = 2; x[2] = 3; foo(x[]); Not so nice. Almost the same issue for a typesafe variadic with fixed-sized arrays. Now, let's look at the same thing for a class: class C { this(int i, string s); } void foo(C arg...); foo(1, "hi"); And the code without typesafe variadics: void foo(C arg); foo(new C(1, "hi")); Not a lot different, we have just basically shown that you are doing an allocation (which is a good thing to show). Going even further, we can even do this: void foo(int i, string s) { foo(new C(i, s)); } And then we get *exactly* the same api. This feature brings absolutely nothing to the table IMO. -Steve
Dec 23 2010