www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - tuple slicing operator

reply "Vlad Levenfeld" <vlevenfeld gmail.com> writes:
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?
Aug 09 2014
parent reply "Meta" <jared771 gmail.com> writes:
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.
Aug 09 2014
next sibling parent reply "Vlad Levenfeld" <vlevenfeld gmail.com> writes:
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'.
Aug 09 2014
parent "Meta" <jared771 gmail.com> writes:
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[]))) { }
Aug 09 2014
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
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.
Aug 10 2014