Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 26, 2013 Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Having a conversation about the design of the new std.process, I lamented that typesafe variadics must be the last element in the list of parameters. But I would love to have a version that simply takes parameters as parameters. In Tango's process class, it was a nice feature. Stuff like this just worked: setArgs("prog.exe", "arg1", "arg2"); setArgs("prog.exe arg1 arg2".split()); All with one function. Because spawnProcess has optional parameters at the end, it makes it impossible to have this, since typesafe variadics requires that the variadic be the last part of the function parameters, and spawnProcess must take the optional stream and config parameters last. But why? This seems perfectly plausible to me: spawnProcess(string progname, string[] args..., File _stdin = stdin, File _stdout = stdout, File _stderr = stderr, Config config = Config.none); There is no ambiguity with something like: spawnProcess("prog.exe", "arg1", "arg2", File("infile.txt")); A string does not implicitly convert to a File, and vice versa. Typesafe variadics are actually extremely simple to deal with (much simpler than C-style or D-style variadics), it's just passed as a simple D slice. The compiler takes care of the nasty parts, and is entirely call-side. Basically, in order for this to work, a typesafe variadic parameter must have no way to implicitly convert to or from the type of the next parameters, up to the first non-variadic parameter. In other words: void foo(T[] arg1..., U[] arg2..., V arg3, W[] arg4...) This works if T, U and V cannot be implicitly converted to each other. W can implicitly convert to or from V, because V is positional (there MUST be one V argument in this call, and that matches arg3, so any args after that are assumed to be arg4) Would this work? Would it be something people want? -Steve |
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote: > Would it be something people want? Yes. Also related: http://d.puremagic.com/issues/show_bug.cgi?id=8687 One extremely common and important use-case of allowing it is this: foo(string[] args..., string file = __FILE__, size_t line = __LINE__); Right now as soon as you introduce variadics you can forget about using __FILE__/__LINE__ at runtime (unless you resort to some inner-template tricks, but that only works in some cases methinks, probably not at runtime). |
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tue, Feb 26, 2013 at 03:29:51PM -0500, Steven Schveighoffer wrote: > Having a conversation about the design of the new std.process, I lamented that typesafe variadics must be the last element in the list of parameters. [...] > But why? This seems perfectly plausible to me: > > spawnProcess(string progname, string[] args..., File _stdin = stdin, File _stdout = stdout, File _stderr = stderr, Config config = Config.none); [...] > Basically, in order for this to work, a typesafe variadic parameter must have no way to implicitly convert to or from the type of the next parameters, up to the first non-variadic parameter. > > In other words: > > void foo(T[] arg1..., U[] arg2..., V arg3, W[] arg4...) > > This works if T, U and V cannot be implicitly converted to each other. W can implicitly convert to or from V, because V is positional (there MUST be one V argument in this call, and that matches arg3, so any args after that are assumed to be arg4) > > Would this work? Would it be something people want? [...] +1, yes!!! This would also make it possible to do things like user-defined library types that throw exception at the caller by using __FILE__ and __LINE__, when the function is variadic. Currently, there is no way to do this: void func(MyType args..., string file=__FILE__, size_t line=__LINE__) { dotDotDotMagic(args); if (failed) throw new Exception(file, line, epicFailMsg); } Well, you could put file and line as compile-time parameters, but then you'll get extreme template bloat. Nor, for that matter, this: void func(T...)(string file=__FILE__, size_t line=__LINE__, MyType target, T args) { ... } Which, ideally, would do the right thing when invoked like this: MyType obj1, obj2; func(obj2, 1, 2, 3, 'a', 'c', "c"); func(obj2, "abc", 'd', 'e', 'f', 123); In both cases there is no ambiguity, because MyType does not implicitly convert to string or size_t, so, in theory, the compiler should be able to figure out what the user intended. T -- MAS = Mana Ada Sistem? |
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On Tue, 26 Feb 2013 15:36:11 -0500, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
> On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:
>> Would it be something people want?
>
> Yes. Also related: http://d.puremagic.com/issues/show_bug.cgi?id=8687
>
> One extremely common and important use-case of allowing it is this:
>
> foo(string[] args..., string file = __FILE__, size_t line = __LINE__);
>
> Right now as soon as you introduce variadics you can forget about using __FILE__/__LINE__ at runtime (unless you resort to some inner-template tricks, but that only works in some cases methinks, probably not at runtime).
Well, except that example wouldn't work :)
This would though:
foo(string[] args..., size_t line = __LINE__, string file = __FILE__);
Excellent use case though!
-Steve
|
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 26 February 2013 at 20:52:46 UTC, Steven Schveighoffer wrote:
> On Tue, 26 Feb 2013 15:36:11 -0500, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:
>
>> On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:
>>> Would it be something people want?
>>
>> Yes. Also related: http://d.puremagic.com/issues/show_bug.cgi?id=8687
>>
>> One extremely common and important use-case of allowing it is this:
>>
>> foo(string[] args..., string file = __FILE__, size_t line = __LINE__);
>>
>> Right now as soon as you introduce variadics you can forget about using __FILE__/__LINE__ at runtime (unless you resort to some inner-template tricks, but that only works in some cases methinks, probably not at runtime).
>
> Well, except that example wouldn't work :)
>
> This would though:
>
> foo(string[] args..., size_t line = __LINE__, string file = __FILE__);
>
> Excellent use case though!
>
> -Steve
or use a new struct
struct SourcePos {
string file;
size_t line;
}
foo(string[] args..., SourcePos pos = SourcePos(__FILE__, __LINE__));
|
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to simendsjo | On Tue, Feb 26, 2013 at 09:59:22PM +0100, simendsjo wrote: > On Tuesday, 26 February 2013 at 20:52:46 UTC, Steven Schveighoffer wrote: > >On Tue, 26 Feb 2013 15:36:11 -0500, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote: > > > >>On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote: [...] > >>foo(string[] args..., string file = __FILE__, size_t line = > >>__LINE__); > >> > >>Right now as soon as you introduce variadics you can forget about using __FILE__/__LINE__ at runtime (unless you resort to some inner-template tricks, but that only works in some cases methinks, probably not at runtime). > > > >Well, except that example wouldn't work :) > > > >This would though: > > > >foo(string[] args..., size_t line = __LINE__, string file = > >__FILE__); > > > >Excellent use case though! [...] > > or use a new struct > struct SourcePos { > string file; > size_t line; > } > foo(string[] args..., SourcePos pos = SourcePos(__FILE__, __LINE__)); Excellent idea!!! Why didn't I think of this before... this would help even with the current limitation on variadics, as it helps solve ambiguity problems with overloaded functions: void func(string a, string file=__FILE__, int line=__LINE__); void func(string a, string b, string file=__FILE__, int line=__LINE__); func("a"); func("a", "b"); // ambiguity error Encapsulating it in SourcePos avoids the ambiguity problem. But of course, having variadics support this would make it so much more useful. T -- It is not the employer who pays the wages. Employers only handle the money. It is the customer who pays the wages. -- Henry Ford |
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:
> Having a conversation about the design of the new std.process, I lamented that typesafe variadics must be the last element in the list of parameters.
Could the idea be expanded into allowing optional arguments in front of non-optional ones, when it is not ambiguous to do so?
|
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | I proposed this a few weeks ago, but nobody gave feedback. This would enable it without worrying about special cases. http://forum.dlang.org/thread/miqtvuufvlwgfzblexxp@forum.dlang.org feature request: special optional argument (__FILE__, ...) AFTER variadic template. Please let me know what you think! |
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vladimir Panteleev | On Tue, 26 Feb 2013 16:38:39 -0500, Vladimir Panteleev <vladimir@thecybershadow.net> wrote:
> On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:
>> Having a conversation about the design of the new std.process, I lamented that typesafe variadics must be the last element in the list of parameters.
>
> Could the idea be expanded into allowing optional arguments in front of non-optional ones, when it is not ambiguous to do so?
I think so, technically, it's no different than using a variadic parameter, and then requiring exactly none or one element in the variadic argument spot.
The one dangerous thing I thought of is we currently allow two consecutive same-type optional parameters. The issue there is if a type changes, a call to the function might silently bind different parameters.
So perhaps we would have to stick to situations that aren't already valid (such as your idea of having an optional parameter before a required one), and disallow functions to have consecutive like-typed optional parameters in those cases. Not sure if it's worth it. It would be confusing to allow consecutive like-typed optional parameters at the end, but not at the front.
-Steve
|
February 26, 2013 Re: Typesafe variadics in any position | ||||
---|---|---|---|---|
| ||||
Posted in reply to timotheecour | On Tue, 26 Feb 2013 17:04:40 -0500, timotheecour <thelastmammoth@gmail.com> wrote: > I proposed this a few weeks ago, but nobody gave feedback. This would enable it without worrying about special cases. > > http://forum.dlang.org/thread/miqtvuufvlwgfzblexxp@forum.dlang.org > feature request: special optional argument (__FILE__, ...) AFTER variadic template. I think this is a different problem, the issue I'm talking about is typesafe variadics, not variadic templates. > Please let me know what you think! Doesn't this work? foo(string filename=__FILE__, T...)(T args) -Steve |
Copyright © 1999-2021 by the D Language Foundation