www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Tuple literal syntax

reply Walter Bright <newshound2 digitalmars.com> writes:
There have been a couple of looong threads about tuples:

http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html

http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html

A lot of it foundered on what the syntax for tuple literals should be. The top 
of the list is simply enclosing them in ( ). The problem with this is

  (expression)

Is that a parenthesized expression, or a tuple? This really matters, since 
(e)[0] means very different things for the two. Finally, I got to thinking, why 
not just make it a special case:


  ( ) == tuple
  (a) == parenthesized expression
  (a,b) == tuple
  (a,b,c) == tuple
  (a,b,c,d) == tuple

etc.

No ambiguities! Only one special case. I submit this special case is rare, 
because who wants to define a function that returns a tuple of 1? Such will
come 
about from generative programming, but:

(a,b,c)[0]

may be how the generative programming works, and that suggests:

(a,0)[0]

as how a user could generate a tuple of 1. Awkward, sure, but like I said, I 
think this would be rare.
Oct 06 2010
next sibling parent reply Kagamin <spam here.lot> writes:
Don't function arguments also comprise a tuple? A tuple of 1.
Oct 06 2010
parent Walter Bright <newshound2 digitalmars.com> writes:
Kagamin wrote:
 Don't function arguments also comprise a tuple? A tuple of 1.
Yes, but that's not ambiguous.
Oct 06 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday 06 October 2010 23:04:35 Walter Bright wrote:
 There have been a couple of looong threads about tuples:
 
 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_peopl
 e_using_D_93528.html
 
 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operat
 or_be_removed_in_D2_101321.html
 
 A lot of it foundered on what the syntax for tuple literals should be. The
 top of the list is simply enclosing them in ( ). The problem with this is
 
   (expression)
 
 Is that a parenthesized expression, or a tuple? This really matters, since
 (e)[0] means very different things for the two. Finally, I got to thinking,
 why not just make it a special case:
 
 
   ( ) == tuple
   (a) == parenthesized expression
   (a,b) == tuple
   (a,b,c) == tuple
   (a,b,c,d) == tuple
 
 etc.
 
 No ambiguities! Only one special case. I submit this special case is rare,
 because who wants to define a function that returns a tuple of 1? Such will
 come about from generative programming, but:
 
 (a,b,c)[0]
 
 may be how the generative programming works, and that suggests:
 
 (a,0)[0]
 
 as how a user could generate a tuple of 1. Awkward, sure, but like I said,
 I think this would be rare.
As long as you can define () to use tuples in an unambiguous manner, I'm all for it. Personally, I don't really mind Tuple so much as I find the fact that you have both Tuple and TypeTuple to be highly confusing. But it wouldn't hurt my feelings to just use parens either. - Jonathan M Davis
Oct 06 2010
prev sibling next sibling parent reply Juanjo Alvarez <fake fakeemail.com> writes:
On Wed, 06 Oct 2010 23:04:35 -0700, Walter Bright 
<newshound2 digitalmars.com> wrote:
 (a,0)[0]
 as how a user could generate a tuple of 1. Awkward, sure, but like 
I said, I
 think this would be rare.
Python uses: (5,) Which is a lot better IMHO
Oct 07 2010
next sibling parent Don <nospam nospam.com> writes:
Juanjo Alvarez wrote:
 On Wed, 06 Oct 2010 23:04:35 -0700, Walter Bright 
 <newshound2 digitalmars.com> wrote:
 (a,0)[0]
 as how a user could generate a tuple of 1. Awkward, sure, but like 
I said, I
 think this would be rare.
Python uses: (5,) Which is a lot better IMHO
I agree, that would fit well with the optional trailing commas in array literals.
Oct 07 2010
prev sibling parent Olivier Pisano <olivier.pisano laposte.net> writes:
Le 07/10/2010 09:44, Juanjo Alvarez a écrit :
 On Wed, 06 Oct 2010 23:04:35 -0700, Walter Bright
 <newshound2 digitalmars.com> wrote:
 (a,0)[0]
 as how a user could generate a tuple of 1. Awkward, sure, but like
I said, I
 think this would be rare.
Python uses: (5,) Which is a lot better IMHO
Vote++;
Oct 07 2010
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Thu, 07 Oct 2010 10:04:35 +0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 There have been a couple of looong threads about tuples:

 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html

 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html

 A lot of it foundered on what the syntax for tuple literals should be.  
 The top of the list is simply enclosing them in ( ). The problem with  
 this is

   (expression)

 Is that a parenthesized expression, or a tuple? This really matters,  
 since (e)[0] means very different things for the two. Finally, I got to  
 thinking, why not just make it a special case:


   ( ) == tuple
   (a) == parenthesized expression
   (a,b) == tuple
   (a,b,c) == tuple
   (a,b,c,d) == tuple

 etc.

 No ambiguities! Only one special case. I submit this special case is  
 rare, because who wants to define a function that returns a tuple of 1?  
 Such will come about from generative programming, but:

 (a,b,c)[0]

 may be how the generative programming works, and that suggests:

 (a,0)[0]

 as how a user could generate a tuple of 1. Awkward, sure, but like I  
 said, I think this would be rare.
If tuples become first-class citizens of D lands, is it possible to make 'void' and alias to an empty tuple? I believe they are basically the same thing. A function that accepts no arguments may be defined as a function that accepts a tuple of size 0: void f1(string, string); auto tuple1 = ("hello, %s", "world"); f1(tuple1); // works void f2(); auto tuple2 = (); f2(tuple2); // should work, too That would allow creation a variables of type void, which is very useful for generic programming. Here is an example: auto proxy(alias f)() { auto result = f(); do(stuff); return result; } Works for any functions 'f' but returning voids. I know it have been asked many times with no success, but still...
Oct 07 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 1:04 CDT, Walter Bright wrote:
 There have been a couple of looong threads about tuples:

 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html


 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html


 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is

 (expression)

 Is that a parenthesized expression, or a tuple? This really matters,
 since (e)[0] means very different things for the two. Finally, I got to
 thinking, why not just make it a special case:


 ( ) == tuple
 (a) == parenthesized expression
 (a,b) == tuple
 (a,b,c) == tuple
 (a,b,c,d) == tuple

 etc.

 No ambiguities! Only one special case. I submit this special case is
 rare, because who wants to define a function that returns a tuple of 1?
 Such will come about from generative programming, but:

 (a,b,c)[0]

 may be how the generative programming works, and that suggests:

 (a,0)[0]

 as how a user could generate a tuple of 1. Awkward, sure, but like I
 said, I think this would be rare.
Sorry for being Debbie Downer in this thread, but I'm not seeing a lot of progress here. This is nothing but a syntax cutesy that helps Tuple!(A, B) and tuple(a, b) and leaves all other issues related to tuples unresolved (I'm actually afraid that it exacerbates them). One good thing about Tuple is that it allows names of fields, so functions can return tuples with conveniently named fields, e.g. Tuple!(bool, "found", size_t, "position") etc. without having to define little structs everywhere and fostering simple, clear code on the caller side. Also, obviously, empty tuples and tuples with one element are self-explanatory (Tuple!() and Tuple!(int) for types, tuple() and tuple(4) for values). Up until recently the syntax t[i] didn't work for tuples, forcing t.field[i]. This marginally improves usage of tuples. There are still other issues left due to compiler bugs; for example slicing t[a .. b] is supposed to work but it doesn't. But my question is, do we need more notation, more special cases, more ambiguities, more solution to ambiguities, more corner cases (there's already a request for handling void in a particular way)...? And for what? Quite literally because we refuse to call a tuple a tuple? I'm not seeing much gain here. Syntactic sugar is good in moderate quantities, but in Perlis' words this is bound to cause cancer of the semicolon. My suggestion on improving tuples is to fix the compiler bugs that currently hamstrung Tuple and to make it the best it can be. Once we're clear on the functionality, it would be great to see how we can package it better with a bit of language support. Andrei
Oct 07 2010
next sibling parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 03:20:23 -0500, Andrei Alexandrescu wrote:

 Sorry for being Debbie Downer in this thread, but I'm not seeing a lot
 of progress here. This is nothing but a syntax cutesy that helps
 Tuple!(A, B) and tuple(a, b) and leaves all other issues related to
 tuples unresolved (I'm actually afraid that it exacerbates them).
 
 One good thing about Tuple is that it allows names of fields, so
 functions can return tuples with conveniently named fields, e.g.
 Tuple!(bool, "found", size_t, "position") etc. without having to define
 little structs everywhere and fostering simple, clear code on the caller
 side.
Why do tuple fields need a name? Isn't this a new ad-hoc way to introduce structural typing in D? I often start with tuples, but if it turns out that the value is used in many places, it will be eventually replaced with a struct (e.g. coordinates in a gui / gamedev) for better type safety. Even with structs the need for field names is very rare. The real need for tuples is in very special cases where the syntax needs to be light.
Oct 07 2010
next sibling parent Kagamin <spam here.lot> writes:
retard Wrote:

 safety. Even with structs the need for field names is very rare. The real 
 need for tuples is in very special cases where the syntax needs to be 
 light.
You really need tuples to write obscure functional code.
Oct 07 2010
prev sibling next sibling parent Juanjo Alvarez <juanjux gmail.com> writes:
retard Wrote:


 Why do tuple fields need a name? Isn't this a new ad-hoc way to introduce 
 structural typing in D? I often start with tuples, but if it turns out 
 that the value is used in many places, it will be eventually replaced 
 with a struct (e.g. coordinates in a gui / gamedev) for better type 
 safety. Even with structs the need for field names is very rare. The real 
 need for tuples is in very special cases where the syntax needs to be 
 light.
I found they are useful for callbacks, when you can put, in a tuple, the delegate or function to the callback and in another nested tuple the delegate/function parameters. This way you can define the callbacks to be used along with their parameters, even if their signature is different. You could do the same with the callbacks having variable number and types of args, using a template, but I like this way more.
Oct 07 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 5:39 CDT, retard wrote:
 Thu, 07 Oct 2010 03:20:23 -0500, Andrei Alexandrescu wrote:

 Sorry for being Debbie Downer in this thread, but I'm not seeing a lot
 of progress here. This is nothing but a syntax cutesy that helps
 Tuple!(A, B) and tuple(a, b) and leaves all other issues related to
 tuples unresolved (I'm actually afraid that it exacerbates them).

 One good thing about Tuple is that it allows names of fields, so
 functions can return tuples with conveniently named fields, e.g.
 Tuple!(bool, "found", size_t, "position") etc. without having to define
 little structs everywhere and fostering simple, clear code on the caller
 side.
Why do tuple fields need a name?
They don't always need, but oftentimes names are better than numeric constants.
 Isn't this a new ad-hoc way to introduce
 structural typing in D?
Well what is the old ad-hoc way? Anyhow, tuples are a prime candidate for structural typing. Currently Tuple does not support it.
 I often start with tuples, but if it turns out
 that the value is used in many places, it will be eventually replaced
 with a struct (e.g. coordinates in a gui / gamedev) for better type
 safety.
I don't see struct Coord { int x, y, z; } one iota typesafer than alias Tuple!(int, "x", int, "y", int, "z") Coord; Clearly if you want to introduce protection, methods etc. then struct/class is the way to go. Tuples have their charter.
 Even with structs the need for field names is very rare.
I don't know how to define a struct without naming its fields in C, C++, descriptive names.
 The real
 need for tuples is in very special cases where the syntax needs to be
 light.
auto r = fun(42); writeln(r.foo, ": ", r.bar); On the client side the syntax is very light. The definition of the function would need to specify the type name: Tuple!(int, "foo", string, "bar") fun(int) { ... } I think much of the list of grievances against tuple limitations stems from a feeling that doing tuples without special syntax is "cheating". For my money, library tuples are eminently usable, and once we fix a couple of compiler bugs, they will be as good as (if not simpler, richer, and clearer than) a built-in facility. I do want to introduce syntax for expansion a la auto (a, b) = foo(42); because that's a common need that's not satisfiable via a library. But then I want to define the syntax in a general way so it works not only with tuples, but also with arrays and types that implement opIndex. Andrei
Oct 07 2010
next sibling parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 09:46:59 -0500, Andrei Alexandrescu wrote:

 On 10/7/10 5:39 CDT, retard wrote:
 Thu, 07 Oct 2010 03:20:23 -0500, Andrei Alexandrescu wrote:

 Sorry for being Debbie Downer in this thread, but I'm not seeing a lot
 of progress here. This is nothing but a syntax cutesy that helps
 Tuple!(A, B) and tuple(a, b) and leaves all other issues related to
 tuples unresolved (I'm actually afraid that it exacerbates them).

 One good thing about Tuple is that it allows names of fields, so
 functions can return tuples with conveniently named fields, e.g.
 Tuple!(bool, "found", size_t, "position") etc. without having to
 define little structs everywhere and fostering simple, clear code on
 the caller side.
Why do tuple fields need a name?
They don't always need, but oftentimes names are better than numeric constants.
If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).
 
 Isn't this a new ad-hoc way to introduce structural typing in D?
Well what is the old ad-hoc way? Anyhow, tuples are a prime candidate for structural typing. Currently Tuple does not support it.
I have nothing against the structural typing of tuples, per se. I meant structural typing in the sense that Scala implements it -- a set of name- value pairs constructs a new type. It seems to require runtime dictionaries in their implementation.
 
 I often start with tuples, but if it turns out that the value is used
 in many places, it will be eventually replaced with a struct (e.g.
 coordinates in a gui / gamedev) for better type safety.
I don't see struct Coord { int x, y, z; } one iota typesafer than alias Tuple!(int, "x", int, "y", int, "z") Coord;
I meant the naming of the aggregate vs not naming it. Passing around n- tuples without any name associated for the concept allows mixing n-tuples if the internal type structure matches. Sometimes I want to distinguish between the uses. Clearly some coordinate in the game world shouldn't automatically be applicable in the GUI context: struct GameCoord { int x,y,z; } struct GUICoord { int x,y,z; } // void drawOval(GUICoord); // fun prototype GameCoord a; drawOval(a); // bang This might lead to bugs if the compiler silently accepts a wrong aggregate.
 Even with structs the need for field names is very rare.
I don't know how to define a struct without naming its fields in C, C++, descriptive names.
I didn't know what the template creates. I had an impression that it creates an array of strings for some runtime purposes, like: foreach(value; tuple) { writefln("%s is %s", value.name, value); } So I was just refering to those runtime string literals. Maybe I confused this with some enum related template.
 The real
 need for tuples is in very special cases where the syntax needs to be
 light.
auto r = fun(42); writeln(r.foo, ": ", r.bar); On the client side the syntax is very light. The definition of the function would need to specify the type name: Tuple!(int, "foo", string, "bar") fun(int) { ... }
We have an issue with terminology here. To me that isn't a *tuple*, it's a record! A tuple would let you choose the variable names on the client side: auto (foo, bar) = fun(42); writeln(foo, ": ", bar);
Oct 07 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
retard <re tard.com.invalid> wrote:

 Why do tuple fields need a name?
They don't always need, but oftentimes names are better than numeric constants.
If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).
What? You really think structs/tuples are implemented like Variant[string]? foo.bar => *(&foo + bar.offsetof), where offsetof is known at compiletime. It doesn't get faster than that. -- Simen
Oct 07 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 10:22 CDT, Simen kjaeraas wrote:
 retard <re tard.com.invalid> wrote:

 Why do tuple fields need a name?
They don't always need, but oftentimes names are better than numeric constants.
If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).
What? You really think structs/tuples are implemented like Variant[string]? foo.bar => *(&foo + bar.offsetof), where offsetof is known at compiletime. It doesn't get faster than that.
Yah, this is D dammit :o). Andrei
Oct 07 2010
prev sibling parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 17:22:08 +0200, Simen kjaeraas wrote:

 retard <re tard.com.invalid> wrote:
 
 Why do tuple fields need a name?
They don't always need, but oftentimes names are better than numeric constants.
If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).
What? You really think structs/tuples are implemented like Variant[string]? foo.bar => *(&foo + bar.offsetof), where offsetof is known at compiletime. It doesn't get faster than that.
There are several conflicting concepts at stake here. I guess the nominative typing is quite clear -- the type name fully dictates the physical and logical form of the data. But structural typing can be implemented in several ways. I use the name 'record' for tuples with field names. This notation doesn't necessarily define any physical order of fields in the memory. When you bring an aggregate from the tuple world to the struct world, you have to lock down some physical layout for the data. If you don't have first class tuple constructors and define them with a template, that's unfortunately not structural typing. The D's structs might use the copying semantics from structural typing, but it's a weird hybrid type, actually. Just like the tuples aren't real tuples. Field names break the definition. Type tuples break it, too.
Oct 07 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
retard <re tard.com.invalid> wrote:

 If you don't have first class tuple constructors and define them with a
 template, that's unfortunately not structural typing.
Might I inquire as to why? As far as I can see, one can regard a structural type as a set of types, fields, if you will. Each element of this set has some properties, which would have to be equal to those of an element of a similar set in an equal type. That is, (int, string) may be equal to (string, int) if one considers index not to be one of those properties. Some structural type systems will consider names part of those properties, leading (string a, int b) to be equivalent to (int b, string a), if, as before, index is not an interesting property. By choosing opposite in these choices (index is important, name is not), I cannot see that the premise of a structural type system is broken. In this system, (int b, string a) != (string a, int b), and (string a, int b) == (string b, int a). Either of these choices can be implemented in D (the latter I have implemented), so I cannot quite see where you are going with this.
 The D's structs
 might use the copying semantics from structural typing, but it's a weird
 hybrid type, actually.
In this I agree. Well, given that in D a struct name in D would be unique (bar linker fuckups), I would argue it is nominative. -- Simen
Oct 07 2010
parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard <re tard.com.invalid> wrote:
 
 If you don't have first class tuple constructors and define them with a
 template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Oct 07 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 13:44 CDT, retard wrote:
 Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard<re tard.com.invalid>  wrote:

 If you don't have first class tuple constructors and define them with a
 template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Could you please take the time to put together a list of requirements? That would be great for either making Tuple better or for improving the language. Andrei
Oct 07 2010
parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote:

 On 10/7/10 13:44 CDT, retard wrote:
 Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard<re tard.com.invalid>  wrote:

 If you don't have first class tuple constructors and define them with
 a template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Could you please take the time to put together a list of requirements? That would be great for either making Tuple better or for improving the language.
Sure, but I can't really promise to have to capacity to think about every possible case when we are discussing D. There are so many complex features! I think a more or less complete list can already be constructed from all past discussions here. The tuple issues come up every now and then. FWIW, the library provided solution with syntactical support doesn't sound so bad now that I think about it. We just need to know, what we are trying to solve here. The bigger problems come up when overloading the same system with mixed value/type/alias tuples.
Oct 07 2010
next sibling parent retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 18:56:46 +0000, retard wrote:

 Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote:
 
 On 10/7/10 13:44 CDT, retard wrote:
 Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard<re tard.com.invalid>  wrote:

 If you don't have first class tuple constructors and define them
 with a template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Could you please take the time to put together a list of requirements? That would be great for either making Tuple better or for improving the language.
Sure, but I can't really promise to have to capacity to think about every possible case when we are discussing D. There are so many complex features! I think a more or less complete list can already be constructed from all past discussions here. The tuple issues come up every now and then. FWIW, the library provided solution with syntactical support doesn't sound so bad now that I think about it. We just need to know, what we are trying to solve here. The bigger problems come up when overloading the same system with mixed value/type/alias tuples.
If I think about some basic features in other tuple using languages, you need to have a way to 1) construct tuples (as a statement and as an expression) auto foo = (1,2); return (1,2); foo = { return (0, 42); }(); 2) interact nicely with built-in types (AAs, structs, classes, arrays, nested tuples, and recursively all permutations of these come to mind) 3) extract a single field auto foo = (1,2); auto bar = foo._1; // or foo[0] 4) extract all fields ("pattern matching") auto baz = (1,2); auto (foo, bar) = baz; auto (foo2, _) = baz; // maybe even this? not necessary 5) tuples with named fields (beware conflicts with other literals) auto baz = (foo: 1, bar: 2); auto buz = baz.foo; // like this maybe? 6) since they use structural typing semantics, this should work auto foo = (1,2); auto bar = (2,3); bar = foo; --- I can't decide how the tuples should work with e.g. parameter lists. I'm not a big friend of auto-flattening on any level. E.g. void foo((int,int) bar); and void foo(int a, int b); should have a different type signature IMO. These rules should cleanly generalize to mixed tuples in type context, when used in metaprogramming (e.g. parametric types). People probably want to construct other literals such as arrays from tuples. These are all special cases from type system's pov. I have no opinion. Well I have -- I don't like messy rules.
Oct 07 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 13:56 CDT, retard wrote:
 Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote:

 On 10/7/10 13:44 CDT, retard wrote:
 Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard<re tard.com.invalid>   wrote:

 If you don't have first class tuple constructors and define them with
 a template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Could you please take the time to put together a list of requirements? That would be great for either making Tuple better or for improving the language.
Sure, but I can't really promise to have to capacity to think about every possible case when we are discussing D. There are so many complex features! I think a more or less complete list can already be constructed from all past discussions here. The tuple issues come up every now and then.
Yah, and it might be the case that we're too close to the matter sometimes. A simple out-of-the-box list should help. I'd start it like this: - must contain an unlimited number of values, including non-distinct types etc. - should be first-class values (e.g. array of tuples or returning tuples should require no tricks) - should support controlled expansion, i.e. I decide when the tuple "explodes" whereas everywhere else it's a sheer value. Consider: void foo(T)(T obj); void foo(T, U)(T obj1, U obj2); foo(tuple(1, 2.2)); Which function should be called? Any way we go, we should be able to call the first overload (because tuples are first-class values!!! the circle closes!!!) but we should also be able to call the second overload if we so want. (By sheer luck, Tuple currently supports that beautifully: foo(tuple(1, 2.2)) calls the first overload and foo(tuple(1, 2.2).expand) calls the second one.) - should support coherent conversion and perhaps subtyping, taking projections (slices), cross-product (concatenation) - should be easy to use, terse, and self-explanatory - should support simple "gathering" (assigning from various values) and "scattering" (assigning to various values) What else?
 FWIW, the library provided solution with syntactical support doesn't
 sound so bad now that I think about it. We just need to know, what we are
 trying to solve here. The bigger problems come up when overloading the
 same system with mixed value/type/alias tuples.
I, too, have learned to appreciate library solutions more because I realized a few things. One, I really don't need to explain what this is: auto x = tuple(1, 2.3); or this Tuple!(int, double) y; or this auto z = tuple("hello"); I mean it's as there as it gets. But I will need some explaining and some head scratching to figure this: auto z = ("hello",); and this: auto t = (); and this: (int, double) foo(bool(int, double) bar); Library tuples rule. Andrei
Oct 07 2010
parent reply retard <re tard.com.invalid> writes:
Thu, 07 Oct 2010 14:11:21 -0500, Andrei Alexandrescu wrote:

 On 10/7/10 13:56 CDT, retard wrote:
 Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote:

 On 10/7/10 13:44 CDT, retard wrote:
 Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:

 retard<re tard.com.invalid>   wrote:

 If you don't have first class tuple constructors and define them
 with a template, that's unfortunately not structural typing.
Might I inquire as to why?
I see these "tuples" defined with a template merely as structs in disguise. They don't cover all the cases where built-in first class tuples can be used.
Could you please take the time to put together a list of requirements? That would be great for either making Tuple better or for improving the language.
Sure, but I can't really promise to have to capacity to think about every possible case when we are discussing D. There are so many complex features! I think a more or less complete list can already be constructed from all past discussions here. The tuple issues come up every now and then.
Yah, and it might be the case that we're too close to the matter sometimes. A simple out-of-the-box list should help. I'd start it like this: - must contain an unlimited number of values, including non-distinct types etc. - should be first-class values (e.g. array of tuples or returning tuples should require no tricks) - should support controlled expansion, i.e. I decide when the tuple "explodes" whereas everywhere else it's a sheer value. Consider: void foo(T)(T obj); void foo(T, U)(T obj1, U obj2); foo(tuple(1, 2.2)); Which function should be called? Any way we go, we should be able to call the first overload (because tuples are first-class values!!! the circle closes!!!) but we should also be able to call the second overload if we so want. (By sheer luck, Tuple currently supports that beautifully: foo(tuple(1, 2.2)) calls the first overload and foo(tuple(1, 2.2).expand) calls the second one.) - should support coherent conversion and perhaps subtyping, taking projections (slices), cross-product (concatenation) - should be easy to use, terse, and self-explanatory - should support simple "gathering" (assigning from various values) and "scattering" (assigning to various values) What else?
Looks really good IMO. The same .expand (or some other "method") should probably also work when dealing with tuples of types. I didn't look how it works now. The auto- flattening isn't always desirable. I guess the other places of confusion are interaction with built-in statements and other features, e.g. auto foo = (1,2,3); auto bar = [foo]; Should there be some way to construct a [1,2,3] array from the tuple or should the only be a way to construct arrays of the type tuple!(int)[] or something similar. The auto-flattening could be used in quite many places (as cases in switches etc.)
Oct 07 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
retard <re tard.com.invalid> wrote:
 I guess the other places of confusion
 are interaction with built-in statements and other features, e.g.

 auto foo = (1,2,3);

 auto bar = [foo];

 Should there be some way to construct a [1,2,3] array from the tuple or
 should the only be a way to construct arrays of the type tuple!(int)[] or
 something similar.
The obvious way to do this: CommonType!T buildArray( T... )( T arg ) { return [ arg ]; } auto foo = tuple( 1, 2, 3 ); auto bar = buildArray( foo.expand ); -- Simen
Oct 07 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 15:45 CDT, Simen kjaeraas wrote:
 retard <re tard.com.invalid> wrote:
 I guess the other places of confusion
 are interaction with built-in statements and other features, e.g.

 auto foo = (1,2,3);

 auto bar = [foo];

 Should there be some way to construct a [1,2,3] array from the tuple or
 should the only be a way to construct arrays of the type tuple!(int)[] or
 something similar.
The obvious way to do this: CommonType!T buildArray( T... )( T arg ) { return [ arg ]; } auto foo = tuple( 1, 2, 3 ); auto bar = buildArray( foo.expand );
Nice. Actually buildArray already exists - it's called array() and it sits in std.array. Andrei
Oct 07 2010
prev sibling parent Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
Simen kjaeraas napisał:

 retard <re tard.com.invalid> wrote:
 I guess the other places of confusion
 are interaction with built-in statements and other features, e.g.

 auto foo = (1,2,3);

 auto bar = [foo];

 Should there be some way to construct a [1,2,3] array from the tuple or
 should the only be a way to construct arrays of the type tuple!(int)[] or
 something similar.
The obvious way to do this: CommonType!T buildArray( T... )( T arg ) { return [ arg ]; } auto foo = tuple( 1, 2, 3 ); auto bar = buildArray( foo.expand );
From a different angle: auto range = byFields(tuple(1,2,3)); It should take structs, classes, maybe unions. Of course, front() = 5 should update the source tuple. Feed it to std.(algorithm|range) for the win! Also, I'd like to see two flavors: byFields!(UnificationStrategy.CommonType)(...); // default byFields!(UnificationStrategy.Variant)(...); // wrappers -- Tomek
Oct 07 2010
prev sibling next sibling parent reply Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
Andrei Alexandrescu napisał:

 On the client side the syntax is very light. The definition of the
 function would need to specify the type name:
 
 Tuple!(int, "foo", string, "bar") fun(int) {
 ...
 }
Blue sky idea -- anonymous structs: struct { int foo; string bar; } fun(int) { ... } They already exist but are allowed only as members of other structs/unions. Then again, it's still a language trip-up, like we don't have enough of those already.
 I think much of the list of grievances against tuple limitations stems
 from a feeling that doing tuples without special syntax is "cheating".
 For my money, library tuples are eminently usable, and once we fix a
 couple of compiler bugs, they will be as good as (if not simpler,
 richer, and clearer than) a built-in facility.
Amen.
 I do want to introduce
 syntax for expansion a la
 
 auto (a, b) = foo(42);

 because that's a common need that's not satisfiable via a library.
Nice, but I can live without that.
 But
 then I want to define the syntax in a general way so it works not only
 with tuples, but also with arrays and types that implement opIndex.
There's a tangent issue with std.typecons.Tuple: int[2] ints; Tuple!(int, int) t = ints; Minor, but should work. -- Tomek
Oct 07 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 15:27 CDT, Tomek Sowiński wrote:
 There's a tangent issue with std.typecons.Tuple:

 int[2] ints;
 Tuple!(int, int) t = ints;

 Minor, but should work.
Yah, good point. Could you please add that to bugzilla so we don't forget? Feel free to assign to me (my first name at metalanguage dot con). Andrei
Oct 07 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I do want to introduce syntax for expansion a la

 auto (a, b) = foo(42);

 because that's a common need that's not satisfiable via a library. But  
 then I want to define the syntax in a general way so it works not only  
 with tuples, but also with arrays and types that implement opIndex.
Philippe Sigaud's reftuple[1] from dranges does that first part: int a, b; _(a,b) = tuple(b,a); // swap _(a,b) = tuple(b,a+b); // fibonacci [1]: http://svn.dsource.org/projects/dranges/trunk/dranges/docs/reftuple.html -- Simen
Oct 07 2010
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-10-07 04:20:23 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Sorry for being Debbie Downer in this thread, but I'm not seeing a lot 
 of progress here. This is nothing but a syntax cutesy that helps 
 Tuple!(A, B) and tuple(a, b) and leaves all other issues related to 
 tuples unresolved (I'm actually afraid that it exacerbates them).
 
 One good thing about Tuple is that it allows names of fields, so 
 functions can return tuples with conveniently named fields, e.g. 
 Tuple!(bool, "found", size_t, "position") etc. without having to define 
 little structs everywhere and fostering simple, clear code on the 
 caller side.
I've always found tuples with named arguments awkward. I mean, a tuple is a list of
 Also, obviously, empty tuples and tuples with one element are 
 self-explanatory (Tuple!() and Tuple!(int) for types, tuple() and 
 tuple(4) for values).
And then you have TypeTuple!(...) for tuples of types or statically-known values. The basic problem is that all these different syntaxes define slight variations of the same core tuple concept. Giving a true syntax for tuples makes things *simpler* by reducing these variations. For instance, a TypeTuple!(int, int) isn't the same thing as Tuple!(int, int). Why is it so? Because of an implementation detail: one defines the core language tuple and the other defines a wrapper struct around the core tuple that implements what's basically missing in the core tuple implementation (returning from a function). With Walter changes I expect you'll be able to call a function this way (simply because this is actually what happens when you use a real tuple in D): auto a = (1, 2); func(a); // same as func(a[0], a[1]); Or you could have some kind of filter function that takes arbitrary arguments and transform them somehow before passing them to another function. For instance: auto square(T...)(T tuple) { foreach (ref element; tuple) element ^= 2; return tuple; } writefln("%d %d %d %d %d", square(1,2,3,4,5)); // prints "1 4 9 16 25" I'm not inventing anything. This is exactly how the core language tuples work today in D. It's already possible to have core language tuples in variables (try creating a variable of type TypeTuple!(int, int), it works!). The only two things Walter is proposing to implement is tuple literals and tuple returns for functions. And, if I'm guessing right, this syntax will also work: int a; float b; (a, b) = func(); // func returns a (int, float) which is directly // stored in the right variables This has been proven very useful in languages that supports it; heck, even C++ has this feature with boost::tie. I assume it'll work because, well, it already works if the tuple isn't the return value of a function call: TypeTuple!(a, b) = TypeTuple!(1, 2); TypeTuple!(a, b) = tuple(1, 2).fields;
 Up until recently the syntax t[i] didn't work for tuples, forcing 
 t.field[i]. This marginally improves usage of tuples. There are still 
 other issues left due to compiler bugs; for example slicing t[a .. b] 
 is supposed to work but it doesn't. But my question is, do we need more 
 notation, more special cases, more ambiguities, more solution to 
 ambiguities, more corner cases (there's already a request for handling 
 void in a particular way)...? And for what? Quite literally because we 
 refuse to call a tuple a tuple? I'm not seeing much gain here. 
 Syntactic sugar is good in moderate quantities, but in Perlis' words 
 this is bound to cause cancer of the semicolon.
I find it hard to see how obsoleting one of the two tuple concepts (the one in Phobos) and keeping only the core language tuple will introduce more bugs. The tuple concept is already at the core of the language, and it is quite needed there too for metaprogramming an other stuff. We can't remove it, so let's improve it instead of layering a wrapper over it, giving it same name, and making things more confusing for everyone. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 07 2010
prev sibling next sibling parent reply Justin Johansson <3.1415926536 bingmail.com> writes:
On 7/10/2010 5:04 PM, Walter Bright wrote:
 There have been a couple of looong threads about tuples:

 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html

 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html

 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is
Walter, please define exactly what a tuple is as being, both in the context of your post and (presumably) in the D type system. Without a precise definition of exactly what a tuple is, your post will at best elucidate responses that also lack a precise understanding of a tuple is (supposed to be). There are already a number of responses to your post that focus on syntax and without any semantic foundation. Regards, Justin Johansson
Oct 07 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 7:23 CDT, Justin Johansson wrote:
 On 7/10/2010 5:04 PM, Walter Bright wrote:
 There have been a couple of looong threads about tuples:

 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html


 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html


 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is
Walter, please define exactly what a tuple is as being, both in the context of your post and (presumably) in the D type system. Without a precise definition of exactly what a tuple is, your post will at best elucidate responses that also lack a precise understanding of a tuple is (supposed to be). There are already a number of responses to your post that focus on syntax and without any semantic foundation.
Wise words! It was exactly what I protested against. It discusses syntax without attacking any of the actual issues. Andrei
Oct 07 2010
prev sibling next sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
I might be missing something, but how does this proposal get around the 
ambiguity in

(a,b,c)[0]

?

Currently, it's valid C syntax and valid D syntax. In your proposal it 
would be valid tuple syntax too.

On 10/07/2010 01:04 AM, Walter Bright wrote:
 There have been a couple of looong threads about tuples:

 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html


 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html


 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is

 (expression)

 Is that a parenthesized expression, or a tuple? This really matters,
 since (e)[0] means very different things for the two. Finally, I got to
 thinking, why not just make it a special case:


 ( ) == tuple
 (a) == parenthesized expression
 (a,b) == tuple
 (a,b,c) == tuple
 (a,b,c,d) == tuple

 etc.

 No ambiguities! Only one special case. I submit this special case is
 rare, because who wants to define a function that returns a tuple of 1?
 Such will come about from generative programming, but:

 (a,b,c)[0]

 may be how the generative programming works, and that suggests:

 (a,0)[0]

 as how a user could generate a tuple of 1. Awkward, sure, but like I
 said, I think this would be rare.
Oct 07 2010
next sibling parent Justin Johansson <no spam.com> writes:
On 8/10/2010 12:23 AM, Ellery Newcomer wrote:
 I might be missing something, but how does this proposal get around the
 ambiguity in

 (a,b,c)[0]

 ?

 Currently, it's valid C syntax and valid D syntax. In your proposal it
 would be valid tuple syntax too.
Sorry Ellery but you, as others, are also focusing on syntax and not a semantic foundation for what tuples are. I note that bearophile makes similar points about the meaning of tuples in a latter post. Without understanding what the meaning of tuples is and what they might be good for, it (imho) doesn't make sense to enter into syntactic arguments. Justin
Oct 07 2010
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
Ellery Newcomer wrote:
 I might be missing something, but how does this proposal get around the 
 ambiguity in
 
 (a,b,c)[0]
 
 ?
 
 Currently, it's valid C syntax and valid D syntax. In your proposal it 
 would be valid tuple syntax too.
As has been proposed frequently, the , operator would have to be dispensed with.
Oct 07 2010
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Oct 2010 13:52:56 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 Ellery Newcomer wrote:
 I might be missing something, but how does this proposal get around the  
 ambiguity in
  (a,b,c)[0]
  ?
  Currently, it's valid C syntax and valid D syntax. In your proposal it  
 would be valid tuple syntax too.
As has been proposed frequently, the , operator would have to be dispensed with.
I think what Ellery is alluding to is it breaks the rule that things that are valid C syntax do the same thing that happens in C. Of course we've broken this rule a few times. -Steve
Oct 07 2010
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

 As has been proposed frequently, the , operator would have to be dispensed
with.
This makes the -cstyle compiler switch more useful than before :-) Bye, bearophile
Oct 07 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Walter Bright <newshound2 digitalmars.com> wrote:

 (a,b,c)[0]

 may be how the generative programming works, and that suggests:

 (a,0)[0]

 as how a user could generate a tuple of 1. Awkward, sure, but like I  
 said, I think this would be rare.
Wouldn't (a,0)[0] currently return a, not (a)? The syntax that behaves as you describe would be slicing: (a,0)[0..1]. This said, read bearophile's post "Re: Tuple literal syntax + Tuple assignment". It seems well thought-out, and I agree with all his points. -- Simen
Oct 07 2010
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
Andrei Alexandrescu Wrote:

 struct Coord
 {
      int x, y, z;
 }
 
 one iota typesafer than
 
 alias Tuple!(int, "x", int, "y", int, "z") Coord;
Is there a real need for an alternative way to declare structs?
Oct 07 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/7/10 10:13 CDT, Kagamin wrote:
 Andrei Alexandrescu Wrote:

 struct Coord
 {
       int x, y, z;
 }

 one iota typesafer than

 alias Tuple!(int, "x", int, "y", int, "z") Coord;
Is there a real need for an alternative way to declare structs?
Yes. Andrei
Oct 07 2010
parent reply Stephan Soller <stephan.soller helionweb.de> writes:
On 07.10.2010 17:36, Andrei Alexandrescu wrote:
 On 10/7/10 10:13 CDT, Kagamin wrote:
 Andrei Alexandrescu Wrote:

 struct Coord
 {
 int x, y, z;
 }

 one iota typesafer than

 alias Tuple!(int, "x", int, "y", int, "z") Coord;
Is there a real need for an alternative way to declare structs?
Yes. Andrei
I agree but I also don't agree. I like the possibility to return multiple values (quite handy in Ruby, PHP and other languages) and therefore we need language constructs to group multiple values and ungroup them again. However as soon as these fields are named it looks to me like an ordinary structure. So why not just create something like an "anonymous structure literal" that behaves to structures like anonymous functions (or delegates) to functions? This would look a lot more consistent to me than playing around with different kinds of tuples. However I'm not sure about the details (e.g. how would such structures handle type or alias contents). Happy programming Stephan
Oct 10 2010
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 10 Oct 2010 17:39:52 +0400, Stephan Soller  
<stephan.soller helionweb.de> wrote:

 On 07.10.2010 17:36, Andrei Alexandrescu wrote:
 On 10/7/10 10:13 CDT, Kagamin wrote:
 Andrei Alexandrescu Wrote:

 struct Coord
 {
 int x, y, z;
 }

 one iota typesafer than

 alias Tuple!(int, "x", int, "y", int, "z") Coord;
Is there a real need for an alternative way to declare structs?
Yes. Andrei
I agree but I also don't agree. I like the possibility to return multiple values (quite handy in Ruby, PHP and other languages) and therefore we need language constructs to group multiple values and ungroup them again. However as soon as these fields are named it looks to me like an ordinary structure. So why not just create something like an "anonymous structure literal" that behaves to structures like anonymous functions (or delegates) to functions? This would look a lot more consistent to me than playing around with different kinds of tuples. However I'm not sure about the details (e.g. how would such structures handle type or alias contents). Happy programming Stephan
Exactly. To be honest, I see absolutely no reason to have yet another to declare structs, but some people have other preferences. I don't mind having Tuple in a library, as long as I'm not insisted in using it *and* it doesn't affect other language features. I mean, it's not even shorter to write alias Tuple!(int, "x", int, "y", int, "z") Coord; than struct Coord { int x; int y; int z; }
Oct 10 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Denis Koroskin:

 I don't mind having Tuple in a library, as long as I'm not insisted in  
 using it *and* it doesn't affect other language features.
More modern module-based languages as D are not like C. If they want some success they develop a community of programmers that share modules. You don't program in a vacuum any more. This means that if Tuple is appreciated and used by the community, then you will often use modules (including frequently stuff from Phobos2) written by other people that expect tuples as input values or that return tuples as outputs and so on. So if tuples have success, you will probably need to use them in your code too, they become an idiom of the language almost as they are built-ins, this is also why it's better to give them a good syntax. Multiple return values have the disadvantage that sometimes your don't exactly remember what each value is, but they are handy, and overall they are an improvement over C-style single return values. In a recent post I've shown why they may also help avoid some bugs compared to "out" arguments. Bye, bearophile
Oct 10 2010
parent "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 10 Oct 2010 18:33:35 +0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Denis Koroskin:

 I don't mind having Tuple in a library, as long as I'm not insisted in
 using it *and* it doesn't affect other language features.
More modern module-based languages as D are not like C. If they want some success they develop a community of programmers that share modules. You don't program in a vacuum any more. This means that if Tuple is appreciated and used by the community, then you will often use modules (including frequently stuff from Phobos2) written by other people that expect tuples as input values or that return tuples as outputs and so on. So if tuples have success, you will probably need to use them in your code too, they become an idiom of the language almost as they are built-ins, this is also why it's better to give them a good syntax. Multiple return values have the disadvantage that sometimes your don't exactly remember what each value is, but they are handy, and overall they are an improvement over C-style single return values. In a recent post I've shown why they may also help avoid some bugs compared to "out" arguments. Bye, bearophile
I was referring *only* to Tuple!(int, "foo", float, "bar") syntax. I'd love having proper tuples (Python-style or similar) support in D, and use it to the maximum. But Tuple!? Meh.
Oct 10 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/10 9:00 CDT, Denis Koroskin wrote:
 On Sun, 10 Oct 2010 17:39:52 +0400, Stephan Soller
 <stephan.soller helionweb.de> wrote:

 On 07.10.2010 17:36, Andrei Alexandrescu wrote:
 On 10/7/10 10:13 CDT, Kagamin wrote:
 Andrei Alexandrescu Wrote:

 struct Coord
 {
 int x, y, z;
 }

 one iota typesafer than

 alias Tuple!(int, "x", int, "y", int, "z") Coord;
Is there a real need for an alternative way to declare structs?
Yes. Andrei
I agree but I also don't agree. I like the possibility to return multiple values (quite handy in Ruby, PHP and other languages) and therefore we need language constructs to group multiple values and ungroup them again. However as soon as these fields are named it looks to me like an ordinary structure. So why not just create something like an "anonymous structure literal" that behaves to structures like anonymous functions (or delegates) to functions? This would look a lot more consistent to me than playing around with different kinds of tuples. However I'm not sure about the details (e.g. how would such structures handle type or alias contents). Happy programming Stephan
Exactly. To be honest, I see absolutely no reason to have yet another to declare structs, but some people have other preferences. I don't mind having Tuple in a library, as long as I'm not insisted in using it *and* it doesn't affect other language features. I mean, it's not even shorter to write alias Tuple!(int, "x", int, "y", int, "z") Coord; than struct Coord { int x; int y; int z; }
Tuples with named fields are restricted in a number of ways compared to structs. They are expandable, they have indexed fields, they offer no encapsulation, etc. Lambda structs would be rather unwieldy. I personally am fine with tuples. Andrei
Oct 10 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 Tuples with named fields are restricted in a number of ways compared to 
 structs. They are expandable, they have indexed fields, they offer no 
 encapsulation, etc. Lambda structs would be rather unwieldy. I 
 personally am fine with tuples.
Now the discussion is developing in a slower and more relaxed way. Have Walter and you reached some partial conclusion on this subject? I am not asking for the final words on this topic, because I probably few further discussions will be needed, but other people and I have already expressed several opinions and ideas. I think that multiple return values and a nice clean packing & unpacking syntax for tuples may be useful for D (especially if it can be used for unpacking in foreach and function signatures too). And It's just syntax sugar, yet I think a good syntax sugar for this is able to change the taste of the D language, because if it's good and efficient, it will probably be used very often, in normal Python code it's not hard to find one or more tuples every 3-8 lines of code, a normal Python module may contain a fifty tuple literals (often just as "return x, y"). Bye, bearophile
Oct 10 2010
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Whatever the conclusion on all this is, may I suggest to have a way to
concatenate tuples?

auto t1 = tuple(1, "a");                   // or (|1, "a"|) or {1,
"a"} or what have you.
auto t2 = tuple((int i, string s) { return i;});

auto result = t1 ~ t2;

result is a (int,string, int function(int,string)) tuple.

Ideally, you should also be able to add any value before or after a tuple.

auto result2 = 3.1415 ~ result;

This is easily added to std.typecons.Tuple with opBinary!"~".
Oct 10 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Philippe Sigaud:

 may I suggest to have a way to concatenate tuples?
I have implemented it, see enhancement request 4591 Bye, bearophile
Oct 10 2010
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Oct 10, 2010 at 23:05, bearophile <bearophileHUGS lycos.com> wrote:
 Philippe Sigaud:

 may I suggest to have a way to concatenate tuples?
I have implemented it, see enhancement request 4591
Cool, I'll have a look. *does so* Wow, much more complicated that what I had in mind. I totally forgot about named fields. Philippe
Oct 10 2010
prev sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Stephan Soller <stephan.soller helionweb.de> wrote:

 However as soon as these fields are named it looks to me like an  
 ordinary structure. So why not just create something like an "anonymous  
 structure literal" that behaves to structures like anonymous functions  
 (or delegates) to functions?
Perhaps it would be possible to augment struct static initializers for this purpose? { int a; string b } foo( ) { return { 1, "text" }; } I'm not sure if there are problems with this syntax (it sorta looks like a delegate, for one), so elucidation would be welcome. -- Simen
Oct 10 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Simen kjaeraas:

 Perhaps it would be possible to augment struct static initializers for
 this purpose?
 
 { int a; string b } foo( ) {
      return { 1, "text" };
 }
What kind of tuple unpacking syntax do you suggest for this? (I think at the moment the unpacking syntax is more important than the literals one). Bye, bearophile
Oct 10 2010
parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
bearophile <bearophileHUGS lycos.com> wrote:

 Simen kjaeraas:

 Perhaps it would be possible to augment struct static initializers for
 this purpose?

 { int a; string b } foo( ) {
      return { 1, "text" };
 }
What kind of tuple unpacking syntax do you suggest for this? (I think at the moment the unpacking syntax is more important than the literals one).
int a; string b; { a, b } = foo( ); string s = "123456" char c; { c, s... } = s; I guess. -- Simen
Oct 10 2010
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-10-07 02:04:35 -0400, Walter Bright <newshound2 digitalmars.com> said:

 There have been a couple of looong threads about tuples:
 
 http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html
http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html A
 
 lot of it foundered on what the syntax for tuple literals should be. 
 The top of the list is simply enclosing them in ( ). The problem with 
 this is
 
   (expression)
 
 Is that a parenthesized expression, or a tuple? This really matters, 
 since (e)[0] means very different things for the two.
 Finally, I got to thinking, why not just make it a special case:
 
 
   ( ) == tuple
   (a) == parenthesized expression
   (a,b) == tuple
   (a,b,c) == tuple
   (a,b,c,d) == tuple
 
 etc.
Seems good. I know some people have complained about the lack of a semantic foundation, but my understanding is that this is simply a syntax to define the same kind of tuple as you get with variadic template arguments or variables made from types defined as variadic template arguments. The semantic foundation is already there and in use with variadic templates, it just lacks a few features (literals and the ability to be a return type). If this can be used in place of both Tuple!() and TypeTuple!() defined in Phobos, then it'll be great as we'll no longer need to have two distinct tuple concepts: one in the language and another Tuple!() wrapper that sits top of it just so we can return a tuple from a function. For the syntax, I'd like to second Juanjo's suggestion to mimic Python for the one-element tuple: (a,) == tuple And Don's extension of that suggestion that it always accept a trailing comma like enums and array literals: (a,b,) == tuple (a,b,c,) == tuple -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 07 2010
prev sibling next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Wed, 06 Oct 2010 23:04:35 -0700, Walter Bright wrote:

 There have been a couple of looong threads about tuples:
 
 http://www.digitalmars.com/d/archives/digitalmars/D/
Reddit_why_aren_t_people_using_D_93528.html
 
 http://www.digitalmars.com/d/archives/digitalmars/D/
Should_the_comma_operator_be_removed_in_D2_101321.html
 
 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is
 
   (expression)
 
 Is that a parenthesized expression, or a tuple? This really matters,
 since (e)[0] means very different things for the two. Finally, I got to
 thinking, why not just make it a special case:
 
 
   ( ) == tuple
   (a) == parenthesized expression
   (a,b) == tuple
   (a,b,c) == tuple
   (a,b,c,d) == tuple
 
 etc.
 
 No ambiguities! Only one special case. I submit this special case is
 rare, because who wants to define a function that returns a tuple of 1?
 Such will come about from generative programming, but:
 
 (a,b,c)[0]
 
 may be how the generative programming works, and that suggests:
 
 (a,0)[0]
 
 as how a user could generate a tuple of 1. Awkward, sure, but like I
 said, I think this would be rare.
--vote; Personally, I don't think we should start adding a dedicated tuple syntax at this point. There are so many things that are more important, and besides, I think the library tuples are pretty cool. We should instead focus on making Tuple!(...) even better. -Lars
Oct 07 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:

 Personally, I don't think we should start adding a dedicated tuple syntax 
 at this point.  There are so many things that are more important, and 
 besides, I think the library tuples are pretty cool.  We should instead 
 focus on making Tuple!(...) even better.
Tuples are a basic part of a language, they need to come before web tools, loggers, numeric libraries and so on. You build Phobos and all those things with a language. So if the language is better, you will work better. From what I've seen so far in this thread the Tuple/Record library solution will be kept, but some built-in syntax sugar (unpacking, and maybe for the literals) helps in making tuple usage more handy and clean. Bye, bearophile
Oct 08 2010
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday 08 October 2010 03:30:35 bearophile wrote:
 Lars T. Kyllingstad:
 Personally, I don't think we should start adding a dedicated tuple syntax
 at this point.  There are so many things that are more important, and
 besides, I think the library tuples are pretty cool.  We should instead
 focus on making Tuple!(...) even better.
Tuples are a basic part of a language, they need to come before web tools, loggers, numeric libraries and so on. You build Phobos and all those things with a language. So if the language is better, you will work better.
Agreed. But that doesn't mean that library solution isn't the best solution. - Jonathan M Davis
Oct 08 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Fri, 08 Oct 2010 06:30:35 -0400, bearophile wrote:

 Lars T. Kyllingstad:
 
 Personally, I don't think we should start adding a dedicated tuple
 syntax at this point.  There are so many things that are more
 important, and besides, I think the library tuples are pretty cool.  We
 should instead focus on making Tuple!(...) even better.
Tuples are a basic part of a language, they need to come before web tools, loggers, numeric libraries and so on. [...]
I know, and I agree that *if* it is decided that tuples should be added to the language, it has to happen now. I just don't think it's necessary to do it at all. -Lars
Oct 08 2010
prev sibling parent Justin Johansson <no spam.com> writes:
On 8/10/2010 9:30 PM, bearophile wrote:
 Lars T. Kyllingstad:

 Personally, I don't think we should start adding a dedicated tuple syntax
 at this point.  There are so many things that are more important, and
 besides, I think the library tuples are pretty cool.  We should instead
 focus on making Tuple!(...) even better.
Tuples are a basic part of a language, they need to come before web tools, loggers, numeric libraries and so on. You build Phobos and all those things with a language. So if the language is better, you will work better. From what I've seen so far in this thread the Tuple/Record library solution will be kept, but some built-in syntax sugar (unpacking, and maybe for the literals) helps in making tuple usage more handy and clean.
People responding on this thread still allude the basic question about exactly a tuple is supposed to be. This discussion is hitherto pointless. I think Andrei is in agreement .. here's the transcript from earlier on in this thread. Cheers Justin Johansson (prior transcript follows) On 10/7/10 7:23 CDT, Justin Johansson wrote:
 On 7/10/2010 5:04 PM, Walter Bright wrote:
 There have been a couple of looong threads about tuples:

 
http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.html
 
http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html
 A lot of it foundered on what the syntax for tuple literals should be.
 The top of the list is simply enclosing them in ( ). The problem with
 this is
Walter, please define exactly what a tuple is as being, both in the context of your post and (presumably) in the D type system. Without a precise definition of exactly what a tuple is, your post will at best elucidate responses that also lack a precise understanding of a tuple is (supposed to be). There are already a number of responses to your post that focus on syntax and without any semantic foundation.
Wise words! It was exactly what I protested against. It discusses syntax without attacking any of the actual issues. Andrei
Oct 08 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Lars T. Kyllingstad:

I know, and I agree that *if* it is decided that tuples should be added to the
language, it has to happen now.  I just don't think it's necessary to do it at
all.<
A better built-in support for tuples is a form of syntax sugar, this means it doesn't give you more power, it doesn't give you ways to do things you were unable to do before. So it's not necessary. On the other hand sometimes it's good to have some syntax sugar, because when it's well chosen it may allow you to write less bug-prone code, to write more readable code, to write less code, and sometimes even to write more efficient code, etc. Some syntax to support tuples better is (mostly) an additive change, this means that tuple syntax may be added to D3 instead of D2. There is no need to add it now. But it's a basic language feature, so it's better to add it soon, and allow people that write Phobos to use and enjoy it sooner. As with many other language features, it's not easy to understand how much useful (or how much useless) a feature is if you have never used it before for some time. For example I have heard about Design by Contract before trying it in D, but I have never used it for real before trying it for months in D and discussing about it for months in this newsgroup. Now I am sold and I use a poor's man DbC even in my Python code, and I think it's very useful, and I've asked for this PEP to be implemented when Python will come out of its current design hiatus (http://www.python.org/dev/peps/pep-0316/ ). This means that if you have not used tuples much in other languages, then it will be hard for you to understand why they are useful and good to have. Sometimes it happens that a feature X that's very useful in language Y is not so useful in language Z, so you need care to avoid adding it to Z. Currently std.typecons.tuple is useful for several different purposes, but in my opinion, on the base of tuple usage I've had in Python (and cons cells in Scheme-like languages), I think its usage is hindered by a lack of a more clean syntax. So I think some syntax sugar may free more potential usages of tuples in D. I presume Walter and Andrei agree on this. Experience has shown me that very often there is a "weight" threshold: if the syntax and semantics needed to use a feature is simple enough and short enough, then many programmers will use it, otherwise it will not be used much even if it's useful. The syntax sugar for tuples is needed to lower enough the "potential barrier" to access tuples to make their usage convenient in many situations. In a single post I can't show you what's good in tuple usage in Python, you need practical usage experience for that. But I can show some of the tuple syntax that may be needed to use tuples at their best, showing what's bad/hard to do now, and how it may become handy/better. We have to keep in mind that tuple usage also has some disadvantages, so there are situations where using tuples makes the program worse. The usage of tuples with unnamed fields as function return values may reduce code readability a bit, making it less explicit. A heavy usage of anonymous tuples is like a heavy usage of anonymous functions, you lose some names, and this worsens your stack traces (where you see labels just like lambda1, lambda2, lambda3, etc instead of semantically meaningful function names), it may worsen your debugging and code readability, etc. Sometimes a language that's easy to write is less easy to read, for example Python dynamic typing allows you to write code faster, but much later the lack of types in function signatures may make it less easy to understand the meaning of the code. If you want to write code that's meant to be debugged and used for many years, then using lots of anonymous tuples may be negative. As most tools, tuples may be abused, so you need to use them with care only where they improve the code or your work. There are two kinds of syntax sugar that may be useful for tuples: syntax to build/define a tuple and syntax to de-structure/match it. A tuple is useful to group and keep related data together, like a struct. The tuple offers a lighter and shorter way to define it, and better ways to de-structure the data later. Tuples are quite useful to allow functions to return multiple values. Returning a single values in C/C++/Java is a silly limitation, in many situations you need to return more than a value. You may use "out" arguments, but they are a HACK, they are semantically unclean, because you may assign a out value outside a function before its call (and this value gets silently ignored and overwritten) and the syntax is unclean, because in mathematics function arguments are things that go inside the function. Usage of languages like Python (and Go) shows you that it's very handy and clean to be able to return two or more values from functions (this means a 2-tuple or 3-tuple). If you return too many items you may lose track of what the function returns, so it's good to limit the number of return values to just few, usually just 1, 2 or 3. In Python there is a built-in function named divmod, given two numbers the quotient and remainder of their integer division. If you want you may redefine (and use) in a naive way it again like this (in Python it's useful if x and y are large multi-precision integers, it reduces a lot the total amount of computations done if you need both results):
 def divmod(x, y):
... return x // y, x % y ...
 d, r = divmod(14, 4)
 print d
3
 print r
2 This is a possible way to do the same thing in D2: import std.stdio: writeln; import std.bigint: BigInt; // std.bigints ridicolously lack a way to print them const(char)[] repr(BigInt i) { const(char)[] result; i.toString((const(char)[] s){ result = s; }, "d"); return result; } void divmod(BigInt x, BigInt y, out BigInt q, out BigInt r) { q = x / y; r = x % y; } void main() { BigInt q, r; // never initialize q and r here divmod(BigInt(14), BigInt(4), q, r); writeln(repr(q)); writeln(repr(r)); } The divmod1() may also return q and use r as out value, but this breaks symmetry in the q and r return values and I don't like it much. You may use std.typecons.tuple: import std.stdio: writeln; import std.bigint: BigInt; import std.typecons: tuple, Tuple; const(char)[] repr(BigInt i) { const(char)[] result; i.toString((const(char)[] s){ result = s; }, "d"); return result; } Tuple!(BigInt, "q", BigInt, "r") divmod(BigInt x, BigInt y) { return typeof(return)(x / y, x % y); } void main() { Tuple!(BigInt, "q", BigInt, "r") q_r = divmod(BigInt(14), BigInt(4)); writeln(repr(q_r.q)); writeln(repr(q_r.r)); } You may also use auto and anonymous fields to shorten the code a little: import std.stdio: writeln; import std.bigint: BigInt; import std.typecons: tuple; const(char)[] repr(BigInt i) { const(char)[] result; i.toString((const(char)[] s){ result = s; }, "d"); return result; } auto divmod(BigInt x, BigInt y) { return tuple(x / y, x % y); } void main() { auto q_r = divmod(BigInt(14), BigInt(4)); writeln(repr(q_r[0])); writeln(repr(q_r[1])); } "auto" reduces the amount of code, but a heavy usage of type inference may make it harder to understand what types your code is using months later when you read your code again. There are few different ways to design the syntax sugar to build and de-structure the tuple used in that program. A possible syntax to build a tuple is just to use tuple() or record(). This is not bad, and it's very readable, but it's a bit long, so if you use tuples in complex expressions this may make your expression too much long. To shorten the syntax a little you may use what Andrei has named banana syntax (using just () to denote tuples is more handy, but it introduces a corner case for 1-tuples and it's not backward compatible with C syntax): auto divmod1(BigInt x, BigInt y) { return (| x / y, x % y |); } Or a syntax that just avoids to use strings to represent field values: Tuple!(BigInt q, BigInt r) divmod(BigInt x, BigInt y) { return typeof(return)(x / y, x % y); } Some possible syntaxes for the unpacking, others may be possible: void main() { auto record(q, r) = divmod1(BigInt(14), BigInt(4)); writeln(repr(q)); writeln(repr(q)); } void main() { (|BigInt q, BigInt r|) = divmod1(BigInt(14), BigInt(4)); writeln(repr(q)); writeln(repr(q)); } void main() { (|auto q, auto r|) = divmod1(BigInt(14), BigInt(4)); writeln(repr(q)); writeln(repr(q)); } void main() { auto (|q, r|) = divmod1(BigInt(14), BigInt(4)); writeln(repr(q)); writeln(repr(q)); } (the versions with and without auto may be allowed at the same time.) This is a function of std.file (Phobos2 of DMD 2.047): void getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm); Introducing tuples more into Phobos its signature becomes: Tuple!(d_time "ftc", d_time "fta", d_time "ftm") getTimes(const string name); Or: Record!(d_time "ftc", d_time "fta", d_time "ftm") getTimes(const string name); With some syntax sugar: Record!(d_time ftc, d_time fta, d_time ftm) getTimes(const string name); Or: (|d_time ftc, d_time fta, d_time ftm|) getTimes(const string name); Once you have added the unpackign syntax you may call that function as: void main() { // Here I have used "fc" != "ftc" (|d_time fc, d_time fa, d_time fm|) = getTimes("filename"); } Or just like this, that is short and sometimes good enough: void main() { auto (|fc, fa, fm|) = getTimes("filename"); } That's syntax sugar for something like: void main() { auto __temp1 = getTimes("filename"); d_time fc = __temp1.field[0]; d_time fa = __temp1.field[1]; d_time fm = __temp1.field[2]; } In Python2 nested unpacking too is available, and it may be supported by D too: (|int x, (|int y, int z|)|) = foo(); An unpacking syntax for Tuples is useful to replace the very similar zip() and lockstep(): import std.algorithm, std.stdio, std.range; void main() { foreach (p; zip([1, 2, 3], "abcd")) writeln(p._0, " ", p.length, " ", p._1); writeln(); foreach (i, a, b; lockstep([1, 2, 3], "abcd")) writeln(i, " ", a, " ", b); } with a single zip() that may be used for both situations: import std.algorithm, std.stdio, std.range; void main() { foreach (p; zip([1, 2, 3], "abcd")) writeln(p[0], " ", p[1]); writeln(); foreach ((a, b); zip([1, 2, 3], "abcd")) writeln(a, " ", b); } As in Python: for p in zip([1, 2, 3], "abcd"): print p[0], p[1] print for (a, b) in zip([1, 2, 3], "abcd"): print a, b (The zip() is a very commonly useful higher order function.) A related handy feature, present in Python2 is de-structuring (unpacking) in function signature (this is a small amount of pattern matching that's missing in Python3):
 def foo((x, y), z): print y
...
 foo("ab", 2)
b Walter has also suggested a syntax that is often useful in functional programming, to de-structure the head and tail (car and crd) of sequences (something similar is present in Python3 and absent in Python2): auto (|car, cdr...|) = expr; This is not a complete introduction to tuple usefulness, but it gives you some ideas. If you have questions, feel free to ask. Bye, bearophile
Oct 08 2010
parent reply so <so so.do> writes:
 ...
 auto (|car, cdr...|) = expr;

 This is not a complete introduction to tuple usefulness, but it gives  
 you some ideas. If you have questions, feel free to ask.

 Bye,
 bearophile
The syntax is too ugly, i don't know how you call it "sugar" :) Sorry for the one liner. (Though it is not a one liner anymore!) -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Oct 09 2010
next sibling parent Justin Johansson <no spam.com> writes:
On 9/10/2010 7:29 PM, so wrote:
 The syntax is too ugly, i don't know how you call it "sugar" :)
Perhaps "saccharin" then? :-)
Oct 09 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
so:

 The syntax is too ugly, i don't know how you call it "sugar" :)
If you take a look at Fortress you may see how much they use that kind of syntax. And they are able to convert the ASCII code into more elegant pages that use special chars. It's a clean syntax, I think it has no corner cases, I think it doesn't collide with C comma syntax operator, and it's shorter than the range()/tuple() syntax. So I don't agree with you :-) Bye, bearophile
Oct 09 2010
parent reply so <so so.do> writes:
This must have been answered many times already but i shamelessly ask once  
again..
What is the problem with :

[a, b, [c, d], e...]

At first glance it doesn't have the cases braces have and it looks much  
better.

Thanks!

On Sat, 09 Oct 2010 16:08:17 +0300, bearophile <bearophileHUGS lycos.com>  
wrote:

 so:

 The syntax is too ugly, i don't know how you call it "sugar" :)
If you take a look at Fortress you may see how much they use that kind of syntax. And they are able to convert the ASCII code into more elegant pages that use special chars. It's a clean syntax, I think it has no corner cases, I think it doesn't collide with C comma syntax operator, and it's shorter than the range()/tuple() syntax. So I don't agree with you :-) Bye, bearophile
-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Oct 09 2010
parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
so <so so.do> wrote:

 This must have been answered many times already but i shamelessly ask  
 once again..
 What is the problem with :

 [a, b, [c, d], e...]

 At first glance it doesn't have the cases braces have and it looks much  
 better.
Uhm, it's an array? That is, the syntax is already taken and means something else. -- Simen
Oct 09 2010
parent so <so so.do> writes:
Hahaa! Thanks for quick answer. I sometimes forget this is D, not C.

On Sat, 09 Oct 2010 21:27:29 +0300, Simen kjaeraas  
<simen.kjaras gmail.com> wrote:

 so <so so.do> wrote:

 This must have been answered many times already but i shamelessly ask  
 once again..
 What is the problem with :

 [a, b, [c, d], e...]

 At first glance it doesn't have the cases braces have and it looks much  
 better.
Uhm, it's an array? That is, the syntax is already taken and means something else.
-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Oct 09 2010