August 20, 2013
Kenji Hara:

> So, std.typecons.Tuple _is not special_. You can define another Tuple struct in the same way.
> We should not define new syntax for the library utility std.typecons.Tuple.

With your idea is there a way to unpack a short array into variables? This is an handy operation I do often in Python:


>>> s = "red blue"
>>> (a, b) = s.split()
>>> a
'red'
>>> b
'blue'


Bye,
bearophile
August 20, 2013
>>>> s = "red blue"
>>>> (a, b) = s.split()
>>>> a
> 'red'
>>>> b
> 'blue'

It's supported in Haskell too:

Prelude> let s = "red blue"
Prelude> let [a, b] = words s
Prelude> a
"red"
Prelude> b
"blue"

Bye,
bearophile
August 20, 2013
bearophile I really respect informational contribution you have been doing in D community but in my opinion mentioning random snippets from other languages is the least useful thing possible in this thread. It is even less useful than discussing syntax.
August 20, 2013
2013/8/20 Dicebot <public@dicebot.lv>

> What we have here are two completely different _built-in_ tuple types. "T" is pure template arguments list and is pretty much equal TypeTuple!(int, int). But what is "args"? It uses the very same built-in tuple syntax but it is much closer to std.typecons.Tuple in its behavior (actually, latter is implemented in terms of it as I was pointed out) - it is an entity that provides abstraction of top of group of run-time values. It does not have any binary structure on its own (built on top of existing values) but observable semantic are very "run-time'ish".
>

"args" is a built-in tuple of two function parameter variables. In binary
level, args[0] and args[1] could be bounded to completely individual
storage. (Even if args[1] is on stack, args[0] may be on register)
On the other hand, std.typecons.Tuple is a struct. Its second field has the
memory address which follows of the first field.

What bothers me is the question "can we clean this up and bring those two
> worlds together, even at cost of minor breakage?". I am not speaking about literals here or unpacking or whatever. I am speaking about re-defining semantics so that struct-based Tuple and built-in syntax sugar in form of run-time expression tuple both get merged into one built-in construct which can be used in wider variety of places.


> At least right now I can't find any technical objections why expression tuple can't use std.typecons.Tuple ABI when returned from function but still be automatically expanded when passed into functions. Kenji, what is your your opinion about complexity to implement something like that in DMD?
>

Automatically packing/unpacking would need hidden runtime cost.

Kenji Hara


August 20, 2013
On Tuesday, 20 August 2013 at 15:43:39 UTC, Kenji Hara wrote:
> On the other hand, std.typecons.Tuple is a struct. Its second field has the
> memory address which follows of the first field.

Yes but as you have said exact storage of built-in tuple elements is not defined - it can be distinct elements or struct fields, compiler is free to chose any. I am not asking about internal implementation but about behavior observable by user in typical cases - it is most important topic here.

> Automatically packing/unpacking would need hidden runtime cost.

Will it be any more costly then returning std.typecons.Tuple and unpacking it manually? And, well, do we have _any_ other option of returning a tuple with no runtime costs right now anyway?

Considering we are far away from stable ABI that does not seem to be a real issue.
August 20, 2013
On Tuesday, 20 August 2013 at 13:14:46 UTC, Timon Gehr wrote:
> On 08/20/2013 12:38 PM, eles wrote:
>>
>> What about:
>>
>> !!(a, b)
>>
>
> This already has a meaning.

True :( I dunno why I took it for some kind of binary operator instead of a unary one.

I was too quick on my keyboard.
August 20, 2013
2013/8/20 bearophile <bearophileHUGS@lycos.com>

> So, std.typecons.Tuple _is not special_. You can define another Tuple
>> struct in the same way.
>> We should not define new syntax for the library utility
>> std.typecons.Tuple.
>>
>
> With your idea is there a way to unpack a short array into variables? This is an handy operation I do often in Python:
>
>  s = "red blue"
>>>> (a, b) = s.split()
>>>> a
>>>>
>>> 'red'
>
>> b
>>>>
>>> 'blue'
>

My position to such a feature is constant. We should not conflate tuple unpacking and array unpacking.

But, extending unpacking syntax mentioned in DIP32 might help it.

// Just an idea: extending DIP32 unpacking syntax
import std.typecons : tuple;
auto tup = tuple(1, tuple(2,3), [4,5]);
{ auto a, {b, c}, [d, e] } = tup;
//{ auto a, [b, c], {d, e} } = tup;   // cause compile-time error
assert(a == 1);
assert(b == 2 && c == 3);
assert(d == 4 && e == 5);

However, array unpacking would require *hidden* runtime boundary check. In above example code,

  assert(tup[2].length == 2);
  // or
  if (tup[2].length != 2) throw Error("Runtime mismatch of unpacking
pattern");
  // or similar

should be implicitly inserted by compiler, even in @system code. I'm not sure that is acceptable cost or not.

Kenji Hara


August 20, 2013
Dicebot:

> bearophile I really respect informational contribution you have been doing in D community but in my opinion mentioning random snippets from other languages is the least useful thing possible in this thread. It is even less useful than discussing syntax.

Look better at them, those aren't random snippets, they show one more case of de-structuring, creating a tuple of variables out of an array. It's a commonly used operation in two very well designed languages that have tuples. Here we are discussing tuples and their packing and unpacking, so the two examples I've shown are very relevant, even if we decide to not support that specific feature.

Bye,
bearophile
August 20, 2013
Kenji Hara:

> My position to such a feature is constant.

Even if your opinion is not changed, I have to show that common tuple-related features to the other persons that are reading this thread, because it's an an idea to keep in account (even if it's refused), and some other person could have an opinion different from yours.


> However, array unpacking would require *hidden* runtime boundary check.
> In above example code,
>
>   assert(tup[2].length == 2);
>   // or
>   if (tup[2].length != 2) throw Error("Runtime mismatch of unpacking
> pattern");
>   // or similar
>
> should be implicitly inserted by compiler, even in @system code.
> I'm not sure that is acceptable cost or not.

Runtime boundary checks and tests are not needed if you unpack a fixed-sized array:

auto tup = Tuple!(int, string[2])(1, ["red", "blue"]);
auto {x, [c1, c2]} = tup;

Regarding the de-structuring of dynamic arrays, I think it's not too much different than this:

void main() {
    int[] a = [10, 20, 30];
    int[2] b = a;
}

If you compile and run it without switches, you get at run-time:

object.Error: lengths don't match for array copy, 2 = 3


While I receive no run-time errors if I compile with -noboundscheck.

Bye,
bearophile
August 20, 2013
On 8/19/13 11:39 PM, Timon Gehr wrote:
> On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:
>>
>> Why would it be necessary to return an object of type TypeTuple (i.e.
>> template tuple)?
>
>
> - Elegance. Eg:
>
> auto seq(T...)(T arg){ return arg; }
>
> auto fold(alias a,S,R)(S start, R range){ ... }
>
>
> seq(0,[1,2,3]).fold!((a,b)=>a+b);

But this is again a value tuple not a template tuple, no?

Andrei