digitalmars.D - Tuple enhancement
- Andrei Alexandrescu (16/16) Oct 16 2016 I was thinking it would be handy if tuples had a way to access a field
- Dmitry Olshansky (3/19) Oct 16 2016 I swear I've seen a pull request merged that adds an accessible "names"
- Andrei Alexandrescu (3/12) Oct 16 2016 Sadly it was closed, not merged. And it was a bit more general allowing
- Jack Stouffer (6/8) Oct 17 2016 The PR in question if anyone is interested:
- Sebastiaan Koppe (8/13) Oct 16 2016 That would mean that tuple then needs to keep the strings around
- Chris Wright (6/23) Oct 16 2016 It's a little bit of runtime reflection, which people sometimes find
- Temtaime (2/26) Oct 16 2016 Please, not. We already have great compile time reflection.
- Sebastiaan Koppe (6/14) Oct 17 2016 Sure, but it still takes up space in the executable. Negligible
- Kapps (18/32) Oct 16 2016 I don't think this would actually require storing any additional
- sarn (8/26) Oct 16 2016 Personally, if I wanted this, I'd be using a hash table with
- Steven Schveighoffer (21/36) Oct 17 2016 Why not something like this:
- Edwin van Leeuwen (5/20) Oct 17 2016 I like the general solution, although I probably would just
- Steven Schveighoffer (7/27) Oct 17 2016 Hm... this could work:
- Bienlein (18/22) Oct 18 2016 In Scala you can do this:
- Idan Arye (28/46) Oct 18 2016 When I need to choose at runtime a value out of multiple choices
I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14); The get method takes the field name and the type of the presumed field, and it returns the value of the field in the tuple. If no field by that name and type, return the second argument. Rquirements: * Do not throw - allow the second argument to be a throwing delegate * Do not add overhead if the method is never used * Figure out a reasonable (but not all too complicated) way to deal with implicit conversions, e.g. if x == "a" in the the code above, should it return 3.14 or convert the int to double? * Handle qualifiers appropriately Andrei
Oct 16 2016
On 10/16/16 3:58 PM, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);I swear I've seen a pull request merged that adds an accessible "names" AliasSeq with names of fields. That should be a good starting point.The get method takes the field name and the type of the presumed field, and it returns the value of the field in the tuple. If no field by that name and type, return the second argument. Rquirements: * Do not throw - allow the second argument to be a throwing delegate * Do not add overhead if the method is never used * Figure out a reasonable (but not all too complicated) way to deal with implicit conversions, e.g. if x == "a" in the the code above, should it return 3.14 or convert the int to double? * Handle qualifiers appropriately Andrei
Oct 16 2016
On 10/16/2016 11:07 AM, Dmitry Olshansky wrote:On 10/16/16 3:58 PM, Andrei Alexandrescu wrote:Sadly it was closed, not merged. And it was a bit more general allowing getting a field by name from any struct. -- AndreiI was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);I swear I've seen a pull request merged that adds an accessible "names" AliasSeq with names of fields. That should be a good starting point.
Oct 16 2016
On Sunday, 16 October 2016 at 16:49:43 UTC, Andrei Alexandrescu wrote:Sadly it was closed, not merged. And it was a bit more general allowing getting a field by name from any struct. -- AndreiThe PR in question if anyone is interested: https://github.com/dlang/phobos/pull/4154 I currently lack the time to resurrect this, so anyone is free to take my code if they wish.
Oct 17 2016
On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);That would mean that tuple then needs to keep the strings around - taking up space. That plus the fact that the following code is equivalent (obviously): Tuple!(int, "a", double, "b") t; double v = condition ? t.a : t.b; Why this addition? What does it enable?
Oct 16 2016
On Sun, 16 Oct 2016 18:51:06 +0000, Sebastiaan Koppe wrote:On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:It doesn't change Tuple.sizeof.I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);That would mean that tuple then needs to keep the strings around - taking up space.That plus the fact that the following code is equivalent (obviously): Tuple!(int, "a", double, "b") t; double v = condition ? t.a : t.b; Why this addition? What does it enable?It's a little bit of runtime reflection, which people sometimes find handy. There's nothing stopping you from writing it manually or with metaprogramming, granted. And if it's just tuples, it doesn't seem like much of an advantage.
Oct 16 2016
On Sunday, 16 October 2016 at 20:11:01 UTC, Chris Wright wrote:On Sun, 16 Oct 2016 18:51:06 +0000, Sebastiaan Koppe wrote:Please, not. We already have great compile time reflection.On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:It doesn't change Tuple.sizeof.I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);That would mean that tuple then needs to keep the strings around - taking up space.That plus the fact that the following code is equivalent (obviously): Tuple!(int, "a", double, "b") t; double v = condition ? t.a : t.b; Why this addition? What does it enable?It's a little bit of runtime reflection, which people sometimes find handy. There's nothing stopping you from writing it manually or with metaprogramming, granted. And if it's just tuples, it doesn't seem like much of an advantage.
Oct 16 2016
On Sunday, 16 October 2016 at 20:11:01 UTC, Chris Wright wrote:On Sun, 16 Oct 2016 18:51:06 +0000, Sebastiaan Koppe wrote:Sure, but it still takes up space in the executable. Negligible of course, but for something that doesn't bring anything to the table, not so.That would mean that tuple then needs to keep the strings around - taking up space.It doesn't change Tuple.sizeof.It's a little bit of runtime reflection, which people sometimes find handy. There's nothing stopping you from writing it manually or with metaprogramming, granted. And if it's just tuples, it doesn't seem like much of an advantage.Exactly. When you want runtime reflection, would you put it in a tuple?
Oct 17 2016
On Sunday, 16 October 2016 at 18:51:06 UTC, Sebastiaan Koppe wrote:On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:I don't think this would actually require storing any additional data. It'd be more like: struct Tuple(Aliases...) { auto get(T)(string name) { foreach(alias, i; ExtractNames!Aliases) { if(alias == name) return this[i]; } } } Which is the advantage over runtime reflection in this case. It does seem a bit arbitrary to have Tuple include it though. But given that it's a template method (therefore won't be compiled in if not accessed for this particular Tuple type) and requires storing no data in the instance, there's zero overhead if you're not actually using the feature.I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14);That would mean that tuple then needs to keep the strings around - taking up space. That plus the fact that the following code is equivalent (obviously): Tuple!(int, "a", double, "b") t; double v = condition ? t.a : t.b; Why this addition? What does it enable?
Oct 16 2016
On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14); The get method takes the field name and the type of the presumed field, and it returns the value of the field in the tuple. If no field by that name and type, return the second argument. Rquirements: * Do not throw - allow the second argument to be a throwing delegate * Do not add overhead if the method is never used * Figure out a reasonable (but not all too complicated) way to deal with implicit conversions, e.g. if x == "a" in the the code above, should it return 3.14 or convert the int to double? * Handle qualifiers appropriately AndreiPersonally, if I wanted this, I'd be using a hash table with Variant objects in it or something. An argument for keeping tuple features simple is that they really aren't a good tool for doing anything fancy. If you need a runtime interface, you're probably outgrowing tuples already. Why not make a struct that contains a hash table?
Oct 16 2016
On 10/16/16 9:58 AM, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14); The get method takes the field name and the type of the presumed field, and it returns the value of the field in the tuple. If no field by that name and type, return the second argument. Rquirements: * Do not throw - allow the second argument to be a throwing delegate * Do not add overhead if the method is never used * Figure out a reasonable (but not all too complicated) way to deal with implicit conversions, e.g. if x == "a" in the the code above, should it return 3.14 or convert the int to double? * Handle qualifiers appropriatelyWhy not something like this: Val get(T, Val)(auto ref T item, string memberName, Val defaultValue) { switch(memberName) { foreach(n; __traits(allMembers, T)) { static if(is(typeof(__traits(getMember, item, n)) : Val)) case n: mixin("return item." ~ n ~ ";"); } default: return defaultValue; } } 1. It's opt-in, no code is added to the binary if you don't use it. 2. works for any type, not just Tuple. Note: no testing, this needs probably some work to get it reasonable, e.g. need to filter out private members. Maybe Jack Stouffer's PR is a better start. -Steve
Oct 17 2016
On Monday, 17 October 2016 at 13:35:12 UTC, Steven Schveighoffer wrote:Why not something like this: Val get(T, Val)(auto ref T item, string memberName, Val defaultValue) { switch(memberName) { foreach(n; __traits(allMembers, T)) { static if(is(typeof(__traits(getMember, item, n)) : Val)) case n: mixin("return item." ~ n ~ ";"); } default: return defaultValue; } }I like the general solution, although I probably would just expect it to fail compiling if no member is present or return Val.init if no defaultValue is passed.
Oct 17 2016
On 10/17/16 9:42 AM, Edwin van Leeuwen wrote:On Monday, 17 October 2016 at 13:35:12 UTC, Steven Schveighoffer wrote:Hm... this could work: Val get(Val, T)(auto ref T item, string memberName, Val defaultValue = Val.init) int x = t.get("a", 1); int x = t.get!int("a"); -SteveWhy not something like this: Val get(T, Val)(auto ref T item, string memberName, Val defaultValue) { switch(memberName) { foreach(n; __traits(allMembers, T)) { static if(is(typeof(__traits(getMember, item, n)) : Val)) case n: mixin("return item." ~ n ~ ";"); } default: return defaultValue; } }I like the general solution, although I probably would just expect it to fail compiling if no member is present or return Val.init if no defaultValue is passed.
Oct 17 2016
On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b";In Scala you can do this: def getUserInfo = ("Al", 42, 200.0) val(name, age, weight) = getUserInfo See http://alvinalexander.com/scala/scala-tuple-examples-syntax. You can also do the same thing in Kotlin and in Groovy (in Groovy it only works if static type checking is not turned on, though). I fear if D in contrast has a solution for tuples like this: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14); where variable names are mapped as strings it could harm the reputation of the language. People have something they could easily use as a sample to attack the language. These are harsh words, I know. Sorry for that. I only write this because I feel people should be advised not to do this. Real tuples or none. IMHO much better.
Oct 18 2016
On Sunday, 16 October 2016 at 13:58:51 UTC, Andrei Alexandrescu wrote:I was thinking it would be handy if tuples had a way to access a field by name at runtime. E.g.: Tuple!(int, "a", double, "b") t; string x = condition ? "a" : "b"; double v = t.get!string(x, 3.14); The get method takes the field name and the type of the presumed field, and it returns the value of the field in the tuple. If no field by that name and type, return the second argument. Rquirements: * Do not throw - allow the second argument to be a throwing delegate * Do not add overhead if the method is never used * Figure out a reasonable (but not all too complicated) way to deal with implicit conversions, e.g. if x == "a" in the the code above, should it return 3.14 or convert the int to double? * Handle qualifiers appropriately AndreiWhen I need to choose at runtime a value out of multiple choices with different types(all available at compile-time), and handle them similarly, I like to use something like this: import std.stdio; import std.typecons; import std.conv; auto getAnd(alias dlg, T)(T tup, string key) { final switch (key) foreach (fieldName; T.fieldNames) { case fieldName: return dlg(__traits(getMember, tup, fieldName)); } } void main() { Tuple!(int, "a", double, "b") t; t.a = 3; t.b = 3.14; string toString(string key) { return t.getAnd!(x => x.to!string)(key); } assert (toString("a") == "3"); assert (toString("b") == "3.14"); } The idea is to pass a delegate as an "alias", and instantiate it multiple times, once for each field. This means that instead of being forced to convert them to a common type, we can write once code that uses the correct type for each field.
Oct 18 2016