digitalmars.D - named arguments (C++) - Something D could learn from
- bauss (11/11) Dec 14 2018 In C++ you can achieve named arguments using templates and
- JN (4/8) Dec 14 2018 Even if a DIP would happen, people would just say it's
- Steven Schveighoffer (15/25) Dec 14 2018 Bleh, C++ is so ugly. I can't see how D can't do better.
- Dukc (5/9) Dec 14 2018 Hope if far from lost here. There is not one, but two DIPs in
- rikki cattermole (8/19) Dec 14 2018 Disclaimer the second DIP is mine.
- John Chapman (4/13) Dec 14 2018 If anyone wants to play with an implementation, I've updated
- Neia Neutuladh (46/61) Dec 14 2018 The only vaguely interesting thing in that example is selecting an item
- NX (3/5) Dec 15 2018 Check this out:
- Neia Neutuladh (4/11) Dec 15 2018 Nice! I think I saw this before and forgot about it.
- Jacob Carlborg (32/47) Dec 16 2018 Here's a simple version in D that doesn't require to declare a variable
- Matthew OConnor (5/16) Dec 16 2018 I am a C++ developer by day and reading that article made me
- Ethan (7/11) Dec 17 2018 Sweet zombie Jesus I just read the article and wow I can't
- Atila Neves (2/14) Dec 18 2018 At least the static variables are const...
- JN (5/9) Dec 17 2018 Well that's the problem. If it was implemented as a language
- Atila Neves (10/21) Dec 18 2018 IMHO, there's no point, just wrap every parameter in a struct. Is
- JN (6/15) Dec 18 2018 Well, but then you have to create structs for everything you want
- aliak (20/42) Dec 18 2018 You also have to build it:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (28/50) Dec 18 2018 No need to pollute the namespace:
- aliak (9/64) Dec 18 2018 Woah... that's quite neat.
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (31/38) Dec 19 2018 Thanks, but it has some serious drawbacks - like this:
- Kagamin (2/7) Dec 19 2018 https://blog.jetbrains.com/dotnet/2018/11/27/inline-parameter-name-hints...
- JN (8/9) Dec 19 2018 I think there are two usecases that are kind of getting mixed
- Neia Neutuladh (5/17) Dec 19 2018 D has optional arguments already, but the thing that reorderable named
In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/ I assume this is not possible to port to D because D doesn't do operator overload in the same way C++ does, correct? I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.
Dec 14 2018
On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.Even if a DIP would happen, people would just say it's unnecessary/bloat/can be done as a library function through some ugly mixin :/
Dec 14 2018
On 12/14/18 3:13 PM, bauss wrote:In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/ I assume this is not possible to port to D because D doesn't do operator overload in the same way C++ does, correct?Bleh, C++ is so ugly. I can't see how D can't do better. operator overloading works fine in D, just like it does in the given example. What C++ allows is: 1. operator overloading of arbitrary operators. D has certain requirements for certain operators. 2. extracting the operator overloading to a module-level function. D requires operator overloading inside a type. But neither of those problems are in play here. You could practically port the solution exactly to D. HOWEVER, I don't think the mechanics make this solution worthwhile. Carrying around extra structs and wrapping things in this complicated way doesn't seem very attractive to me. -Steve
Dec 14 2018
On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.Hope if far from lost here. There is not one, but two DIPs in draft stage to add named function parameters to D: https://github.com/dlang/DIPs/pull/123 https://github.com/dlang/DIPs/pull/126
Dec 14 2018
On 15/12/2018 10:22 AM, Dukc wrote:On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:Disclaimer the second DIP is mine. The first is mostly concerned with syntax sugar. The second is about modelling externally setting internal (but private) attributes that are visible publicly. They both have their own pluses and minuses, but IMO the second is much harder to implement as a library. In fact we already do, see ElementType for input ranges. We can do better at modelling this.I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.Hope if far from lost here. There is not one, but two DIPs in draft stage to add named function parameters to D: https://github.com/dlang/DIPs/pull/123 https://github.com/dlang/DIPs/pull/126
Dec 14 2018
On Friday, 14 December 2018 at 21:22:38 UTC, Dukc wrote:On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:If anyone wants to play with an implementation, I've updated Jacob Carlborg's old work here: https://github.com/jsatellite/dmd/tree/named-argumentsI still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.Hope if far from lost here. There is not one, but two DIPs in draft stage to add named function parameters to D: https://github.com/dlang/DIPs/pull/123 https://github.com/dlang/DIPs/pull/126
Dec 14 2018
On Fri, 14 Dec 2018 20:13:42 +0000, bauss wrote:In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/ I assume this is not possible to port to D because D doesn't do operator overload in the same way C++ does, correct? I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.The only vaguely interesting thing in that example is selecting an item based on its compile-time type, and that's easy. In addition to what the FluentCpp post supports, we'd like to add default value handling, and we'd like to automatically generate the forwarding function. I hacked this up: https://git.ikeran.org/dhasenan/snippets/src/branch/master/namedargs/ forwarding.d And you use it like: --- writeln(dispatch!greet(Count(3), Name("Aerith"))); --- Issues: * You have to write a bunch of extra structs. Namespace pollution ahoy. Code that looks right but isn't because both module A and module B define a `Name` parameter struct. You can probably reduce that a bit with std.typecons.Typedef. * This ignores superfluous arguments. That's left as an exercise to the reader. * Documentation. You can document the non-dispatch version of things and suggest that users use the dispatch wrapper, or you can document an alias around dispatch!fun and have no documentation for what parameters the function has. * Overloads. It is difficult to refer to a specific overload from a set, and if you want to provide aliases for the dispatch function, it is difficult to expose all of them. (On the other hand, with optional, reorderable, named arguments, you can much more easily pack things into the same function, assuming they're all supposed to do roughly the same thing, which is good design.) * Ref and out parameters. You can probably support them, but it would be kind of hard. Another strategy is to automatically generate a struct for each function, then use the struct initialization syntax to create the value and call a method on it to invoke the function. It would work like: --- Invoker!greet f = { name: "Rydia", count: 1 }; writeln(f()); --- And that has its own issues: you have to declare a new variable each time, it's easy to call the function multiple times, and ref and out parameters are much more awkward. You can at least tell whether a parameter was provided or not using std.typecons.Nullable or the like.
Dec 14 2018
On Friday, 14 December 2018 at 23:10:35 UTC, Neia Neutuladh wrote:I hacked this up: https://git.ikeran.org/dhasenan/snippets/src/branch/master/namedargs/forwarding.dCheck this out: https://github.com/CyberShadow/ae/blob/master/utils/meta/args.d
Dec 15 2018
On Sat, 15 Dec 2018 15:59:48 +0000, NX wrote:On Friday, 14 December 2018 at 23:10:35 UTC, Neia Neutuladh wrote:forwarding.dI hacked this up: https://git.ikeran.org/dhasenan/snippets/src/branch/master/namedargs/Check this out: https://github.com/CyberShadow/ae/blob/master/utils/meta/args.dNice! I think I saw this before and forgot about it. I'll still probably never use it, but oh well.
Dec 15 2018
On 2018-12-14 21:13, bauss wrote:In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/ I assume this is not possible to port to D because D doesn't do operator overload in the same way C++ does, correct? I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.Here's a simple version in D that doesn't require to declare a variable for each name, does not support reordering names: void foo(int a) { writeln(a); } void bar(NamedArgument!("b", int) b) { writeln(b); } struct NamedArgument(string name, T) { T value; alias value this; } struct NamedArgumentProxy { auto opDispatch(string name, T)(T value) const { return NamedArgument!(name, T)(value); } } immutable NamedArgumentProxy na; void main() { foo(na.a = 3); // the name "a" here doesn't matter, it can be anything foo(na.b = 4); // this has to be "b", otherwise it won't compile } https://run.dlang.io/is/zgejqi -- /Jacob Carlborg
Dec 16 2018
On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/ I assume this is not possible to port to D because D doesn't do operator overload in the same way C++ does, correct? I still think named arguments should be something to consider implementing for D, but since everything requires a DIP and it's very hard to write a DIP that's proper for such a thing then I guess it'll just be a dream, forever.I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.
Dec 16 2018
On Sunday, 16 December 2018 at 22:16:28 UTC, Matthew OConnor wrote:I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.Sweet zombie Jesus I just read the article and wow I can't believe that was written _this week_. Named arguments by defining non-thread-safe statics? People write this tripe in 2018? And get _good comments_ on it? Something has gone very wrong in compsci education.
Dec 17 2018
On Monday, 17 December 2018 at 19:24:06 UTC, Ethan wrote:On Sunday, 16 December 2018 at 22:16:28 UTC, Matthew OConnor wrote:At least the static variables are const...I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.Sweet zombie Jesus I just read the article and wow I can't believe that was written _this week_. Named arguments by defining non-thread-safe statics? People write this tripe in 2018? And get _good comments_ on it? Something has gone very wrong in compsci education.
Dec 18 2018
On Sunday, 16 December 2018 at 22:16:28 UTC, Matthew OConnor wrote:I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.Well that's the problem. If it was implemented as a language feature it'd be a clean solution with nice syntax. But trying to force it with templates will always look ugly.
Dec 17 2018
On Monday, 17 December 2018 at 21:11:03 UTC, JN wrote:On Sunday, 16 December 2018 at 22:16:28 UTC, Matthew OConnor wrote:IMHO, there's no point, just wrap every parameter in a struct. Is there really that much of a difference between: displayCoolName(firstName = "James", lastName = "Bond") and displayCoolName(FirstName("James"), LastName("Bond")) ? It's not even fewer characters! It's not trivial but it's possible to make the order not matter by using a templated implementation and aliasing it to `displayCoolName`.I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.Well that's the problem. If it was implemented as a language feature it'd be a clean solution with nice syntax. But trying to force it with templates will always look ugly.
Dec 18 2018
On Tuesday, 18 December 2018 at 10:44:28 UTC, Atila Neves wrote:IMHO, there's no point, just wrap every parameter in a struct. Is there really that much of a difference between: displayCoolName(firstName = "James", lastName = "Bond") and displayCoolName(FirstName("James"), LastName("Bond")) ? It's not even fewer characters! It's not trivial but it's possible to make the order not matter by using a templated implementation and aliasing it to `displayCoolName`.Well, but then you have to create structs for everything you want to pass to the method. And you have to explicitly define which have to mark arguments as named or anything like that, you just pass the names at the call site.
Dec 18 2018
On Tuesday, 18 December 2018 at 10:44:28 UTC, Atila Neves wrote:On Monday, 17 December 2018 at 21:11:03 UTC, JN wrote:You also have to build it: func toHex(r: Int, g: Int, b: Int) -> Int { return r << g << b; } As opposed to: struct R { int value; } struct G { int value; } struct B { int value; } int toHex(R r, G g, B b) { return r.value << g.value << b.value; } That's 67 vs 146 characters. Not to mention one pollutes the namespace and one doesn't.On Sunday, 16 December 2018 at 22:16:28 UTC, Matthew OConnor wrote:IMHO, there's no point, just wrap every parameter in a struct. Is there really that much of a difference between: displayCoolName(firstName = "James", lastName = "Bond") and displayCoolName(FirstName("James"), LastName("Bond")) ? It's not even fewer characters! It's not trivial but it's possible to make the order not matter by using a templated implementation and aliasing it to `displayCoolName`.I am a C++ developer by day and reading that article made me cringe. C++ has this creeping, expansive, everything ends up in the language or writable in it, if you accept awful messages and contorting the syntax. I hope D doesn't go down that route.Well that's the problem. If it was implemented as a language feature it'd be a clean solution with nice syntax. But trying to force it with templates will always look ugly.
Dec 18 2018
On Tuesday, 18 December 2018 at 11:08:43 UTC, aliak wrote:No need to pollute the namespace: struct args { template opDispatch(string name) { alias opDispatch = Arg!name; } } struct Args(T) { template opDispatch(string name) { alias opDispatch = Arg!(name, T); } } struct Arg(string name) { static auto opAssign(T)(T value) { return Arg!(name, T)(value); } } struct Arg(string name, T) { T value; alias value this; } void fun(Args!int.foo foo) {} // Unfortunately requires repetition of arg name. :( unittest { fun(args.foo = 3); } -- SimenIt's not even fewer characters! It's not trivial but it's possible to make the order not matter by using a templated implementation and aliasing it to `displayCoolName`.You also have to build it: func toHex(r: Int, g: Int, b: Int) -> Int { return r << g << b; } As opposed to: struct R { int value; } struct G { int value; } struct B { int value; } int toHex(R r, G g, B b) { return r.value << g.value << b.value; } That's 67 vs 146 characters. Not to mention one pollutes the namespace and one doesn't.
Dec 18 2018
On Tuesday, 18 December 2018 at 11:15:26 UTC, Simen Kjærås wrote:On Tuesday, 18 December 2018 at 11:08:43 UTC, aliak wrote:Woah... that's quite neat. I feel like this is how std.typecons.Flag should have been made!! I played around with it for a bit, and if there was a way to get some better error messages then that could be quite nice to use! - i dunno, maybe through some static assert on the "string names"s being passed in or something... Cheers, - AliNo need to pollute the namespace: struct args { template opDispatch(string name) { alias opDispatch = Arg!name; } } struct Args(T) { template opDispatch(string name) { alias opDispatch = Arg!(name, T); } } struct Arg(string name) { static auto opAssign(T)(T value) { return Arg!(name, T)(value); } } struct Arg(string name, T) { T value; alias value this; } void fun(Args!int.foo foo) {} // Unfortunately requires repetition of arg name. :( unittest { fun(args.foo = 3); } -- SimenIt's not even fewer characters! It's not trivial but it's possible to make the order not matter by using a templated implementation and aliasing it to `displayCoolName`.You also have to build it: func toHex(r: Int, g: Int, b: Int) -> Int { return r << g << b; } As opposed to: struct R { int value; } struct G { int value; } struct B { int value; } int toHex(R r, G g, B b) { return r.value << g.value << b.value; } That's 67 vs 146 characters. Not to mention one pollutes the namespace and one doesn't.
Dec 18 2018
On Tuesday, 18 December 2018 at 18:23:20 UTC, aliak wrote:Woah... that's quite neat. I feel like this is how std.typecons.Flag should have been made!! I played around with it for a bit, and if there was a way to get some better error messages then that could be quite nice to use! - i dunno, maybe through some static assert on the "string names"s being passed in or something...Thanks, but it has some serious drawbacks - like this: void fun(Args!byte.foo foo) {} unittest { fun(args.foo = 3); // function foo.fun(Arg!("foo", byte) foo) is not callable using argument types (Arg!("foo", int)) } For a limited use case like std.typecons.Flag, it could work pretty well, though: struct Flag { alias opDispatch(string name) = FlagImpl!name; } template FlagImpl(string name) { // mixin to embetter type name. mixin(`struct `~name~` { bool value; alias value this; static typeof(this) opAssign(bool value) { return typeof(this)(value); } }`); mixin("alias FlagImpl = "~name~";"); } void fun(Flag.exclusive exclusive) { assert(exclusive); } unittest { fun(Flag.exclusive = true); } -- Simen
Dec 19 2018
On Friday, 14 December 2018 at 20:13:42 UTC, bauss wrote:In C++ you can achieve named arguments using templates and operator overload: It's sad that D is still against having named arguments, but it's possible in something that D thrives to be better than. https://www.fluentcpp.com/2018/12/14/named-arguments-cpp/https://blog.jetbrains.com/dotnet/2018/11/27/inline-parameter-name-hints-c-vb- et-resharper-rider/ resharper 2018 just overlays parameter names right in editor window.
Dec 19 2018
On Wednesday, 19 December 2018 at 13:30:57 UTC, Kagamin wrote:https://blog.jetbrains.com/dotnet/2018/11/27/inline-parameter-name-hints-c-vb- et-resharper-rider/ resharper 2018 just overlays parameter names right in editor window.I think there are two usecases that are kind of getting mixed here, correct me if I'm wrong. Named/keyword arguments provide two benefits: 1) you know what the arguments mean at the call place 2) you can make optional arguments without making multiple function overloads or using something like the Builder pattern This fixes 1) but doesn't fix 2)
Dec 19 2018
On Wed, 19 Dec 2018 15:07:48 +0000, JN wrote:On Wednesday, 19 December 2018 at 13:30:57 UTC, Kagamin wrote:hints-c-vb-net-resharper-rider/https://blog.jetbrains.com/dotnet/2018/11/27/inline-parameter-name-D has optional arguments already, but the thing that reorderable named arguments can easily get you is not having to specify optional arguments 0 through n-1 just to specify optional argument n.resharper 2018 just overlays parameter names right in editor window.I think there are two usecases that are kind of getting mixed here, correct me if I'm wrong. Named/keyword arguments provide two benefits: 1) you know what the arguments mean at the call place 2) you can make optional arguments without making multiple function overloads or using something like the Builder pattern This fixes 1) but doesn't fix 2)
Dec 19 2018