October 21, 2009
Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:

> On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo@bar.com.invalid> wrote:
> 
>> Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.
> 
> Or use a templated opAssign mixin to allow two desperate types to be assigned to each other.

Wow, you need templates to implement == for built-in values types, nice..

> Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be:
> 
>    val a = (1,2) : [Int,Int]
>    val b = (1,2) : [Int,Int]
>    val c = (2,3) : MyCustomTupleType[Int,Int]
> 
> which would probably generate:
>       assert(a == b); // ok
>       assert(a != c); // Error: incompatible types for ((a) != (b))

If you have built-in tuple literals, there is no way you can build a MyCustomTupleType without resorting to other language features. There are no apples and oranges, cause they both are seen as (Int,Int) by the equivalence checker. Do you understand how equivalence works in structural typing system (http://en.wikipedia.org/wiki/ Structural_type_system) vs nominal typing? In structural equivalence there are no names attached to the types (well there might be, but those are omitted in the comparison), only their internal structure matters.

Why would anyone want to create two incompatible tuples by default as you still would have 'typedef' and 'struct' for implementing just that.
October 21, 2009
Yigal Chripun, el 21 de octubre a las 07:18 me escribiste:
> On 21/10/2009 05:48, Robert Jacques wrote:
> >On Tue, 20 Oct 2009 23:30:48 -0400, Leandro Lucarella <llucax@gmail.com> wrote:
> >>Robert Jacques, el 20 de octubre a las 21:06 me escribiste:
> >>>Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.
> >>
> >>Yes, that's another thing that can be done without real tuple support in the language. Anyway, I guess I was a little exaggerated with '*way far* from ideal', but I'm convinced there is plenty of room for improvements. =)
> >>
> >
> >Would you happen to know of a language which does tuples well already?
> 
> pick any functional language.. my favorite is ML

Or Python ;)

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
HACIA NEUQUEN: EL JUEVES SALDRA CARAVANA CON PERROS
DESDE CAPITAL EN APOYO AL CACHORRO CONDENADO A MUERTE
	-- Crónica TV
October 21, 2009
On Wed, 21 Oct 2009 02:23:09 -0400, language_fan <foo@bar.com.invalid> wrote:
> Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:
>
>> On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo@bar.com.invalid>
>> wrote:
>>
>>> Real tuple types do not have a special type tag which gets injected
>>> implicitly with structs. So every time you try to do something
>>> lightweight by emulating tuples, you need to refer to the global Tuple
>>> type or bang your head to the wall.
>>
>> Or use a templated opAssign mixin to allow two desperate types to be
>> assigned to each other.
>
> Wow, you need templates to implement == for built-in values types, nice..

Unlike C++, D templates don't require a PhD to use. And it's definitely better that banging your head against the wall.

>> Besides, I think you're comparing apples to oranges. In the SOL example,
>> you use the same declaration for all types. Shouldn't the SOL example
>> be:
>>
>>    val a = (1,2) : [Int,Int]
>>    val b = (1,2) : [Int,Int]
>>    val c = (2,3) : MyCustomTupleType[Int,Int]
>>
>> which would probably generate:
>>       assert(a == b); // ok
>>       assert(a != c); // Error: incompatible types for ((a) != (b))
>
> If you have built-in tuple literals, there is no way you can build a
> MyCustomTupleType without resorting to other language features. There are
> no apples and oranges, cause they both are seen as (Int,Int) by the
> equivalence checker. Do you understand how equivalence works in
> structural typing system (http://en.wikipedia.org/wiki/
> Structural_type_system) vs nominal typing? In structural equivalence
> there are no names attached to the types (well there might be, but those
> are omitted in the comparison), only their internal structure matters.
>
> Why would anyone want to create two incompatible tuples by default as you
> still would have 'typedef' and 'struct' for implementing just that.

My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)


October 21, 2009
Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:

> On Wed, 21 Oct 2009 02:23:09 -0400, language_fan <foo@bar.com.invalid> wrote:
>> Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:
>>
>>> On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo@bar.com.invalid> wrote:
>>>
>>>> Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.
>>>
>>> Or use a templated opAssign mixin to allow two desperate types to be assigned to each other.
>>
>> Wow, you need templates to implement == for built-in values types, nice..
> 
> Unlike C++, D templates don't require a PhD to use. And it's definitely better that banging your head against the wall.
> 
>>> Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be:
>>>
>>>    val a = (1,2) : [Int,Int]
>>>    val b = (1,2) : [Int,Int]
>>>    val c = (2,3) : MyCustomTupleType[Int,Int]
>>>
>>> which would probably generate:
>>>       assert(a == b); // ok
>>>       assert(a != c); // Error: incompatible types for ((a) != (b))
>>
>> If you have built-in tuple literals, there is no way you can build a MyCustomTupleType without resorting to other language features. There are no apples and oranges, cause they both are seen as (Int,Int) by the equivalence checker. Do you understand how equivalence works in structural typing system (http://en.wikipedia.org/wiki/ Structural_type_system) vs nominal typing? In structural equivalence there are no names attached to the types (well there might be, but those are omitted in the comparison), only their internal structure matters.
>>
>> Why would anyone want to create two incompatible tuples by default as you still would have 'typedef' and 'struct' for implementing just that.
> 
> My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)

Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work. I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country.

Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.
October 21, 2009
language_fan wrote:
> Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:
>> My issue was that all your example _showed_ was nominal typing. Though I
>> didn't mention it by name, I did mention that if SOL tuples had
>> structural typing, it might would be a different story. (Well, until/if
>> opImplicitCast was implemented, as it would allow for structural
>> typing.)
> 
> Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.

I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?

> I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country.

How and why are they treated badly?

> Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.

What exactly didn't D's tuples get right?


Andrei
October 21, 2009
On Wed, Oct 21, 2009 at 8:48 AM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> language_fan wrote:
>>
>> Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:
>>>
>>> My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)
>>
>> Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.
>
> I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?
>
>> I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country.
>
> How and why are they treated badly?
>
>> Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.
>
> What exactly didn't D's tuples get right?

Well, auto-flattening is a colossally bad idea to be sure.

--bb
October 21, 2009
Bill Baxter wrote:
> Well, auto-flattening is a colossally bad idea to be sure.

Well that I agree with. I wonder if we need to fix it for D2. If we don't, we risk to live with it like with a chronic cough.

Andrei
October 21, 2009
Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:

> language_fan wrote:
>> Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:
>>> My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)
>> 
>> Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.
> 
> I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?

Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.

>>> STARTS HERE

template Tuple(T...) { alias T Tuple; }

struct STuple(T...) {
  T t;
}

void main() {
  Tuple!(int,int) a; // typeof(this) *is* the official tuple type
  STuple!(int,int) b;  // this is actually a struct

  a = Tuple!(1,1);  // ok
  // Tuple!(int,int) a2 = Tuple!(1,1); // WTF? Error: cannot implicitly
convert expression (tuple(1,1)) of type (int, int) to int
  auto a3 = Tuple!(1,1); // ok


  b = STuple!(int,int)(1,1); // no easier way? make_tuple!(1,1) ?
  STuple!(int,int) b2 = STuple!(int,int)(1,1); // ok, but very verbose


  auto e1 = a[0];  // ok

  //auto e2 = b[0]; // nope
  auto e3 = b.t[0]; // this is how it works - you could possibly define
opIndex but how would it work with different types then

   writefln("%s", a); // we get.. 1 !? but..
   writefln("%s", typeof(a).stringof); // (int, int)
   writefln("%s", b); // STuple!(int,int)(1, 1) - rather verbose, but
suffices


  //auto retTest() { return STuple!(int,int)(1,1); } // no identifier for
declarator retTest

  STuple!(int,int) retTest2() { return STuple!(int,int)(1,1); }; // ok,
but a bit too verbose

  int d,e;
  Tuple!(d,e) = Tuple!(10,20); // ok

  // but how to discard an unnecessary value? e.g. (a, _) = (1, 2)

  // Tuple!(d,e) = STuple!(10,20); // nope, not interchangeable
  // b = STuple!(a); // same here

  a = a; // ok
  b = b; // ok
  // a = b; // Error: a is not an lvalue -- interesting!


  Tuple!(d,b) = Tuple!(1, retTest2()); // awesome, with the Tuple I can
even assign Tuples of STuples!
  //Tuple!(d,a) = Tuple!(1, a); // but Tuples don't help when assigning
Tuples of Tuples

    //test.d(12): Error: expression _a_field_0 is not a valid template
value argument
    //test.d(12): Error: expression _a_field_1 is not a valid template
value argument
    //test.d(47): Error: template instance test.Tuple!
(1,_a_field_0,_a_field_1) error instantiating

  // LET'S MAKE ARRAYS!

   int[] a1; // ok
   int[][] a2; // ok
   auto a1b = [1,2,3]; // ok
   auto a2b = [[1],[2],[3]]; // ok

   //Tuple!(int,int)[] a4; // Error: can't have array of (int, int) --
WHY NOT - it's simple, try e.g. ML
   STuple!(int,int)[] a5; // ok

   auto a3b = [Tuple!(1,1)]; // works, but hey did you know this is an
array of ints!

   auto a4b = [STuple!(int,int)(1,1)]; // ok

   // int[Tuple!(int,int)] a6; // Error: can't have associative array key
of (int, int)
   int[STuple!(int,int)] a7; // ok

   a7[STuple!(int,int)(1,1)] = 5; // ok

   Tuple!(int,Tuple!(int,int)) a8; // this isn't a (int, (int,int)) tuple
- it's (int,int,int) !
   STuple!(int,STuple!(int,int)) a9; // ok

   //auto a10 = [ Tuple!(1,1) : 2 ]; // Error: can't have associative
array key of (int, int) -- Why did this work in array literal then?!

   auto a11 = [ STuple!(int,int)(1,1) : 2 ]; // ok

   alias Tuple!(int, 5) foo;
   // alias STuple!(int, 5) foo2; // parameters can only be types
}
October 21, 2009
Wed, 21 Oct 2009 16:54:22 +0000, language_fan thusly wrote:

> Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:
> 
>> language_fan wrote:
>>> Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:
>>>> My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)
>>> 
>>> Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.
>> 
>> I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?
> 
> Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.

I forgot to say that you need two kinds of tuple "literals" in your standard library in D: one with value semantics, and one that is a wrapper around the alias tuple since auto-flattening happens.
October 21, 2009
language_fan wrote:
> Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:
> 
>> language_fan wrote:
>>> Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:
>>>> My issue was that all your example _showed_ was nominal typing. Though
>>>> I didn't mention it by name, I did mention that if SOL tuples had
>>>> structural typing, it might would be a different story. (Well,
>>>> until/if opImplicitCast was implemented, as it would allow for
>>>> structural typing.)
>>> Why do you insist on using nominal typing for tuples and the library
>>> defined "literal". If I want plain old tuples without any kind of type
>>> name, why should I care about extra hand waving needed to make it work.
>> I'm late in this dialog, but I'm not seeing an impediment here. What
>> does it matter to you that tuples actually have a name vs. not having a
>> name at all?
> 
> Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague.

How do you know what "people" do?

> I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/
> type tuples. Stuples can only be used as values and when the auto-
> flattening is not desired.
> 
>>>> STARTS HERE
> 
> template Tuple(T...) { alias T Tuple; }

Why do you define Tuple instead of using the standard std.typecons.tuple?

> struct STuple(T...) {
>   T t;
> }

Why do you insist on defining another tuple type instead of using the one provided by the standard library?

> void main() {
>   Tuple!(int,int) a; // typeof(this) *is* the official tuple type
>   STuple!(int,int) b;  // this is actually a struct
> 
>   a = Tuple!(1,1);  // ok

That doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write:

a = Tuple!(1, 1);

that is as good syntactically as:

a = int;

which I hope you agree shouldn't quite go through. Write this:

Tuple!(int,int) a;
a = tuple(1, 1);

or this:

auto a = tuple(1, 1);

>   // Tuple!(int,int) a2 = Tuple!(1,1); // WTF? Error: cannot implicitly convert expression (tuple(1,1)) of type (int, int) to int

Yeah, WTF that doesn't work either:

int a2 = int;

>   auto a3 = Tuple!(1,1); // ok

Not ok on my machine, nor it should be ok as this is also not ok:

auto a3 = int;

>   b = STuple!(int,int)(1,1); // no easier way? make_tuple!(1,1) ?

Yeah try tuple(1, 1) in conjunction with std.typecons.Tuple.

>   STuple!(int,int) b2 = STuple!(int,int)(1,1); // ok, but very verbose

Well write this:

auto stuple(T...)(T args) {
    return STuple!(T)(args);
}

>   auto e1 = a[0];  // ok

This doesn't work because of a bug in the compiler, but this does with std.typecons.Tuple:

auto e1 = a.field[0];

etc. etc. etc.

I'm sure you make a couple of good points, but they are difficult to find. I suggest you peruse std.typecons.Tuple and submit any bugs you find to bugzilla.


Andrei