digitalmars.D - Typesafe variadics in any position
- Steven Schveighoffer (33/33) Feb 26 2013 Having a conversation about the design of the new std.process, I lamente...
- Andrej Mitrovic (12/13) Feb 26 2013 Yes. Also related:
- Steven Schveighoffer (7/16) Feb 26 2013 Well, except that example wouldn't work :)
- simendsjo (9/34) Feb 26 2013 or use a new struct
- H. S. Teoh (17/46) Feb 26 2013 [...]
- H. S. Teoh (30/52) Feb 26 2013 [...]
- Vladimir Panteleev (4/7) Feb 26 2013 Could the idea be expanded into allowing optional arguments in
- timotheecour (6/6) Feb 26 2013 I proposed this a few weeks ago, but nobody gave feedback. This
- Steven Schveighoffer (7/13) Feb 26 2013 I think this is a different problem, the issue I'm talking about is
- H. S. Teoh (7/25) Feb 26 2013 [...]
- Steven Schveighoffer (6/28) Feb 26 2013 Well, not too bad. The template can be a wrapper call, and would likely...
- Andrei Alexandrescu (3/25) Feb 26 2013 Just forward immediately to a regular function. That gets rid of the blo...
- Steven Schveighoffer (15/21) Feb 26 2013 I think so, technically, it's no different than using a variadic
- H. S. Teoh (5/13) Feb 26 2013 +1.
- Jacob Carlborg (5/39) Feb 27 2013 I like. But in the case of spawnProcess I would prefer named parameters:
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
Feb 26 2013
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).
Feb 26 2013
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:Well, except that example wouldn't work :) This would though: foo(string[] args..., size_t line = __LINE__, string file = __FILE__); Excellent use case though! -SteveWould 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).
Feb 26 2013
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:or use a new struct struct SourcePos { string file; size_t line; } foo(string[] args..., SourcePos pos = SourcePos(__FILE__, __LINE__));On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:Well, except that example wouldn't work :) This would though: foo(string[] args..., size_t line = __LINE__, string file = __FILE__); Excellent use case though! -SteveWould 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).
Feb 26 2013
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
Feb 26 2013
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?
Feb 26 2013
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?
Feb 26 2013
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!
Feb 26 2013
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
Feb 26 2013
On Tue, Feb 26, 2013 at 05:16:29PM -0500, Steven Schveighoffer wrote:On Tue, 26 Feb 2013 17:04:40 -0500, timotheecour <thelastmammoth gmail.com> wrote:[...] It should work, except that you'll have template bloat (not as bad as putting __line__ in the compile-time arguments though!) T -- What are you when you run out of Monet? Baroque.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)
Feb 26 2013
On Tue, 26 Feb 2013 17:29:10 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:On Tue, Feb 26, 2013 at 05:16:29PM -0500, Steven Schveighoffer wrote:Well, not too bad. The template can be a wrapper call, and would likely be inlined. But the symbol bloat would suck... -SteveOn Tue, 26 Feb 2013 17:04:40 -0500, timotheecour <thelastmammoth gmail.com> wrote:[...] It should work, except that you'll have template bloat (not as bad as putting __line__ in the compile-time arguments though!)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)
Feb 26 2013
On 2/26/13 5:29 PM, H. S. Teoh wrote:On Tue, Feb 26, 2013 at 05:16:29PM -0500, Steven Schveighoffer wrote:Just forward immediately to a regular function. That gets rid of the bloat. AndreiOn Tue, 26 Feb 2013 17:04:40 -0500, timotheecour <thelastmammoth gmail.com> wrote:[...] It should work, except that you'll have template bloat (not as bad as putting __line__ in the compile-time arguments though!)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)
Feb 26 2013
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: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. -SteveHaving 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?
Feb 26 2013
On Tue, Feb 26, 2013 at 10:38:39PM +0100, Vladimir Panteleev wrote:On Tuesday, 26 February 2013 at 20:29:51 UTC, Steven Schveighoffer wrote:+1. T -- What do you get if you drop a piano down a mineshaft? A flat minor.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?
Feb 26 2013
On 2013-02-26 21:29, 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 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? -SteveI like. But in the case of spawnProcess I would prefer named parameters: spawnProcess("prog.exe", "arg1", "arg2", _stdin: File("infile.txt")); -- /Jacob Carlborg
Feb 27 2013