October 17, 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 appropriately

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;
   }
}

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
October 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.

October 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:
>>
>> 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.

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");

-Steve
October 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";

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.
October 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
>
>
> Andrei

When 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.
1 2
Next ›   Last »