Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
August 09, 2014 tuple slicing operator | ||||
---|---|---|---|---|
| ||||
I may be misunderstanding the intended semantics of the [] operator but I've come to interpret x[] to mean "give me x as a range" and this is the meaning I intend when I overload it in my own structs. But - auto z = tuple (1,1,1); pragma (msg, typeof(z)); // Tuple!(int, int, int) pragma (msg, typeof(z[])); // (int, int, int) I'm surprised by what the last line outputs. In generic code I tend to use [] to make sure a variable is a range before I use it (like static arrays, or structs following my interpretation of []). So now whenever tuples might come into the mix I have to pass the argument through an overloaded convenience function that can tell a range or tuple type from one-element variadic argument. I've got a lot of difficulty with that last part so I am wondering, is there a better way to do this? |
August 09, 2014 Re: tuple slicing operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vlad Levenfeld | On Saturday, 9 August 2014 at 16:39:34 UTC, Vlad Levenfeld wrote: > I may be misunderstanding the intended semantics of the [] operator but I've come to interpret x[] to mean "give me x as a range" and this is the meaning I intend when I overload it in my own structs. > > But - > > auto z = tuple (1,1,1); > pragma (msg, typeof(z)); // Tuple!(int, int, int) > pragma (msg, typeof(z[])); // (int, int, int) Tuples are special. Tuple internally keeps a compiler tuple that it aliases to itself. Compiler tuples have a built-in "static slice" operator that no other type has. Since Tuple aliases a compiler tuple to itself internally, doing `z[]` actually forwards to the compiler tuple's static slice operator (which is why z[] gives you a type of (int, int, int) instead of Tuple!(int, int, int)). It is a bit confusing, but tuples are a messy part of the D language. Other than that, thinking of `x[]` as "give me x as a range" is not really correct. For one thing, any type can overload the [] operator, so x[] can mean anything. Second, it's more correct to think of x[] as meaning "give me a *slice* of x", since [] is the slice operator. Usually slices *are* ranges, but they don't have to be, and it's not a good assumption to make. > In generic code I tend to use [] to make sure a variable is a range before I use it (like static arrays, or structs following my interpretation of []). So now whenever tuples might come into the mix I have to pass the argument through an overloaded convenience function that can tell a range or tuple type from one-element variadic argument. > > I've got a lot of difficulty with that last part so I am wondering, is there a better way to do this? In generic code, you should always use template constraints and static if along with the appropriate traits to check facts about a type. Take a look at std.traits and std.range, which have templates that can tell you whether a type T is an input range, forward range, etc., an array, etc. |
August 09, 2014 Re: tuple slicing operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Saturday, 9 August 2014 at 19:26:46 UTC, Meta wrote: > (which is why z[] gives you a type of (int, int, int) instead of Tuple!(int, int, int)). That makes sense, and on second thought it wouldn't make sense to use a tuple as a range because it's not guaranteed to have only one element type. So, I can see how expanding the tuple is the reasonable thing to do. > For one thing, any type can overload the [] operator, so x[] can mean anything. True, I just meant insofar as convention based on what I had (up until the tuples) thought to be the typical usage. > Usually slices *are* ranges, but they don't have to be, and it's not a good assumption to make. Are there any specific cases where they're not? > In generic code, you should always use template constraints and static if along with the appropriate traits to check facts about a type. Good advice, I think I will stick to this. My approach was sliding into 'programming by convention'. |
August 10, 2014 Re: tuple slicing operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vlad Levenfeld | On Saturday, 9 August 2014 at 20:32:05 UTC, Vlad Levenfeld wrote: > Are there any specific cases where they're not? Not that I know of, and it doesn't really make sense for them not to be, but it could happen. If you want to be certain that slicing a type will produce a valid range, you can do it in a template constraint or a static if: void test(T)(T someType) if (isInputRange!(typeof(someType[]))) { } |
August 10, 2014 Re: tuple slicing operator | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Saturday, 9 August 2014 at 19:26:46 UTC, Meta wrote: > On Saturday, 9 August 2014 at 16:39:34 UTC, Vlad Levenfeld wrote: >> I may be misunderstanding the intended semantics of the [] operator but I've come to interpret x[] to mean "give me x as a range" and this is the meaning I intend when I overload it in my own structs. >> >> But - >> >> auto z = tuple (1,1,1); >> pragma (msg, typeof(z)); // Tuple!(int, int, int) >> pragma (msg, typeof(z[])); // (int, int, int) > > Tuples are special. Tuple internally keeps a compiler tuple that it aliases to itself. Compiler tuples have a built-in "static slice" operator that no other type has. Since Tuple aliases a compiler tuple to itself internally, doing `z[]` actually forwards to the compiler tuple's static slice operator This DIP by Dicebot is relevant: http://wiki.dlang.org/DIP63 If implemented, it can be used to overload Tuple's slice operator. |
Copyright © 1999-2021 by the D Language Foundation