digitalmars.D - Tuple literal syntax
- Walter Bright (23/23) Oct 06 2010 There have been a couple of looong threads about tuples:
- Kagamin (1/1) Oct 06 2010 Don't function arguments also comprise a tuple? A tuple of 1.
- Walter Bright (2/3) Oct 06 2010 Yes, but that's not ambiguous.
- Jonathan M Davis (6/44) Oct 06 2010 As long as you can define () to use tuples in an unambiguous manner, I'm...
- Juanjo Alvarez (6/9) Oct 07 2010 I said, I
- Don (3/18) Oct 07 2010 I agree, that would fit well with the optional trailing commas in array
- Olivier Pisano (2/11) Oct 07 2010 Vote++;
- Denis Koroskin (22/46) Oct 07 2010 If tuples become first-class citizens of D lands, is it possible to make...
- Andrei Alexandrescu (28/52) Oct 07 2010 Sorry for being Debbie Downer in this thread, but I'm not seeing a lot
- retard (8/18) Oct 07 2010 Why do tuple fields need a name? Isn't this a new ad-hoc way to introduc...
- Kagamin (2/5) Oct 07 2010 You really need tuples to write obscure functional code.
- Juanjo Alvarez (6/13) Oct 07 2010 I found they are useful for callbacks, when you can put, in a tuple, the...
- Andrei Alexandrescu (35/57) Oct 07 2010 They don't always need, but oftentimes names are better than numeric
- retard (36/92) Oct 07 2010 If some compile time voodoo isn't used, the names have an effect on the
- Simen kjaeraas (7/13) Oct 07 2010 What? You really think structs/tuples are implemented like
- Andrei Alexandrescu (3/15) Oct 07 2010 Yah, this is D dammit :o).
- retard (14/29) Oct 07 2010 There are several conflicting concepts at stake here. I guess the
- Simen kjaeraas (20/25) Oct 07 2010 Might I inquire as to why?
- retard (4/10) Oct 07 2010 I see these "tuples" defined with a template merely as structs in
- Andrei Alexandrescu (5/15) Oct 07 2010 Could you please take the time to put together a list of requirements?
- retard (10/27) Oct 07 2010 Sure, but I can't really promise to have to capacity to think about ever...
- retard (35/65) Oct 07 2010 If I think about some basic features in other tuple using languages, you...
- Andrei Alexandrescu (40/67) Oct 07 2010 Yah, and it might be the case that we're too close to the matter
- retard (12/72) Oct 07 2010 Looks really good IMO.
- Simen kjaeraas (9/16) Oct 07 2010 The obvious way to do this:
- Andrei Alexandrescu (4/21) Oct 07 2010 Nice. Actually buildArray already exists - it's called array() and it
- Tomek =?UTF-8?B?U293acWEc2tp?= (10/31) Oct 07 2010 From a different angle:
- Tomek =?UTF-8?B?U293acWEc2tp?= (15/34) Oct 07 2010 Blue sky idea -- anonymous structs:
- Andrei Alexandrescu (4/8) Oct 07 2010 Yah, good point. Could you please add that to bugzilla so we don't
- Simen kjaeraas (9/14) Oct 07 2010 Philippe Sigaud's reftuple[1] from dranges does that first part:
- Michel Fortin (53/76) Oct 07 2010 I've always found tuples with named arguments awkward. I mean, a tuple
- Justin Johansson (10/16) Oct 07 2010 Walter, please define exactly what a tuple is as being, both
- Andrei Alexandrescu (4/23) Oct 07 2010 Wise words! It was exactly what I protested against. It discusses syntax...
- Ellery Newcomer (7/31) Oct 07 2010 I might be missing something, but how does this proposal get around the
- Justin Johansson (8/14) Oct 07 2010 Sorry Ellery but you, as others, are also focusing on syntax and not
- Walter Bright (2/11) Oct 07 2010 As has been proposed frequently, the , operator would have to be dispens...
- Steven Schveighoffer (6/15) Oct 07 2010 I think what Ellery is alluding to is it breaks the rule that things tha...
- bearophile (4/5) Oct 07 2010 This makes the -cstyle compiler switch more useful than before :-)
- Simen kjaeraas (8/13) Oct 07 2010 Wouldn't (a,0)[0] currently return a, not (a)? The syntax that behaves
- Kagamin (2/10) Oct 07 2010 Is there a real need for an alternative way to declare structs?
- Andrei Alexandrescu (3/13) Oct 07 2010 Yes.
- Stephan Soller (14/29) Oct 10 2010 I agree but I also don't agree. I like the possibility to return
- Denis Koroskin (10/41) Oct 10 2010 Exactly. To be honest, I see absolutely no reason to have yet another to...
- bearophile (5/7) Oct 10 2010 More modern module-based languages as D are not like C. If they want som...
- Denis Koroskin (5/24) Oct 10 2010 I was referring *only* to Tuple!(int, "foo", float, "bar") syntax. I'd
- Andrei Alexandrescu (6/51) Oct 10 2010 Tuples with named fields are restricted in a number of ways compared to
- bearophile (4/8) Oct 10 2010 Now the discussion is developing in a slower and more relaxed way. Have ...
- Philippe Sigaud (10/10) Oct 10 2010 Whatever the conclusion on all this is, may I suggest to have a way to
- bearophile (4/5) Oct 10 2010 I have implemented it, see enhancement request 4591
- Philippe Sigaud (6/9) Oct 10 2010 Cool, I'll have a look.
- Simen kjaeraas (10/14) Oct 10 2010 Perhaps it would be possible to augment struct static initializers for
- bearophile (4/10) Oct 10 2010 What kind of tuple unpacking syntax do you suggest for this? (I think at...
- Simen kjaeraas (10/19) Oct 10 2010 int a;
- Michel Fortin (26/48) Oct 07 2010 http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_ope...
- Lars T. Kyllingstad (9/46) Oct 07 2010 Should_the_comma_operator_be_removed_in_D2_101321.html
- bearophile (5/9) Oct 08 2010 Tuples are a basic part of a language, they need to come before web tool...
- Jonathan M Davis (3/13) Oct 08 2010 Agreed. But that doesn't mean that library solution isn't the best solut...
- Lars T. Kyllingstad (5/14) Oct 08 2010 I know, and I agree that *if* it is decided that tuples should be added
- Justin Johansson (15/41) Oct 08 2010 People responding on this thread still allude the basic question about
- bearophile (164/171) Oct 08 2010 A better built-in support for tuples is a form of syntax sugar, this mea...
- so (4/10) Oct 09 2010 The syntax is too ugly, i don't know how you call it "sugar" :)
- Justin Johansson (2/3) Oct 09 2010 Perhaps "saccharin" then? :-)
- bearophile (4/5) Oct 09 2010 If you take a look at Fortress you may see how much they use that kind o...
- so (11/21) Oct 09 2010 This must have been answered many times already but i shamelessly ask on...
- Simen kjaeraas (5/11) Oct 09 2010 Uhm, it's an array? That is, the syntax is already taken and means
- so (5/16) Oct 09 2010 Hahaa! Thanks for quick answer. I sometimes forget this is D, not C.
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
Don't function arguments also comprise a tuple? A tuple of 1.
Oct 06 2010
Kagamin wrote:Don't function arguments also comprise a tuple? A tuple of 1.Yes, but that's not ambiguous.
Oct 06 2010
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
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 likeI said, Ithink this would be rare.Python uses: (5,) Which is a lot better IMHO
Oct 07 2010
Juanjo Alvarez wrote:On Wed, 06 Oct 2010 23:04:35 -0700, Walter Bright <newshound2 digitalmars.com> wrote:I agree, that would fit well with the optional trailing commas in array literals.(a,0)[0]as how a user could generate a tuple of 1. Awkward, sure, but likeI said, Ithink this would be rare.Python uses: (5,) Which is a lot better IMHO
Oct 07 2010
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:Vote++;(a,0)[0]as how a user could generate a tuple of 1. Awkward, sure, but likeI said, Ithink this would be rare.Python uses: (5,) Which is a lot better IMHO
Oct 07 2010
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
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
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
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
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
On 10/7/10 5:39 CDT, retard wrote:Thu, 07 Oct 2010 03:20:23 -0500, Andrei Alexandrescu wrote:They don't always need, but oftentimes names are better than numeric constants.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?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
Thu, 07 Oct 2010 09:46:59 -0500, Andrei Alexandrescu wrote:On 10/7/10 5:39 CDT, retard wrote:If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).Thu, 07 Oct 2010 03:20:23 -0500, Andrei Alexandrescu wrote:They don't always need, but oftentimes names are better than numeric constants.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?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.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 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.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 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.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.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);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) { ... }
Oct 07 2010
retard <re tard.com.invalid> wrote: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. -- SimenIf some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).Why do tuple fields need a name?They don't always need, but oftentimes names are better than numeric constants.
Oct 07 2010
On 10/7/10 10:22 CDT, Simen kjaeraas wrote:retard <re tard.com.invalid> wrote:Yah, this is D dammit :o). AndreiWhat? 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.If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).Why do tuple fields need a name?They don't always need, but oftentimes names are better than numeric constants.
Oct 07 2010
Thu, 07 Oct 2010 17:22:08 +0200, Simen kjaeraas wrote:retard <re tard.com.invalid> wrote: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.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.If some compile time voodoo isn't used, the names have an effect on the performance (runtime lookups).Why do tuple fields need a name?They don't always need, but oftentimes names are better than numeric constants.
Oct 07 2010
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
Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote:retard <re tard.com.invalid> wrote: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.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?
Oct 07 2010
On 10/7/10 13:44 CDT, retard wrote:Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote: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. Andreiretard<re tard.com.invalid> wrote: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.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?
Oct 07 2010
Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote:On 10/7/10 13:44 CDT, retard wrote: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.Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote: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.retard<re tard.com.invalid> wrote: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.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?
Oct 07 2010
Thu, 07 Oct 2010 18:56:46 +0000, retard wrote:Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote: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.On 10/7/10 13:44 CDT, retard wrote: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.Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote: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.retard<re tard.com.invalid> wrote: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.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?
Oct 07 2010
On 10/7/10 13:56 CDT, retard wrote:Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote: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?On 10/7/10 13:44 CDT, retard wrote: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.Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote: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.retard<re tard.com.invalid> wrote: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.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?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
Thu, 07 Oct 2010 14:11:21 -0500, Andrei Alexandrescu wrote:On 10/7/10 13:56 CDT, retard wrote: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.)Thu, 07 Oct 2010 13:48:31 -0500, Andrei Alexandrescu wrote: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?On 10/7/10 13:44 CDT, retard wrote: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.Thu, 07 Oct 2010 19:12:45 +0200, Simen kjaeraas wrote: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.retard<re tard.com.invalid> wrote: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.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?
Oct 07 2010
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
On 10/7/10 15:45 CDT, Simen kjaeraas wrote:retard <re tard.com.invalid> wrote:Nice. Actually buildArray already exists - it's called array() and it sits in std.array. AndreiI 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 );
Oct 07 2010
Simen kjaeraas napisał:retard <re tard.com.invalid> wrote: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 -- TomekI 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 );
Oct 07 2010
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
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
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
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 ofAlso, 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
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 isWalter, 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
On 10/7/10 7:23 CDT, Justin Johansson wrote:On 7/10/2010 5:04 PM, Walter Bright wrote:Wise words! It was exactly what I protested against. It discusses syntax without attacking any of the actual issues. AndreiThere 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 isWalter, 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.
Oct 07 2010
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
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
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
On Thu, 07 Oct 2010 13:52:56 -0400, Walter Bright <newshound2 digitalmars.com> wrote:Ellery Newcomer wrote: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. -SteveI 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
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
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
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
On 10/7/10 10:13 CDT, Kagamin wrote:Andrei Alexandrescu Wrote:Yes. Andreistruct 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
On 07.10.2010 17:36, Andrei Alexandrescu wrote:On 10/7/10 10:13 CDT, Kagamin wrote: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 StephanAndrei Alexandrescu Wrote:Yes. Andreistruct 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 10 2010
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: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; }On 10/7/10 10:13 CDT, Kagamin wrote: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 StephanAndrei Alexandrescu Wrote:Yes. Andreistruct 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 10 2010
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
On Sun, 10 Oct 2010 18:33:35 +0400, bearophile <bearophileHUGS lycos.com> wrote:Denis Koroskin: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.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
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: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. AndreiOn 07.10.2010 17:36, Andrei Alexandrescu wrote: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; }On 10/7/10 10:13 CDT, Kagamin wrote: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 StephanAndrei Alexandrescu Wrote:Yes. Andreistruct 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 10 2010
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
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
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
On Sun, Oct 10, 2010 at 23:05, bearophile <bearophileHUGS lycos.com> wrote:Philippe Sigaud:Cool, I'll have a look. *does so* Wow, much more complicated that what I had in mind. I totally forgot about named fields. Philippemay I suggest to have a way to concatenate tuples?I have implemented it, see enhancement request 4591
Oct 10 2010
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
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
bearophile <bearophileHUGS lycos.com> wrote:Simen kjaeraas:int a; string b; { a, b } = foo( ); string s = "123456" char c; { c, s... } = s; I guess. -- SimenPerhaps 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).
Oct 10 2010
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.htmlhttp://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.html Alot 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
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.htmlhttp://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.htmlA 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
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
On Friday 08 October 2010 03:30:35 bearophile wrote:Lars T. Kyllingstad:Agreed. But that doesn't mean that library solution isn't the best solution. - Jonathan M DavisPersonally, 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.
Oct 08 2010
On Fri, 08 Oct 2010 06:30:35 -0400, bearophile wrote: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. -LarsPersonally, 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. [...]
Oct 08 2010
On 8/10/2010 9:30 PM, bearophile wrote:Lars T. Kyllingstad: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: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.On 7/10/2010 5:04 PM, Walter Bright wrote:http://www.digitalmars.com/d/archives/digitalmars/D/Reddit_why_aren_t_people_using_D_93528.htmlThere have been a couple of looong threads about tuples:http://www.digitalmars.com/d/archives/digitalmars/D/Should_the_comma_operator_be_removed_in_D2_101321.htmlWise words! It was exactly what I protested against. It discusses syntax without attacking any of the actual issues. AndreiA 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 isWalter, 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.
Oct 08 2010
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):... return x // y, x % y ...def divmod(x, y):3d, r = divmod(14, 4) print d2 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):print r...def foo((x, y), z): print yb 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, bearophilefoo("ab", 2)
Oct 08 2010
... 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, bearophileThe 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
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
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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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
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
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:-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/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.
Oct 09 2010