digitalmars.D - Named arguments via struct initialization in functions
- Seb (54/54) Mar 06 2016 Hey all,
- Chris Wright (34/39) Mar 06 2016 We want something to let people provide arguments sparsely and
- ZombineDev (14/53) Mar 07 2016 The compiler should detect that this call is ambiguous and would
- Chris Wright (6/14) Mar 07 2016 It's a potentially significant amount of work to determine that the
- ZombineDev (8/23) Mar 10 2016 I don't think so. At least not much more than what currently the
- Chris Wright (20/35) Mar 10 2016 Currently, overload resolution deals with a similar problem with numeric...
- ZombineDev (19/61) Mar 11 2016 It's not open-ended - size of the set is equal to the number of
- Jacob Carlborg (6/45) Mar 06 2016 I think the simplest solution is to allow struct member initializer in
- ZombineDev (13/83) Mar 07 2016 +100
- Meta (5/8) Mar 07 2016 Unfortunately this will not work. There was a tuple proposal
- Marc =?UTF-8?B?U2Now7x0eg==?= (11/19) Mar 08 2016 I believe it was the empty tuple, which is indistinguishable from
- ZombineDev (5/13) Mar 10 2016 Can you find the exact case? I'm really interested in getting
- Meta (5/19) Mar 11 2016 Here's the thread where it's pointed out:
- Marc =?UTF-8?B?U2Now7x0eg==?= (5/23) Mar 11 2016 Aside from the empty tuple, I can only find Timon's comment:
- Chris Wright (7/13) Mar 11 2016 {{if(foo()){}}} looks like a tuple containing a delegate or a delegate
- ZombineDev (3/15) Mar 11 2016 Thanks, I had read the DIP, but couldn't find the forum
- Martin Tschierschke (16/63) Mar 08 2016 What about this idea? A new word "as" or something similar.
- Chris Wright (11/13) Mar 08 2016 The syntax isn't an issue.
- Martin Tschierschke (25/38) Mar 09 2016 I have seen the "DIP about named parameters", and i liked the idea
- Idan Arye (18/63) Mar 09 2016 String symbols are Ruby's(and many Lisps', and maybe some other,
- Martin Tschierschke (21/45) Mar 09 2016 Thats true.
- Idan Arye (7/31) Mar 09 2016 If nested strings is what's bothering you, you can always use
- Michael Coulombe (50/58) Mar 09 2016 I posted (in a previous thread about this issue) a library
- Michael Coulombe (9/10) Mar 09 2016 Whoops, forgot this:
- arturg (15/15) Mar 08 2016 hi, has the UDA syntax been proposed already?
- Idan Arye (51/106) Mar 08 2016 As far as I understand, the main two problems with named
- Marc =?UTF-8?B?U2Now7x0eg==?= (7/19) Mar 10 2016 --snip--
- Edwin van Leeuwen (21/27) Mar 08 2016 In ggplotd I often use named tuples as and "anonymoous" struct:
- Edwin van Leeuwen (5/11) Mar 08 2016 Quick clarification. The merge function is used to merge the
- John Colvin (4/27) Mar 09 2016 slightly tangentially, you might be interested in this:
Hey all, I wanted to relive the discussion on named arguments and ping for its current status. There is a bunch of examples to show how needed a unified solution for this problem is, let me give you one from phobos [2]. ``` // I want to allow downsizing iota(10).sliced!(Yes.replaceArrayWithPointer, Yes.allowDownsize)(4); ``` There is of course the alternative solution that an author overloads his function to the utmost, but this results in complexity and duplicated code (see e.g. redBlackTree in phobos [3]). Currently the best solution AFAICT is to use a struct to pass such flags, like ``` struct Options{int x; int y=1; int z=2;} auto fun(Options options) { return options.x + options.y + options.z; } Options options = {x: 4, z: 3}; auto a=fun(options); ``` There are also other workarounds as discussed in [1] (e.g. with CTFE string analysis [4]). I general there two solutions to this problem 1) get true named parameters support in D (probably complicated) 2) allow struct inits in functions - e.g. fun({x: 4}) For 2) Jacob Carlborg has proposed something similar three years ago. In his case he proposed anonymous structs which might be more generally applicable, however just created the struct seems easier and allows more It doesn't seem that complicated to me as the compiler already knows the type of the argument. Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now. What are your thoughts on this issue? On a side note: many templated functions are also complicated and experiencing this issue, so it also might be worth to think about this issue too ;-) Cheers, Seb [1] http://forum.dlang.org/post/pxndhoskpjxvnoacajaz forum.dlang.org [2] https://github.com/DlangScience/mir/issues/18 [3] https://github.com/D-Programming-Language/phobos/pull/4041/files [4] https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.d
Mar 06 2016
On Sun, 06 Mar 2016 17:35:38 +0000, Seb wrote:Hey all, I wanted to relive the discussion on named arguments and ping for its current status.We want something to let people provide arguments sparsely and unambiguously, and if possible in arbitrary order. The existing DIP just lets you provide compiler-checked annotations to verify the parameter names match your expectations, assuming the writer of the function chose to allow it. Nobody much liked it. I've got a draft DIP on my hard drive to provide actual named arguments but haven't gotten around to proposing it. There was considerable disagreement on whether the function parameters should be explicitly marked in order to use them as named or not. Scala, Ruby and Dart require you to mark them. There are a couple other interesting decisions regarding named parameters, but nobody much considered them during the discussion. Ceylon's the most permissive example.2) allow struct inits in functions - e.g. fun({x: 4})I looked into this a bit. I've got another draft DIP for it on my hard drive. There are two obvious ambiguities: struct A { int x; long y; } struct B { int x; string y; } void foo(A a) {} void foo(B b) {} foo({x: 1}); There's no way to tell which overload to invoke. Then let's say I added: void foo(void delegate() dg) {} foo({}); That could be a default-initialized struct of type A or B, or it could be a no-op delegate. You can resolve that with a slightly different syntax: foo(A{x: 1}); I think I noticed an ambiguity with that, too, but I can't recall now. I failed to write it down in any case. Anyway, if it works, it's an improvement. And you only need explicit type marking at the top level; it's unambiguous after that.
Mar 06 2016
On Sunday, 6 March 2016 at 19:10:50 UTC, Chris Wright wrote:On Sun, 06 Mar 2016 17:35:38 +0000, Seb wrote:The compiler should detect that this call is ambiguous and would not allow it. To resolve the ambiguity, the user can write: foo(A{ x: 1 }); foo(B{ x: 1 }); foo(() { }); foo(delegate void() { }); Which I think is a very reasonably requirement. Do you have any other examples of ambiguity that can't be easily resolved?[...]We want something to let people provide arguments sparsely and unambiguously, and if possible in arbitrary order. The existing DIP just lets you provide compiler-checked annotations to verify the parameter names match your expectations, assuming the writer of the function chose to allow it. Nobody much liked it. I've got a draft DIP on my hard drive to provide actual named arguments but haven't gotten around to proposing it. There was considerable disagreement on whether the function parameters should be explicitly marked in order to use them as don't require you to mark them. Ruby and Dart require you to mark them. There are a couple other interesting decisions regarding named parameters, but nobody much considered them during the discussion. Ceylon's the most permissive example.[...]I looked into this a bit. I've got another draft DIP for it on my hard drive. There are two obvious ambiguities: struct A { int x; long y; } struct B { int x; string y; } void foo(A a) {} void foo(B b) {} foo({x: 1}); There's no way to tell which overload to invoke. Then let's say I added: void foo(void delegate() dg) {} foo({}); That could be a default-initialized struct of type A or B, or it could be a no-op delegate. You can resolve that with a slightly different syntax: foo(A{x: 1}); I think I noticed an ambiguity with that, too, but I can't recall now. I failed to write it down in any case.Anyway, if it works, it's an improvement.Yep.And you only need explicit type marking at the top level; it's unambiguous after that.I'm not sure what you mean by "explicit type marking at the top level".
Mar 07 2016
On Mon, 07 Mar 2016 11:06:13 +0000, ZombineDev wrote:The compiler should detect that this call is ambiguous and would not allow it.It's a potentially significant amount of work to determine that the expression is ambiguous, or to disambiguate.To resolve the ambiguity, the user can write: foo(A{ x: 1 });That's why I suggested it.It always is unambiguous to write things like: auto a = A{x: {y: 1}};And you only need explicit type marking at the top level; it's unambiguous after that.I'm not sure what you mean by "explicit type marking at the top level".
Mar 07 2016
On Monday, 7 March 2016 at 19:06:54 UTC, Chris Wright wrote:On Mon, 07 Mar 2016 11:06:13 +0000, ZombineDev wrote:I don't think so. At least not much more than what currently the compiler does for overload resolution (comparing the void(A) overloard to the void(B)). Tuples literals / struct initializer literals / delegates should be classified before the end of the parsing phase (which is actually at least an order of magnitude faster than the semantic phase).The compiler should detect that this call is ambiguous and would not allow it.It's a potentially significant amount of work to determine that the expression is ambiguous, or to disambiguate.Ah ok, agreed.To resolve the ambiguity, the user can write: foo(A{ x: 1 });That's why I suggested it.It always is unambiguous to write things like: auto a = A{x: {y: 1}};And you only need explicit type marking at the top level; it's unambiguous after that.I'm not sure what you mean by "explicit type marking at the top level".
Mar 10 2016
On Thu, 10 Mar 2016 19:01:53 +0000, ZombineDev wrote:On Monday, 7 March 2016 at 19:06:54 UTC, Chris Wright wrote:Currently, overload resolution deals with a similar problem with numeric literals. But there's a big difference between supporting it for one class of related types that's all known at compile time, and supporting it for an open-ended set of types that are entirely unrelated. If I were implement this, the first pass would require struct literal expressions to include the struct type. I might later consider whether to change that.On Mon, 07 Mar 2016 11:06:13 +0000, ZombineDev wrote:I don't think so. At least not much more than what currently the compiler does for overload resolution (comparing the void(A) overloard to the void(B)).The compiler should detect that this call is ambiguous and would not allow it.It's a potentially significant amount of work to determine that the expression is ambiguous, or to disambiguate.Tuples literals / struct initializer literals / delegates should be classified before the end of the parsing phaseThat is, you can determine whether something is a delegate literal or a struct literal (even without marking struct literals with their type) during parsing. For a moment, I misunderstood and thought you were talking about assigning types to them.(which is actually at least an order of magnitude faster than the semantic phase).It wouldn't be parseable with an LL(k) parser, which is a minor thing. More to the point, depending on how DMD's parser is designed, it might be pretty awkward to parse something that might be a labeled statement or a struct variable initializer. If we can get something that's approximately as good (arguably better because it's less ambiguous, arguably worse because it's more to type) with far less work, then, given the small number of people who contribute to DMD, it would behoove us to choose the easier option.
Mar 10 2016
On Friday, 11 March 2016 at 05:09:44 UTC, Chris Wright wrote:On Thu, 10 Mar 2016 19:01:53 +0000, ZombineDev wrote:It's not open-ended - size of the set is equal to the number of overloads taking structs, which in practice should be less than 20.On Monday, 7 March 2016 at 19:06:54 UTC, Chris Wright wrote:Currently, overload resolution deals with a similar problem with numeric literals. But there's a big difference between supporting it for one class of related types that's all known at compile time, and supporting it for an open-ended set of types that are entirely unrelated.On Mon, 07 Mar 2016 11:06:13 +0000, ZombineDev wrote:I don't think so. At least not much more than what currently the compiler does for overload resolution (comparing the void(A) overloard to the void(B)).The compiler should detect that this call is ambiguous and would not allow it.It's a potentially significant amount of work to determine that the expression is ambiguous, or to disambiguate.If I were implement this, the first pass would require struct literal expressions to include the struct type. I might later consider whether to change that.I'm OK with this. Even in the future we'll still need this, because with templates, type inference would not be possible.Yes, I meant just coarse-grained AST categorization, not type inference. We need this to be a simple process both ease the implementation, as well as the human reader. Ideally, the user should be able to tell the difference at a glance.Tuples literals / struct initializer literals / delegates should be classified before the end of the parsing phaseThat is, you can determine whether something is a delegate literal or a struct literal (even without marking struct literals with their type) during parsing. For a moment, I misunderstood and thought you were talking about assigning types to them.Since DMD's parser is hand-written (and not generated from a grammer), I don't think it's design would be a problem. AFAIR, it uses arbitrary lookahead for a couple of things, because it is easier or faster.(which is actually at least an order of magnitude faster than the semantic phase).It wouldn't be parseable with an LL(k) parser, which is a minor thing. More to the point, depending on how DMD's parser is designed, it might be pretty awkward to parse something that might be a labeled statement or a struct variable initializer.If we can get something that's approximately as good (arguably better because it's less ambiguous, arguably worse because it's more to type) with far less work, then, given the small number of people who contribute to DMD, it would behoove us to choose the easier option.I don't think that the implementation would be a problem if we can convince Walter and Andrei. From what I've read in old bugzilla issues, they're both supportive of the idea of dedicated tuple syntax, however they wanted to hold from individual enhancements, in favour of a holistic design.
Mar 11 2016
On 2016-03-06 18:35, Seb wrote:Hey all, I wanted to relive the discussion on named arguments and ping for its current status. There is a bunch of examples to show how needed a unified solution for this problem is, let me give you one from phobos [2]. ``` // I want to allow downsizing iota(10).sliced!(Yes.replaceArrayWithPointer, Yes.allowDownsize)(4); ``` There is of course the alternative solution that an author overloads his function to the utmost, but this results in complexity and duplicated code (see e.g. redBlackTree in phobos [3]). Currently the best solution AFAICT is to use a struct to pass such flags, like ``` struct Options{int x; int y=1; int z=2;} auto fun(Options options) { return options.x + options.y + options.z; } Options options = {x: 4, z: 3}; auto a=fun(options); ``` There are also other workarounds as discussed in [1] (e.g. with CTFE string analysis [4]). I general there two solutions to this problem 1) get true named parameters support in D (probably complicated) 2) allow struct inits in functions - e.g. fun({x: 4}) For 2) Jacob Carlborg has proposed something similar three years ago. In his case he proposed anonymous structs which might be more generally applicable, however just created the struct seems easier and allows more It doesn't seem that complicated to me as the compiler already knows the type of the argument. Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now. What are your thoughts on this issue?I think the simplest solution is to allow struct member initializer in all places a struct literal is accepted [1]. [1] https://issues.dlang.org/show_bug.cgi?id=15692 -- /Jacob Carlborg
Mar 06 2016
On Sunday, 6 March 2016 at 20:35:49 UTC, Jacob Carlborg wrote:On 2016-03-06 18:35, Seb wrote:+100 This can also pave the way for tuple literals, e.g.: // nothing new, ordinary struct member init Point2 point = { x: 3, y: 4 }; // auto variables are deduced to be tuples auto plainTuple = { 10, "hi", 3.14 }; // See also DIP32 Which I don't think will cause ambiguity with delegates: auto tuple3 = { getInt() }; tuple auto tuple3 = { getInt(); }; lambda // unambiguous (disallow delegates that contain only CommaExpr): auto tuple4 = { getInt(), getString(), getDouble() };Hey all, I wanted to relive the discussion on named arguments and ping for its current status. There is a bunch of examples to show how needed a unified solution for this problem is, let me give you one from phobos [2]. ``` // I want to allow downsizing iota(10).sliced!(Yes.replaceArrayWithPointer, Yes.allowDownsize)(4); ``` There is of course the alternative solution that an author overloads his function to the utmost, but this results in complexity and duplicated code (see e.g. redBlackTree in phobos [3]). Currently the best solution AFAICT is to use a struct to pass such flags, like ``` struct Options{int x; int y=1; int z=2;} auto fun(Options options) { return options.x + options.y + options.z; } Options options = {x: 4, z: 3}; auto a=fun(options); ``` There are also other workarounds as discussed in [1] (e.g. with CTFE string analysis [4]). I general there two solutions to this problem 1) get true named parameters support in D (probably complicated) 2) allow struct inits in functions - e.g. fun({x: 4}) For 2) Jacob Carlborg has proposed something similar three years ago. In his case he proposed anonymous structs which might be more generally applicable, however just created the struct seems easier and allows more It doesn't seem that complicated to me as the compiler already knows the type of the argument. Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now. What are your thoughts on this issue?I think the simplest solution is to allow struct member initializer in all places a struct literal is accepted [1]. [1] https://issues.dlang.org/show_bug.cgi?id=15692
Mar 07 2016
On Monday, 7 March 2016 at 10:40:15 UTC, ZombineDev wrote:Which I don't think will cause ambiguity with delegates: auto tuple3 = { getInt() }; tuple auto tuple3 = { getInt(); }; lambdaUnfortunately this will not work. There was a tuple proposal sometime back in 2012 or 2013. I can't remember the exact reason, but somebody came up with a case where it can be ambiguous as to whether it's a tuple or a delegate.
Mar 07 2016
On Monday, 7 March 2016 at 18:21:24 UTC, Meta wrote:On Monday, 7 March 2016 at 10:40:15 UTC, ZombineDev wrote:I believe it was the empty tuple, which is indistinguishable from a do-nothing lambda. pragma(msg, typeof({})); // prints: // void function() pure nothrow nogc safe Nothing that can't be solved, I'd say. Just define `{}` to mean one of them and provide a workaround for the other one. OTOH, distinguishing between tuples and lambdas requires unlimited lookahead and backtracking, which can become expensive for pathological cases.Which I don't think will cause ambiguity with delegates: auto tuple3 = { getInt() }; tuple auto tuple3 = { getInt(); }; lambdaUnfortunately this will not work. There was a tuple proposal sometime back in 2012 or 2013. I can't remember the exact reason, but somebody came up with a case where it can be ambiguous as to whether it's a tuple or a delegate.
Mar 08 2016
On Monday, 7 March 2016 at 18:21:24 UTC, Meta wrote:On Monday, 7 March 2016 at 10:40:15 UTC, ZombineDev wrote:Can you find the exact case? I'm really interested in getting proper tuple syntax support and I think that's important to cover all the possible cases before can agree on something and move towards implementing it.Which I don't think will cause ambiguity with delegates: auto tuple3 = { getInt() }; tuple auto tuple3 = { getInt(); }; lambdaUnfortunately this will not work. There was a tuple proposal sometime back in 2012 or 2013. I can't remember the exact reason, but somebody came up with a case where it can be ambiguous as to whether it's a tuple or a delegate.
Mar 10 2016
On Thursday, 10 March 2016 at 19:36:05 UTC, ZombineDev wrote:On Monday, 7 March 2016 at 18:21:24 UTC, Meta wrote:Here's the thread where it's pointed out: http://forum.dlang.org/post/mailman.372.1364547485.4724.digitalmars-d puremagic.com And here's Kenji's DIP: http://wiki.dlang.org/DIP32On Monday, 7 March 2016 at 10:40:15 UTC, ZombineDev wrote:Can you find the exact case? I'm really interested in getting proper tuple syntax support and I think that's important to cover all the possible cases before can agree on something and move towards implementing it.Which I don't think will cause ambiguity with delegates: auto tuple3 = { getInt() }; tuple auto tuple3 = { getInt(); }; lambdaUnfortunately this will not work. There was a tuple proposal sometime back in 2012 or 2013. I can't remember the exact reason, but somebody came up with a case where it can be ambiguous as to whether it's a tuple or a delegate.
Mar 11 2016
On Friday, 11 March 2016 at 13:26:49 UTC, Meta wrote:On Thursday, 10 March 2016 at 19:36:05 UTC, ZombineDev wrote:Aside from the empty tuple, I can only find Timon's comment: http://forum.dlang.org/post/kj44fs$2iil$1 digitalmars.comOn Monday, 7 March 2016 at 18:21:24 UTC, Meta wrote:Here's the thread where it's pointed out: http://forum.dlang.org/post/mailman.372.1364547485.4724.digitalmars-d puremagic.comUnfortunately this will not work. There was a tuple proposal sometime back in 2012 or 2013. I can't remember the exact reason, but somebody came up with a case where it can be ambiguous as to whether it's a tuple or a delegate.Can you find the exact case? I'm really interested in getting proper tuple syntax support and I think that's important to cover all the possible cases before can agree on something and move towards implementing it.0 "Inside tuple literal, ; never appears." {{;}} // a tuple not matching your specification {{if(foo()){}}} // a non-tuple matching your specificationThis is not a serious problem, because it just means that the DIP needs to be rephrased. There is no actual ambiguity.And here's Kenji's DIP: http://wiki.dlang.org/DIP32
Mar 11 2016
On Fri, 11 Mar 2016 14:29:39 +0000, Marc Schütz wrote:{{if(foo()){}}} looks like a tuple containing a delegate or a delegate containing a BlockStatement. {} looks like an empty tuple and an empty void delegate(). The proposal resolves the ambiguity by fiat: ambiguous things are classified as tuples. This is a breaking change and should have been called out in the proposal.0 "Inside tuple literal, ; never appears." {{;}} // a tuple not matching your specification {{if(foo()){}}} // a non-tuple matching your specificationThis is not a serious problem, because it just means that the DIP needs to be rephrased. There is no actual ambiguity.
Mar 11 2016
On Friday, 11 March 2016 at 13:26:49 UTC, Meta wrote:On Thursday, 10 March 2016 at 19:36:05 UTC, ZombineDev wrote:Thanks, I had read the DIP, but couldn't find the forum discussion. I added the link to the wiki page.On Monday, 7 March 2016 at 18:21:24 UTC, Meta wrote:Here's the thread where it's pointed out: http://forum.dlang.org/post/mailman.372.1364547485.4724.digitalmars-d puremagic.com And here's Kenji's DIP: http://wiki.dlang.org/DIP32[...]Can you find the exact case? I'm really interested in getting proper tuple syntax support and I think that's important to cover all the possible cases before can agree on something and move towards implementing it.
Mar 11 2016
On Sunday, 6 March 2016 at 17:35:38 UTC, Seb wrote:Hey all, I wanted to relive the discussion on named arguments and ping for its current status. There is a bunch of examples to show how needed a unified solution for this problem is, let me give you one from phobos [2]. ``` // I want to allow downsizing iota(10).sliced!(Yes.replaceArrayWithPointer, Yes.allowDownsize)(4); ``` There is of course the alternative solution that an author overloads his function to the utmost, but this results in complexity and duplicated code (see e.g. redBlackTree in phobos [3]). Currently the best solution AFAICT is to use a struct to pass such flags, like ``` struct Options{int x; int y=1; int z=2;} auto fun(Options options) { return options.x + options.y + options.z; } Options options = {x: 4, z: 3}; auto a=fun(options); ``` There are also other workarounds as discussed in [1] (e.g. with CTFE string analysis [4]). I general there two solutions to this problem 1) get true named parameters support in D (probably complicated) 2) allow struct inits in functions - e.g. fun({x: 4}) For 2) Jacob Carlborg has proposed something similar three years ago. In his case he proposed anonymous structs which might be more generally applicable, however just created the struct seems easier and allows more It doesn't seem that complicated to me as the compiler already knows the type of the argument. Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now. What are your thoughts on this issue? On a side note: many templated functions are also complicated and experiencing this issue, so it also might be worth to think about this issue too ;-) Cheers,What about this idea? A new word "as" or something similar. You have defined: int fun(int x=100, int y=100, int r=100){...} int xpos=100; int ypos=100; int radius=50; Now you are allowed to call: fun(xpos,ypos,radius); // normal nothing has changed! Call with "as": fun(ypos as y, xpos as x, radius as r); // different order! or fun(radius as r); // defaults values are used. <=> fun(,,radius); The compiler is looking for the right mapping?
Mar 08 2016
On Tue, 08 Mar 2016 13:52:09 +0000, Martin Tschierschke wrote:What about this idea? A new word "as" or something similar. fun(ypos as y, xpos as x, radius as r); // different order!The syntax isn't an issue. There was one DIP about named parameters, but it was unpopular. It didn't change *anything* about overload resolution; it only had the compiler check that you provided arguments in the correct order, even if they were all of the same type. Even if there were a DIP everyone liked, nobody is signing up to implement it. DDMD is a little scary and not reflective of good design in D (having been translated by machine from C++). I might take a look, but I probably won't have the time to produce anything useful.
Mar 08 2016
On Tuesday, 8 March 2016 at 18:46:02 UTC, Chris Wright wrote:On Tue, 08 Mar 2016 13:52:09 +0000, Martin Tschierschke wrote:I have seen the "DIP about named parameters", and i liked the idea of getting a easier to read code, because it gets more verbose. My idea with the "val as x" was to avoid the need to define the functions in a different way. But as Idan Arye pointed out, it seems to be more difficult: "As far as I understand, the main two problems with named arguments are overloading ambiguity and the fact that argument names are not part of the signature." An other point on my wish list would be to allow string symbol notation like in ruby. Than using hashes (AA) for parameters gets more convenient: :symbol <= just short for => "symbol" h[:y]= 50; h[:x] = 100; // <=> h["y"] = 50; h["x"] = 100 For calling a function: auto params = [:y : 50, :x : 100] <=> auto params = ["y" : 50 , "x" : 100] Especially when the code is nested in a string for mixin purpose. (vibe.d templates). But maybe this crashes, because of the ambiguity if no space after a ":" is used in this place: auto hash = [ 1 :variable] meaning: auto hash = [ 1 : variable ] not auto hash = [1 "variable" ] which would make no sense either.What about this idea? A new word "as" or something similar. fun(ypos as y, xpos as x, radius as r); // different order!The syntax isn't an issue. There was one DIP about named parameters, but it was unpopular. It didn't change *anything* about overload resolution; it only had the compiler check that you provided arguments in the correct order, even if they were all of the same type. Even if there were a DIP everyone liked, nobody is signing up to implement it. DDMD is a little scary and not reflective of good design in D (having been translated by machine from C++). I might take a look, but I probably won't have the time to produce anything useful.
Mar 09 2016
On Wednesday, 9 March 2016 at 10:06:25 UTC, Martin Tschierschke wrote:On Tuesday, 8 March 2016 at 18:46:02 UTC, Chris Wright wrote:String symbols are Ruby's(and many Lisps', and maybe some other, less popular languages) way to do untyped enums and untyped structs. It's a dynamically typed languages thing and has no room in statically typed languages like D. D mimics dynamic typing to some extent by creating types on the fly with it's powerful templates mechanism - but a new type still needs to be created. D is geared toward reflection on types at compile time, not towards type detection at run-time... Allowing something like `auto params = [:y : 50, :x : 100]` won't really solve anything. It works nicely in Ruby, because Ruby has dynamic typing and with some syntactic sugar you get elegant syntax for dynamic structs. But in a structured language like D, you run into the problem that `[:y : 50, :x : 100] is an associative array with a determined type for it's values, so you can't do things like `[:y : 50, :x : "hello"]` - which greatly limits the usability of this syntax.On Tue, 08 Mar 2016 13:52:09 +0000, Martin Tschierschke wrote:I have seen the "DIP about named parameters", and i liked the idea of getting a easier to read code, because it gets more verbose. My idea with the "val as x" was to avoid the need to define the functions in a different way. But as Idan Arye pointed out, it seems to be more difficult: "As far as I understand, the main two problems with named arguments are overloading ambiguity and the fact that argument names are not part of the signature." An other point on my wish list would be to allow string symbol notation like in ruby. Than using hashes (AA) for parameters gets more convenient: :symbol <= just short for => "symbol" h[:y]= 50; h[:x] = 100; // <=> h["y"] = 50; h["x"] = 100 For calling a function: auto params = [:y : 50, :x : 100] <=> auto params = ["y" : 50 , "x" : 100] Especially when the code is nested in a string for mixin purpose. (vibe.d templates). But maybe this crashes, because of the ambiguity if no space after a ":" is used in this place: auto hash = [ 1 :variable] meaning: auto hash = [ 1 : variable ] not auto hash = [1 "variable" ] which would make no sense either.What about this idea? A new word "as" or something similar. fun(ypos as y, xpos as x, radius as r); // different order!The syntax isn't an issue. There was one DIP about named parameters, but it was unpopular. It didn't change *anything* about overload resolution; it only had the compiler check that you provided arguments in the correct order, even if they were all of the same type. Even if there were a DIP everyone liked, nobody is signing up to implement it. DDMD is a little scary and not reflective of good design in D (having been translated by machine from C++). I might take a look, but I probably won't have the time to produce anything useful.
Mar 09 2016
On Wednesday, 9 March 2016 at 12:55:16 UTC, Idan Arye wrote: [...]An other point on my wish list would be to allow string symbol notation like in ruby. Than using hashes (AA) for parameters gets more convenient: :symbol <= just short for => "symbol" h[:y]= 50; h[:x] = 100; // <=> h["y"] = 50; h["x"] = 100String symbols are Ruby's(and many Lisps', and maybe some other, less popular languages) way to do untyped enums and untyped structs. It's a dynamically typed languages thing and has no room in statically typed languages like D. D mimics dynamic typing to some extent by creating types on the fly with it's powerful templates mechanism - but a new type still needs to be created. D is geared toward reflection on types at compile time, not towards type detection at run-time...Thats true.Allowing something like `auto params = [:y : 50, :x : 100]` won't really solve anything. It works nicely in Ruby, because Ruby has dynamic typing and with some syntactic sugar you get elegant syntax for dynamic structs. But in a structured language like D, you run into the problem that `[:y : 50, :x : 100] is an associative array with a determined type for it's values, so you can't do things like `[:y : 50, :x : "hello"]` - which greatly limits the usability of this syntax.Yes.Ok. What I like about the :symbol notation is, that a string witch is used only to distinguish between different objects in an Hash / AA has a complete different purpose than a string used to be displayed for the user. I think that writeln("Name", a[:name]); is easier to read, than writeln("Name", a["name"]); especially if the structures are getting bigger, or you are in a vibe.d jade template string where you would have to use additional quoting to write: a(href="a[\"url\"]") a["link_text"] a(href="a[:url]") a[:link_text] May be I should get rid of this by using a struct for my mysql results to display? (=> a.url and a.link_text ) Just my 2 Cents :-)
Mar 09 2016
On Wednesday, 9 March 2016 at 13:39:57 UTC, Martin Tschierschke wrote:On Wednesday, 9 March 2016 at 12:55:16 UTC, Idan Arye wrote: [...]If nested strings is what's bothering you, you can always use backticks. Or opDispatch(though I don't recommend it, as it tends to screw up compilation errors). But these won't let you have fields with different types, and since Voldemort types are so easy in D you are probably better off with structs.[...][...]Thats true.[...]Yes.Ok. What I like about the :symbol notation is, that a string witch is used only to distinguish between different objects in an Hash / AA has a complete different purpose than a string used to be displayed for the user. I think that writeln("Name", a[:name]); is easier to read, than writeln("Name", a["name"]); especially if the structures are getting bigger, or you are in a vibe.d jade template string where you would have to use additional quoting to write: a(href="a[\"url\"]") a["link_text"] a(href="a[:url]") a[:link_text] May be I should get rid of this by using a struct for my mysql results to display? (=> a.url and a.link_text ) Just my 2 Cents :-)
Mar 09 2016
On Wednesday, 9 March 2016 at 12:55:16 UTC, Idan Arye wrote:Allowing something like `auto params = [:y : 50, :x : 100]` won't really solve anything. It works nicely in Ruby, because Ruby has dynamic typing and with some syntactic sugar you get elegant syntax for dynamic structs. But in a structured language like D, you run into the problem that `[:y : 50, :x : 100] is an associative array with a determined type for it's values, so you can't do things like `[:y : 50, :x : "hello"]` - which greatly limits the usability of this syntax.I posted (in a previous thread about this issue) a library solution to this: import std.typecons, std.meta; private struct Named(string n, T) { enum name = n; T value; } template NamedToAS(N...) { static if (N.length == 0) { alias NamedToAS = AliasSeq!(); } else { alias NamedToAS = AliasSeq!(typeof(N[0].init.value), N[0].name, NamedToAS!(N[1 .. $])); } } struct Tup { static auto opDollar(size_t i)() { return immutable KeyWordDollar(); } static auto opIndex(NamedArgs...)(NamedArgs nas) { Tuple!(NamedToAS!NamedArgs) tup; foreach(i, ref na ; tup) { na = nas[i].value; } return tup; } } void overrideFrom(TupDef, TupOver)(ref TupDef defaultMap, ref TupOver overrideMap) { foreach(i, ref field ; overrideMap) { __traits(getMember, defaultMap, TupOver.fieldNames[i]) = field; } } auto println(KWA)(KWA kwa) { auto args = Tup[$.str = "abc", $.repeat = 2, $.sep = " "]; args.overrideFrom(kwa); import std.stdio; bool first = true; foreach(i ; 0 .. args.repeat) { if (first) first = false; else write(args.sep); write(args.str); } writeln(); } unittest { println(Tup[$.str = "xyz", $.repeat = 8]); }
Mar 09 2016
On Thursday, 10 March 2016 at 05:17:03 UTC, Michael Coulombe wrote:[...]Whoops, forgot this: private immutable struct KeyWordDollar { property auto opDispatch(string param, T)(T t) { return Named!(param,T)(t); } }
Mar 09 2016
hi, has the UDA syntax been proposed already? void fun(int foo, int bar, int bazDaz = 0){} fun(10, 30, 50); // normal fun(10, 30); normal with default fun(10, 30, bazDaz 50); // mixed fun( bazDaz 50, 10, 30) // mixed and reordered fun( bar 30, 10); // mixed, reordered and default fun( foo 10, bar 30, bazDaz 50); // named fun( bar 30, bazDaz 50, foo 10); // named and reordered foo int a = 10; bar int b = 30; bazDaz int c = 50; fun(c, a, b); // hm allowed or not? but if built in tuples could be used to do named args then it might be better to have those.
Mar 08 2016
On Sunday, 6 March 2016 at 17:35:38 UTC, Seb wrote:Hey all, I wanted to relive the discussion on named arguments and ping for its current status. There is a bunch of examples to show how needed a unified solution for this problem is, let me give you one from phobos [2]. ``` // I want to allow downsizing iota(10).sliced!(Yes.replaceArrayWithPointer, Yes.allowDownsize)(4); ``` There is of course the alternative solution that an author overloads his function to the utmost, but this results in complexity and duplicated code (see e.g. redBlackTree in phobos [3]). Currently the best solution AFAICT is to use a struct to pass such flags, like ``` struct Options{int x; int y=1; int z=2;} auto fun(Options options) { return options.x + options.y + options.z; } Options options = {x: 4, z: 3}; auto a=fun(options); ``` There are also other workarounds as discussed in [1] (e.g. with CTFE string analysis [4]). I general there two solutions to this problem 1) get true named parameters support in D (probably complicated) 2) allow struct inits in functions - e.g. fun({x: 4}) For 2) Jacob Carlborg has proposed something similar three years ago. In his case he proposed anonymous structs which might be more generally applicable, however just created the struct seems easier and allows more It doesn't seem that complicated to me as the compiler already knows the type of the argument. Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now. What are your thoughts on this issue? On a side note: many templated functions are also complicated and experiencing this issue, so it also might be worth to think about this issue too ;-) Cheers, Seb [1] http://forum.dlang.org/post/pxndhoskpjxvnoacajaz forum.dlang.org [2] https://github.com/DlangScience/mir/issues/18 [3] https://github.com/D-Programming-Language/phobos/pull/4041/files [4] https://github.com/timotheecour/dtools/blob/master/dtools/util/functional.dAs far as I understand, the main two problems with named arguments are overloading ambiguity and the fact that argument names are not part of the signature. Using a struct to define the named arguments solves the signature problem, but the ambiguity problem remains - it simply gets shifted from "which overload to choose" to "which struct to choose". The consensus here seems to be that ambiguous code should be result in compilation errors(and that it should be easy for the compiler to detect that the code is ambiguous!), and that if structs are used to declare named arguments, then solving overloading ambiguities should be done by constructing the struct explicitly. Then everyone disagree regarding how structs should be created explicitly with named fields. I would like to suggest an idea that will allow solving ambiguities without the need for new syntax(behind the syntax for declaring and using named arguments), be consistent with existing D features, and as a bonus provide a much nicer syntax: Make it like variadic functions! Declaring the named arguments variadically will be done by adding `...` after a struct argument: struct Options{int x; int y=1; int z=2;} auto fun(Options options ...) We'll need a syntax for specifying the arguments - but that's more of a matter of taste than an actual technical problem, and it's going to be bikeshedded over and over, so for the purpose of describing my idea let's pick a Ruby-style `:`(because `=` will break the rule of if-it-compiles-as-C-it-should-work-like-C): fun(x: 4, z: 3); I've promised you to solve ambiguity, right? Well, just like regular variadic functions can be called with an explicit array, named arguments variadic functions should also be callable with an explicit struct: Options options = {x: 4, z: 3}; fun(options); Which brings us back to square one, right? Wrong! Because at this point, it should be trivial to give structs a second default constructor: this(typeof(this) that ...) { this = that; } (actual implementation may be more efficient and robust(preferably a syntactic sugar for postblit), but you get the idea). So now structs can be constructed with named arguments, and ambiguities could be neatly solved with: fun(Options(x: 4, z: 3)); P.S: If a struct-based solution is ever implemented for named arguments, I do hope it'll support template inference, where a simple PODS(Plain Old D Struct... sorry...) is automatically created based on the supplied arguments' names and types(and order!). UDA support for that could be nice too...
Mar 08 2016
On Tuesday, 8 March 2016 at 20:32:02 UTC, Idan Arye wrote:Declaring the named arguments variadically will be done by adding `...` after a struct argument: struct Options{int x; int y=1; int z=2;} auto fun(Options options ...) We'll need a syntax for specifying the arguments - but that's more of a matter of taste than an actual technical problem, and it's going to be bikeshedded over and over, so for the purpose of describing my idea let's pick a Ruby-style `:`(because `=` will break the rule of if-it-compiles-as-C-it-should-work-like-C): fun(x: 4, z: 3); I've promised you to solve ambiguity, right?--snip-- I'm not sure, but I think the problem Walter has lies with _detecting_ ambiguity in the first place, because that would make overload resolution more complicated. I personally don't think it's that big a problem, because selecting the candidates could be a step before actual (= as it is now) overload resolution.
Mar 10 2016
On Sunday, 6 March 2016 at 17:35:38 UTC, Seb wrote:Hey all, Using structs is not ideal, because one can't require parameters, but this can be solved by having those parameters as normal ones like `sliced(4, {allowDownsize: true})` and it creates some maybe unnecessary overhead. However it is probably the easiest solution right now.In ggplotd I often use named tuples as and "anonymoous" struct: Tuple!(double,"x")( 0.0 ) I also added a merge function that will return a tuple containing merged named tuples: Tuple!(double,"x",string,"colour")(-1, "black").merge(Tuple!(double,"x")(0.0)) returns: Tuple!(double,"x",string,"colour")(0, "black"); As an aside the merge function also works with structs so you can do the following: struct Point { double x; double y; } Tuple!(double,"x",string,"colour")(-1, "black").merge(Point(1,2)) returns: Tuple!(double,"x",double,"y",string,"colour")(1, 2, "black"); It works reasonably well, except that the tuples require a lot of typing.
Mar 08 2016
On Wednesday, 9 March 2016 at 07:30:31 UTC, Edwin van Leeuwen wrote:I also added a merge function that will return a tuple containing merged named tuples: Tuple!(double,"x",string,"colour")(-1, "black").merge(Tuple!(double,"x")(0.0)) returns: Tuple!(double,"x",string,"colour")(0, "black");Quick clarification. The merge function is used to merge the passed tuple, with the default values needed in the function. This way we don't have to worry about missing values.
Mar 08 2016
On Wednesday, 9 March 2016 at 07:30:31 UTC, Edwin van Leeuwen wrote:On Sunday, 6 March 2016 at 17:35:38 UTC, Seb wrote:slightly tangentially, you might be interested in this: https://github.com/D-Programming-Language/phobos/pull/4043[...]In ggplotd I often use named tuples as and "anonymoous" struct: Tuple!(double,"x")( 0.0 ) I also added a merge function that will return a tuple containing merged named tuples: Tuple!(double,"x",string,"colour")(-1, "black").merge(Tuple!(double,"x")(0.0)) returns: Tuple!(double,"x",string,"colour")(0, "black"); As an aside the merge function also works with structs so you can do the following: struct Point { double x; double y; } Tuple!(double,"x",string,"colour")(-1, "black").merge(Point(1,2)) returns: Tuple!(double,"x",double,"y",string,"colour")(1, 2, "black"); It works reasonably well, except that the tuples require a lot of typing.
Mar 09 2016