www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - A Discussion of Tuple Syntax

reply "Meta" <jared771 gmail.com> writes:
Awhile ago Kenji posted this excellent dip 
(http://wiki.dlang.org/DIP32) that aimed to improve tuple syntax, 
and described several cases in which tuples could be 
destructured. You can see his original thread here: 
http://forum.dlang.org/thread/mailman.372.1364547485.4724.digitalm
rs-d puremagic.com, 
and further discussion in this thread: 
http://forum.dlang.org/thread/dofwinzpbcdwkvhzcgrk forum.dlang.org.

It seemed that there was a lot of interest in having syntax 
somewhat like what is described in Kenji's DIP, but it didn't 
really go anywhere. There is this pull on Github 
(https://github.com/D-Programming-Language/dmd/pull/341), but it 
uses the (a, b) syntax, which has too much overlap with other 
language constructs. Andrei/Walter didn't want to merge that pull 
request without a full consideration of the different design 
issues involved, which in retrospect was a good decision.

That said, I'd like to open the discussion on tuple syntax yet 
again. Tuples are currently sorely underused in D, due in large 
part to being difficult to understand and awkward to use. One 
large barrier to entry is that fact that D has not 1, not 2, but 
3 different types of tuples (depending on how you look at it), 
which are difficult to keep straight.

There is std.typecons.Tuple, which is fundamentally different 
from std.typecons.TypeTuple in that it's implemented as a struct, 
while TypeTuple is just a template wrapped around the compiler 
tuple type. ExpressionTuples are really just TypeTuples that 
contain only values, and aren't mentioned anywhere except for in 
this article: http://dlang.org/tuple.html, which frankly creates 
more confusion than clarity.

A good, comprehensive design has the potential to make tuples 
easy to use and understand, and hopefully clear up the unpleasant 
situation we have currently. A summary of what has been discussed 
so far:

- (a, b) is the prettiest syntax, and it also completely 
infeasible

- {a, b} is not as pretty, but it's not that bad of an 
alternative (though it may still have issues as well)

- #(a, b) is unambiguous and would probably be the easiest 
option. I don't think it looks too bad, but some people might 
find it ugly and noisy

- How should tuples be expanded? There is the precedent of an 
expand() method of std.typecons.Tuple, but Kenji liked tup[] 
(slicing syntax). So with a tuple of #(1, "a", 0.0), tup[0..2] 
would be an expanded tuple containing 1 and "a". On the other 
hand, Bearophile and Timon Gehr preferred that slicing a tuple 
create another "closed" tuple, and to use expand() for expansion. 
So tup[] would create a copy of the tuple, and tup[0..2] would 
create a closed tuple eqvivalent to #(1, "a"). I don't have any 
particular preference in that regard.

- Timon Gehr wanted the ability to swap tuple values, so #(x, y) 
= #(y, x) would be allowed. Kenji was against it, saying that it 
would introduce too many complications.

- There was no consensus on the pattern matching syntax for 
unpacking. For example, #(a, _) = #(1, 2) only introduces one 
binding, "a", into the surrounding scope. The question is, what 
character should go in the place of "_" to signify that a value 
should not be bound? Some suggestions were #(a, $), #(a,  ), #(a, 
?). I personally think #(a, ?) or #(a, *) would be best, but all 
that's  really necessary is a symbol that cannot also be an 
identifier.

     Also up for debate was nested patterns, e.g., #(1, 2, #(3, 4, 
#(5, 6))). I don't think there was a consensus on unpacking and 
pattern matching for this situation. One idea I saw that looked 
good:

         * Use "..." to pattern match on the tail of an 
expressions, so take the above tuple. The pattern #(1, ?, ...) 
would match the two nested sub-tuples. Or, say, #(1, 2, 3) could 
be matched by #(1, 2, 3), #(1, ?, 3), #(1, ...), etc. You 
obviously can't refer to "..." as a variable, so it also becomes 
a useful way of saying "don't care" for multiple items, e.g., 
#(a, ...) -> only bind the first item in the tuple. We can play 
around with this to get a few other useful constructs, such as 
#(a, ..., b) -> match first and last, #(..., b) -> match last, 
etc.

Assuming the "..." syntax for unpacking, it would be useful to 
name the captured tail. For example, you could unpack #(1, 3, 
#(4, 6)) into #(a, b, x...), where a = 1, b = 3, x = #(4, 6). 
Similarly, #(head, rest...) results in head = 1, rest = #(2, #(4, 
6)). I think this would be very useful.

- Concatenating tuples with ~. This is nice to have, but not 
particularly important.

One thing that I think was overlooked, but would be pretty cool, 
is that a tuple unpacking/pattern matching syntax would allow us 
to unpack/pattern match just about anything that you can make a 
tuple of in D. Combine this with the .tupleof property, and 
things get interesting... Maybe. There is one possible problem: 
.tupleof returns a TypeTuple, and it's not at all clear to me 
how, if at all, TypeTuple would work with the proposed syntax. Is 
#(int, string, bool) a valid tuple instantiation? This is 
something that needs to be worked out.

This is the third or fourth time that I know of that tuple syntax 
has come up, and as of yet, nothing has been done about it. I'd 
really like to get the ball rolling on this, as I think a good 
syntax for these tuple operations would do D a world of good. I'm 
not a compiler hacker, unfortunately, so I can't implement it 
myself as proof of concept... However, I hope that discussing it 
and working out all the kinks will help pave the way for an 
actual implementation.
Aug 16 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Meta:

 Andrei/Walter didn't want to merge that pull request without a 
 full consideration of the different design issues involved, 
 which in retrospect was a good decision.

I agree that before adding some new syntax you have to think well.
 - {a, b} is not as pretty, but it's not that bad of an 
 alternative (though it may still have issues as well)

It has technical issues, they were discussed in one of the last threads. Such problems should be added in a note in the DIP32, so they don't get lost in time.
 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

It looks nice (but I don't know if it's technically usable), I have added it at the end of the list of alternative syntaxes: http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
 I personally think #(a, ?) or #(a, *) would be best, but all 
 that's  really necessary is a symbol that cannot also be an 
 identifier.

I think ? is clear, unambiguous, etc, and I like it. The * is already used for pointers, product, dereferencing, ** is used for pow, so it's better to not add further meanings to it.
 - Concatenating tuples with ~. This is nice to have, but not 
 particularly important.

In theory I like this operation, but in practice in my D code I don't need it often, so I think it should be left out, for later. In Python I sometimes concatenate tuples, but in such use cases they are essentially immutable dynamically typed arrays, losing their positional meaning. Tuples could also be used in switch/case statements, to support a very basic form of pattern matching. See also a standard method named "unapply" I have discussed a bit here, coming from Scala language, that is a very simple solution to solve a significant problem: http://d.puremagic.com/issues/show_bug.cgi?id=596 Bye, bearophile
Aug 16 2013
parent captaindet <2krnk gmx.net> writes:
On 2013-08-16 20:02, Meta wrote:
 On Friday, 16 August 2013 at 23:48:53 UTC, bearophile wrote:
 - #(a, b) is unambiguous and would probably be the easiest option. I don't
think it looks too bad, but some people might find it ugly and noisy

It looks nice (but I don't know if it's technically usable), I have added it at the end of the list of alternative syntaxes: http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax

Why do you say that? It seems to me that it would be better than {}, because there's only 1 other language construct that uses #, so there's little overlap with other features.

not sure what we are talking about here, new syntax for a) TypeTuple (that would be my best guess but i am not sure) b) std.typecons.Tuple c) both, a unified syntax the DIP is not completely clear about this either. only case (a) is hot at the moment and i fell into some related pits recently myself. so i'd love to have a better syntax, one that makes the dirty hack (status quo) a proper part of the language - as it is widely used already and very powerful. i am curious too if ..(..) constructs are completely out of the question. if not, i would suggest as shorthand: !(a,b) this reminds of template instantiation and is exactly how the awkwardly/confusingly named TypeTuple is realized now, as an alias to its own template arguments. if we need a name for it, it should not remind at all of 'tuple' - since there is also the completely unrelated std.typecons.Tuple. a more verbose/explicit suggestion would be symbols(a,b) /det
Aug 16 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Friday, 16 August 2013 at 23:48:53 UTC, bearophile wrote:
 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

It looks nice (but I don't know if it's technically usable), I have added it at the end of the list of alternative syntaxes: http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax

Why do you say that? It seems to me that it would be better than {}, because there's only 1 other language construct that uses #, so there's little overlap with other features.
Aug 16 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Saturday, 17 August 2013 at 05:48:47 UTC, captaindet wrote:
 not sure what we are talking about here, new syntax for
 a) TypeTuple (that would be my best guess but i am not sure)
 b) std.typecons.Tuple
 c) both, a unified syntax
 the DIP is not completely clear about this either.

First and foremost, a new syntax for std.typecons.Tuple. Creating tuple literals -> #(1, "a", false), pattern matching on tuples -> switch (#(1, 2)), and destructuring of tuples -> #(a, b) = #(1, 2). A good question is whether this syntax can (and more importantly, should) be used for TypeTuples as well. TypeTuples are poorly named and not at all similar to Tuple, so it doesn't make much sense to give them both the same syntax. Also, I can't see TypeTuple seeing nearly as much use as Tuple, so it may be better to introduce the new syntax for Tuple, and keep TypeTuple as-is.
 only case (a) is hot at the moment and i fell into some related 
 pits recently myself. so i'd love to have a better syntax, one 
 that makes the dirty hack (status quo) a proper part of the 
 language - as it is widely used already and very powerful.

What TypeTuple gives you access to is the compiler tuple type that it uses for function argument lists and other things. I wouldn't really call it a dirty hack. The two most confusing things about TypeTuple, I think, is the auto-expansion, and the fact that it can contain both types and values.
 i am curious too if ..(..) constructs are completely out of the 
 question. if not, i would suggest as shorthand:

 	!(a,b)

 this reminds of template instantiation and is exactly how the 
 awkwardly/confusingly named TypeTuple is realized now, as an 
 alias to its own template arguments.

Unfortunately, that won't work, as the value of this expression is already well-defined in the current language. A list of comma-separated expressions means that each is evaluated from left to right, and then the result of the entire expression is the result of the rightmost expression, e.g.: auto a = true; auto b = false; //Evaluate a, then b. The result of the expression //in the brackets is b. Then the ! gets applied to b auto x = !(a, b); assert(x == true); //Passes
 if we need a name for it, it should not remind at all of 
 'tuple' - since there is also the completely unrelated 
 std.typecons.Tuple. a more verbose/explicit suggestion would be

 	symbols(a,b)

I 100% agree that TypeTuple needs a better name. A couple other suggestions were put forward as well in the other tuple thread currently active.
Aug 17 2013
prev sibling next sibling parent reply "Wyatt" <wyatt.epp gmail.com> writes:
Note: I'm leading off with a reply to bearophile transplanted 
here to stop making OT noise in John's thread about TypeTuple.

On Friday, 16 August 2013 at 23:23:59 UTC, bearophile wrote:
 It's short, clear, has a precedent with q{}.

Wait, what is q{}? That's something in D? What does that even do? I can infer that q{} is probably some manner of scoping or grouping _something_ somehow, but I have to dig into lexical and manually search for q{ to find out it's [neither of the things I expected]. In my view, this right here is really just a fundamental problem with single-character prefixes and I feel that's something we should endeavour to avoid, if possible.
 I don't like it a lot, but it's way better than not having
 language support for tuples.

 I'd prefer just using parentheses, but I think there were 
 readability problems that caused the DIP to end up with:

More than just readability problems. They were discussed when Kenji presented the DIP 32 in this forum. Timon found a significant problem with the {} syntax.

parentheses, (). I read over that whole DIP32 thread a couple times, and didn't see any rationale offered for why the likely "cleanest" version "can't be used". It wasn't even brought up (unless I've missed something subtle). In the second thread, linked in the OP here, they were glossed over again. Now, I fully believe there's a very good reason that's been written somewhere, but I _would_ like to know what that is, preferably documented somewhere less ephemeral and difficult to search than the newsgroup (such as in DIP32). The closest I've seen so far is the pull request where Walter and Andrei expressed that it should be considered further. On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

readability, though, even more than q{} or t{}, I have concerns about its ability to be found with an ordinary search engine by an ordinary user. Have you tried looking for documentation on weird operators with a search engine lately? They don't exactly take to it well. :/ (cf. Perl's <=>) Addressing the other suggestion I saw that cropped up, I personally find the two-character "bananas" to be impressively ugly. I considered suggesting some permutation on that same idea, but after toying with a few examples I find it ends up looking awful and I think it's honestly annoying to type them in any form. I even don't like how the unicode version of that one looks; for doubling up, I think ⟦ ⟧ or ⟪ ⟫ or are easier on the eyes. It's times like these that I wish the standard PC keyboard had something like guillemets « », or corner brackets 「 」 (big fan of these) in addition to everything else. (Or even that we could use < > for bracing, though at this point I don't think I could easily condone that move for D). I feel weird admitting this, but if we can't use some manner of bare brace, I think I'd rather have tup(), tup[], tup{} (or even tuple() et al) as a prefix over any single character. Another stray thought: is there room for a little box of syntax chocolate so that e.g. tuple(), [||], and ⟦ ⟧ are all valid? I don't know if we have a precedent like that off the top of my head and I'm pretty sure I don't like it, but I thought I'd at least mention it.
 - There was no consensus on the pattern matching syntax for 
 unpacking. For example, #(a, _) = #(1, 2) only introduces one 
 binding, "a", into the surrounding scope. The question is, what 
 character should go in the place of "_" to signify that a value 
 should not be bound? Some suggestions were #(a, $), #(a,  ), 
 #(a, ?). I personally think #(a, ?) or #(a, *) would be best, 
 but all that's  really necessary is a symbol that cannot also 
 be an identifier.

IMO. It isn't as burdened with meanings elsewhere (sure there's ternary and possibly-match in regex, but...have I forgotten something?)
     Also up for debate was nested patterns, e.g., #(1, 2, #(3, 
 4, #(5, 6))). I don't think there was a consensus on unpacking 
 and pattern matching for this situation. One idea I saw that 
 looked good:

not mentioned in the DIP that I saw, so I assumed it was allowed, but explicit mention is probably warranted.
         * Use "..." to pattern match on the tail of an 
 expressions, so take the above tuple. The pattern #(1, ?, ...) 
 would match the two nested sub-tuples. Or, say, #(1, 2, 3) 
 could be matched by #(1, 2, 3), #(1, ?, 3), #(1, ...), etc. You 
 obviously can't refer to "..." as a variable, so it also 
 becomes a useful way of saying "don't care" for multiple items, 
 e.g., #(a, ...) -> only bind the first item in the tuple. We

#(a, ...) looks like to me like it would make a 2-tuple containing a and a tuple of "everything else", because of the ellipsis' use in templated code. I think this is a little unclear, so instead I'd prefer #(a, ? ...) (or whatever ends up used for the discard character) to make it explicit.
 Assuming the "..." syntax for unpacking, it would be useful to 
 name the captured tail. For example, you could unpack #(1, 3, 
 #(4, 6)) into #(a, b, x...), where a = 1, b = 3, x = #(4, 6). 
 Similarly, #(head, rest...) results in head = 1, rest = #(2, 
 #(4, 6)). I think this would be very useful.

less likely to completely change the meaning of the statement. Compare: #(a, b, ...) //bind the first two elements, discard the rest. #(a, b ...) //bind the first element to a and everything else to b #(a, b, ? ...) //same as the first #(a, b ? ...) //syntax error Granted, there's this case: #(a, ?, ...) ...but that seems like it would be less common just based on how people conventionally order their data structures. Thought: Is there sufficient worth in having different tokens for discarding a single element vs. a range? e.g. #(a, ?, c, * ...) //bind first and third elements; discard the rest // I'm not attached to the asterisk there. // +, #, or would also make some amount of sense to me.
 - Concatenating tuples with ~. This is nice to have, but not 
 particularly important.

auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right? auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b == #(1,2,3,4,5)?
 This is the third or fourth time that I know of that tuple 
 syntax has come up, and as of yet, nothing has been done about 
 it. I'd really like to get the ball rolling on this, as I think 
 a good syntax for these tuple operations would do D a world of 
 good. I'm not a compiler hacker, unfortunately, so I can't 
 implement it myself as proof of concept... However, I hope that 
 discussing it and working out all the kinks will help pave the 
 way for an actual implementation.

Great! After this, let's fix properties. ;) -Wyatt
Aug 19 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 10:54 AM, Dicebot wrote:
 On Monday, 19 August 2013 at 17:45:44 UTC, H. S. Teoh wrote:
 On Mon, Aug 19, 2013 at 07:34:38PM +0200, Dicebot wrote:
 On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:
What I'd like to know, is how all of these proposals address >the
fundamental differences between "symbol tuples" (compile-time
construct)

Those are not symbol tuples. For example, `int` is not a symbol. http://dlang.org/template.html#Symbol - only things that have identifiers and template instances are symbols.

Well, OK, whatever they're supposed to be called. Compiler-tuples, or expression tuples, or whatever.

Well, technically they are compile-time tuples of stuff.

I'd call them alias tuples. Andrei
Aug 19 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 11:14 AM, Dicebot wrote:
 On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu wrote:
 I'd call them alias tuples.

Because we don't have strict definition of alias too? :)

I'm thinking such a tuple may hold everything that one may define an alias to. Andrei
Aug 19 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 1:41 PM, Dicebot wrote:
 On Monday, 19 August 2013 at 20:36:10 UTC, Andrei Alexandrescu wrote:
 On 8/19/13 11:14 AM, Dicebot wrote:
 On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu wrote:
 I'd call them alias tuples.

Because we don't have strict definition of alias too? :)

I'm thinking such a tuple may hold everything that one may define an alias to.

Normal alias or template alias parameter? ;)

Normal alias. Yah, perhaps "template tuples" are more descriptive. Andrei
Aug 19 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 11:54 AM, Meta wrote:
 Realistically, Andrei, how amenable are you and Walter to adding tuple
 literal/packing&unpacking/pattern matching syntax to D, be it Tuple,
 TypeTuple, whatever? I don't recall either of you commenting much in the
 two other discussion threads linked. We can discuss this all day, but it
 what are the actual chances of you agreeing to such a large change in
 the language?

We'd be fools to reject a valuable addition to the language. That being said, there's no broad agreement on what's needed and what's to be added. Furthermore, most discussions are disproportionally focused on syntax (as opposed to semantics) and fall for syntactic cutesies instead of simple and robust library support. That in my experience is a bad omen. Now _that_ being said, if and when a gem comes about, we hope to have the insight to see it. Andrei
Aug 19 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/19/2013 07:44 PM, H. S. Teoh wrote:
 Well, OK, whatever they're supposed to be called. Compiler-tuples, or
 expression tuples, or whatever. See, part of the problem is that they
 just don't have any good name that correctly conveys what they are.

They are simply template argument lists. (http://wiki.dlang.org/The_D_Programming_Language/Seq)
Aug 19 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 12:54 PM, bearophile wrote:
 Meta:

 It *could* be an underscore; the only thing is that the underscore is
 a valid variable name, so the above expression would actually be
 binding two variables, which might surprise someone who was expecting
 otherwise. I don't really care all that much, but it's something to
 think about.

You can't define a variable more than once in a scope, so this can't be valid: void main() { auto t1 = #(5, "hello", 1.5); auto (_, _, x) = t1; auto (_, gr, _) = t1; } While ? defines nothing, so this is OK: void main() { auto t1 = #(5, "hello", 1.5); auto (?, ?, x) = t1; auto (?, gr, ?) = t1; } Bye, bearophile

It's stuff like this that's just useless and gives a bad direction to the whole discussion. There's hardly anything wrong with auto x = t1[2] or auto gr = t1[1], but once the bikeshed is up for painting, the rainbow won't suffice. Andrei
Aug 19 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On Monday, 19 August 2013 at 20:46:02 UTC, Andrei Alexandrescu wrote:
 It's stuff like this that's just useless and gives a bad
 direction to the whole discussion. There's hardly anything
 wrong with auto x = t1[2] or auto gr = t1[1], but once the
 bikeshed is up for painting, the rainbow won't suffice.

I started this discussion to build on Kenji's DIP, which discusses destructuring and pattern matching syntax in addition to tuple literal syntax, as well as the previous discussion that's already gone on in the two "DIP discussion" threads. Are you saying that you dislike the destructuring/pattern matching discussion as a whole? I'm saying that there's a mix of useful stuff and just syntactic additions that are arguably less so. In my opinion: a) destructuring tuples in auto declarations - good to have: auto (a, b, c) = functionReturningTupleOrStaticArrayWith3Elements(); b) syntactic support for ignoring certain members in a destructuring - is that really needed? auto (a, ?, c) = functionReturningTupleOrStaticArrayWith3Elements(); Andrei
Aug 19 2013
parent captaindet <2krnk gmx.net> writes:
On 2013-08-19 17:04, Meta wrote:
 On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu
 wrote:
 b) syntactic support for ignoring certain members in a
 destructuring - is that really needed?

 auto (a, ?, c) =
 functionReturningTupleOrStaticArrayWith3Elements();

In fairness, it is very common in other languages with pattern matching/destructuring. Off the top of my head I can think of Haskell, ML, Racket, Javascript (destructuring only) and Rust.

same in matlab. once destruction->auto assignment is available, (future) library functions will make heavy use of it, e.g. statistics functions returning lots of parameters/characteristics for a dataset. more often than not one is only interested in a few. /det
Aug 19 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 4:48 PM, Meta wrote:
 I don't necessarily want built-in syntax for a library type, but making
 tuples first-class would be nice. I mean, it's a bummer that they can't
 be returned from functions. That should definitely be changed.

return tuple(1, "a"); Andrei
Aug 19 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 5:14 PM, Meta wrote:
 On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu wrote:
 On 8/19/13 4:48 PM, Meta wrote:
 I don't necessarily want built-in syntax for a library type, but making
 tuples first-class would be nice. I mean, it's a bummer that they can't
 be returned from functions. That should definitely be changed.

return tuple(1, "a");

That's not a TypeTuple, though, it's a built-in tuple. void main() { writeln(func()); } TypeTuple!(int, string) func() { return tuple(1, "a"); //Error } Nor does it work the other way around: Tuple!(int, string) func() { return TypeTuple!(1, "a"); //Error } How would this work for some hypothetical built-in syntax? #(int, string) func() { return tuple(1, "a"); //Error? }

Why would it be necessary to return an object of type TypeTuple (i.e. template tuple)? It has no state. Andrei
Aug 19 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:
 Why would it be necessary to return an object of type TypeTuple (i.e.
 template tuple)?

- Elegance. Eg: auto seq(T...)(T arg){ return arg; } auto fold(alias a,S,R)(S start, R range){ ... } seq(0,[1,2,3]).fold!((a,b)=>a+b); (Obviously you can get close by requiring expansion at the call site.) - ABI Multiple return values could use a more efficient ABI than struct instances because they do not have an address. - Consistency A type whose instances cannot be returned from a function is just weird language design.
 It has no state.

It may alias variables that do.
Aug 19 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/19/13 11:39 PM, Timon Gehr wrote:
 On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:
 Why would it be necessary to return an object of type TypeTuple (i.e.
 template tuple)?

- Elegance. Eg: auto seq(T...)(T arg){ return arg; } auto fold(alias a,S,R)(S start, R range){ ... } seq(0,[1,2,3]).fold!((a,b)=>a+b);

But this is again a value tuple not a template tuple, no? Andrei
Aug 20 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 08:51 PM, Andrei Alexandrescu wrote:
 On 8/19/13 11:39 PM, Timon Gehr wrote:
 On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:
 Why would it be necessary to return an object of type TypeTuple (i.e.
 template tuple)?

- Elegance. Eg: auto seq(T...)(T arg){ return arg; } auto fold(alias a,S,R)(S start, R range){ ... } seq(0,[1,2,3]).fold!((a,b)=>a+b);

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

In my understanding the former is a special case of the latter. Since you invented those terms, I might be mistaken. How do you distinguish between them?
Aug 20 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-08-20 05:33, Kenji Hara wrote:

 If you want to return multiple values from a function, you must always
 wrap them by std.typecons.Tuple, or other used-defined types. You cannot
 directly return built-in tuple from a function.
 (Built-in tuple return is mostly equivalent with multiple-value-return
 issue. However it would be mostly impossible that defining calling
 conversion scheme for that in portable)

If I recall correctly some ABI's passes small structs in registers, at least I think it does on Mac OS X.
 My opinions agains various syntax proposals:

 #(1, "str")
 --> The character '#' is already used for the start of "Special Token
 Sequences"
 http://dlang.org/lex.html#Special Token Sequence

 It is recognized in lexing phase, so adding semantic meaning to the '#'
 character would be a contradict of D's principle.

 Quote from http://dlang.org/lex.html
 "The lexical analysis is independent of the syntax parsing and the
 semantic analysis."

It depends on how it's lexed. If the compiler lexes "#line" as a single token I cannot see how it will be a problem. Then the "#" token would mean tuple literal. -- /Jacob Carlborg
Aug 20 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 05:18 PM, bearophile wrote:
 s = "red blue"
 (a, b) = s.split()
 a



 b




It's supported in Haskell too: Prelude> let s = "red blue" Prelude> let [a, b] = words s Prelude> a "red" Prelude> b "blue" Bye, bearophile

Any language with algebraic data types supports this.
Aug 20 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 09:57 PM, Timon Gehr wrote:
 On 08/20/2013 05:18 PM, bearophile wrote:
 s = "red blue"
 (a, b) = s.split()
 a



 b




It's supported in Haskell too: Prelude> let s = "red blue" Prelude> let [a, b] = words s Prelude> a "red" Prelude> b "blue" Bye, bearophile

Any language with algebraic data types supports this.

(Some will only allow it if you can prove the match is total within them, of course.)
Aug 20 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 6:57 AM, Dicebot wrote:
 I am proposing something more radical. Deprecate _both_ TypeTuple and
 Tuple. Clearly define the difference between built-in type tuple and
 expression tuple (latter being instance of former).

But that can't be the case.
 Preserve
 auto-expansion.

That would be problematic to say the least. (There have been a few discussions in this group; I've come to think auto expansion is fail.)
 Provide two different literals to remove ambiguity
 between referencing symbol as a value and referencing it as an alias.
 Make compiler auto-generate Tuple-like struct type for expression tuples
 that need to be returned from functions. Create some new type in
 std.typecons for those who don't want auto-expansion.

 It won't even break stuff.

That sounds good :o). Andrei
Aug 20 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 1:24 PM, Dicebot wrote:
 That would be problematic to say the least. (There have been a few
 discussions in this group; I've come to think auto expansion is fail.)

:O it is awesome!

"Spawn of Satan" would be a tad more appropriate.
 Stuff like foo(myStructInstance.tupleof) is very
 powerful tool for generic interfaces.

One problem with automatic expansion is that now there's a whole new kind - a single expression that doesn't quite have one value and one type, but instead is an explosion of other expressions. The problem now is how to contain these things - presumably one should associate a self-exploding tuple with a symbol: auto pack = functionReturningTuple(); The symbol should not expand when, for example, assigned to another: auto packCopy = pack; However, the symbol _should_ expand "where it should", presumably in a function code: auto m = min(pack, 0); So this will invoke min with various numbers of arguments depending on what pack contains. Same with e.g. writeln(pack); Before one even realizes it, the matter of when to expand vs. when not to expand becomes a thing. That thing will have people confused (because now an expression isn't what it seems; it may be, in fact, several expressions at once). It will get explained in articles and books. There will be debates about choices of automatic unpacking vs. not in which reasonable people may disagree. People will get all confused about it. Generic code won't be able to tell much about what's going on because arity can't be guaranteed anymore. Alternatively, we could do what Go does and prevent all packing altogether (if I understand what Go does correctly). That is, if a function returns a tuple you can't even keep that tuple together unless you use some handcrafted solution. In that case, before long there will be some "Pack" structure and some pack helper function, viz. the converse of .expand. Clearly both packing and unpacking tuples are necessary. The question is what the default is. My argument here is that keeping one expression/symbol have one value is so deeply embedded in the semantics (and the ethos for that matter) of D, that it would be a major step backwards to retrofit it all to accommodate self-expanding tuples. Not speaking for other languages, I think it's great that in D writeln(x); is known to take an argument, whereas writeln(x.expand); takes zero or more arguments. It is the best compromise I can imagine that keeps the language sealed tight.
 Do you remember any keywords to
 look for to find those discussions? Ones I remember were mostly about
 auto-expansion _not_ happening in some reasonable places.

Ionno so I just summarized it. Andrei
Aug 20 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 5:28 PM, Tyler Jameson Little wrote:
 OT: is the only thing stopping us from using the nice (x,y) syntax for
 tuples the comma operator? If so, can we take that mis-feature behind
 the woodshed and shoot it? I sincerely hope nobody is relying on it...

I think this whole thread is approaching things wrongly. It should be: 1. What do we need? 2. What does a solution look like in the current language? 3. Which parts of the solution are frequent/cumbersome enough to warrant a language change? Instead there have been 1001 proposals for new syntax for tuple literals, one cuter than the next. Andrei
Aug 20 2013
next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 1. What do we need?

I think D needs less tuples. It has two kinds (language kind and Phobos's kind), which is confusing. It should have just one that covers most use cases. So in essence a tuple should: 1. be able to contain anything you can put as a template argument 2. be able to be packed and expanded as needed And the above should be usable in these situations: - using a type tuple as a variable's type - unpacking a tuple as function/template arguments - using a tuple as a return type - assigning a value tuple to an alias-of-variables tuples - using foreach with a tuple - pass a tuple by reference to a function - return a tuple by reference from a function - slice a tuple - concat tuples I'm on the fence about taking the address of a tuple. Not being able to take the address has an upside: if the function call ABI pass each component of a tuple as one ref parameter under the hood, then you could pass tuple of aliases as function arguments. For instance, here I'd be swapping variables a, c, and e with variables b, d, and f with just one call to swap: int a, b, c, d, e, f; swap(...(a, c, e), ...(b, d, f)); (Note: using "..." syntax to create packed tuple literals. See my other post about how that'd work.) -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Aug 20 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 8:25 PM, Michel Fortin wrote:
 On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 1. What do we need?

I think D needs less tuples. It has two kinds (language kind and Phobos's kind), which is confusing. It should have just one that covers most use cases.

Yah, fewer tuples (or assigning distinct names to what we call today such) would be awesome.
 So in essence a tuple should:

 1. be able to contain anything you can put as a template argument

I'm unfortunately lost already. I was discussing tuples as in "anonymous structs", not as in "template tuples". So I'll skip most of what follows, except:
      int a, b, c, d, e, f;
      swap(...(a, c, e), ...(b, d, f));

 (Note: using "..." syntax to create packed tuple literals. See my other
 post about how that'd work.)

This looks like an example taken from a book in which "..." means some stuff is omitted. This thread has a few odd choices of syntax, but this is awful, pure and simple. How in the world could we use "..." which has already a strong literary connotation, for an operation? How could one deem swap(...(a, c, e), ...(b, d, f)); superior to swap(pack(a, c, e), pack(b, d, f)); , particularly considering that "pack" could be replaced with a more informative word or combination of words? Sigh. Andrei
Aug 21 2013
parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-08-21 16:59:17 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 8/20/13 8:25 PM, Michel Fortin wrote:
 On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 
 1. What do we need?

I think D needs less tuples. It has two kinds (language kind and Phobos's kind), which is confusing. It should have just one that covers most use cases.

Yah, fewer tuples (or assigning distinct names to what we call today such) would be awesome.

That seems like the only thing everyone agrees with. :-)
 I'm unfortunately lost already. I was discussing tuples as in 
 "anonymous structs", not as in "template tuples".

Well, the original post that started this discussion talked about both. I don't think narrowing it only to "anonymous structs" is going to solve the syntax problem as a whole.
      int a, b, c, d, e, f;
      swap(...(a, c, e), ...(b, d, f));

This looks like an example taken from a book in which "..." means some stuff is omitted.

Seriously, the major issue with tuples is a conceptual one. No pretty syntax is going to fix it alone. Unfortunately, talking about concepts requires inventing a syntax for them. The syntax then immediately get dismissed as ugly/impractical and no thought is given to what's under it. No wonder this is getting nowhere for the nth time when everyone thinks so superficially. Just disregard the "..." syntax. It makes sense in the context of my other post. There's no way to appreciate it without that context (and even then, it can surely be improved). The idea (in my other post) was to un-cripple language-level tuples with one simple fundamental change: allow them to be packed and expanded. With that you can cover 99% of what you want from a tuple struct using the built-in language-level tuple. Plus you can do some other things like the swap of aliases to variables shown above. There is no reason for template-argument-tuples to be auto-expanding. If you fix that, as I proposed in my other post, you'll almost never need a library struct template to represent a tuple anymore. Thus, fewer tuples. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Aug 21 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 8:39 PM, Jonathan M Davis wrote:
 On Tuesday, August 20, 2013 23:25:03 Michel Fortin wrote:
 On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu

 <SeeWebsiteForEmail erdani.org> said:
 1. What do we need?

I think D needs less tuples. It has two kinds (language kind and Phobos's kind), which is confusing. It should have just one that covers most use cases.

I honestly think that trying to combine Tuple and TypeTuple would increase the confusion

I agree. I think we could and should eliminate this requirement right off the bat. Andrei
Aug 21 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 6:38 PM, Kenji Hara wrote:
 2013/8/21 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org
 <mailto:SeeWebsiteForEmail erdani.org>>

     I think this whole thread is approaching things wrongly. It should be:

     1. What do we need?


 Both
 a. Built-in tuple construction syntax
 and
 b. Built-in tuple deconstruction syntax

     2. What does a solution look like in the current language?


 a.
    alias Types = {int, long};
    auto values = {1, "str"};
 b.
    auto {a, b} = tup;  // on variable declaration
    {a, b} = tup;       // on assignment expression
    ...

The current language would be D as it is today, with no syntactic addition. So I guess that would be: a. alias Types = TypeTuple!(int, long); auto values = tuple(1, "str"); b. auto a = tup[0]; auto b = tup[1]; tup.scatter(a, b); "scatter" is not defined yet. It scatters the content of a tuple over the (ref-passed) arguments. Andrei
Aug 21 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 11:08 PM, eles wrote:
 On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei Alexandrescu wrote:
 On 8/20/13 5:28 PM, Tyler Jameson Little wrote:
 Instead there have been 1001 proposals for new syntax for tuple
 literals, one cuter than the next.

I agree. However, that syntax issue is the bikeshed and it keeps everyone's mind busy. So, I propose to pick-up a syntax, even a provisional one, let's say that &(a,b) that I kinda like, then stick with it. This will free the way for more important and fundamental issues and, on the way, it will also allow to discover the eventual shortcomings of the syntax that was picked-up.

That's wrong, too. Choose a syntax from _within_ the language, not from _without_. That way we can discuss semantics without noise, and then figure whether a new syntax is warranted. So instead of &(a, b) we should use symbol(a, b) or symbol!(a, b) replacing "symbol" appropriately. With &(a, b) I have no idea what you're talking about - save taking the address of b :o). Andrei
Aug 21 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 10:16 PM, Andrei Alexandrescu wrote:
 (There have been a few discussions in this group; I've come to think
 auto expansion is fail.)

+1. :)
Aug 20 2013
prev sibling parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-08-20 20:16:48 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 8/20/13 6:57 AM, Dicebot wrote:
 Preserve
 auto-expansion.

That would be problematic to say the least. (There have been a few discussions in this group; I've come to think auto expansion is fail.)

I used to like auto expansion, probably because it was convenient for what I was doing. I always feared that not having auto-expansion would make my code ugly. But now that I've been working with C++11 with its variadic template parameters that don't auto expand, I'm quite fond of it. To expand a "tuple" all you have to do is suffix it with "...", example: template < typename A, typename B, typename... C > shared_ptr< Expression > make_exp(Operator op, A first, B second, C... more) { return make_exp(op, make_exp(op, first, second), more...); } Now, if we could get rid of auto expansion while requiring a "..." suffix to expand a tuple, I think it'd be really great. Can't we steal this from C++? What follows is how I'd transpose this to D. First, let's put the three-dots *before* the template argument (somewhat as in C++) to get a packed tuple. This will ensure backward compatibility (if you put the three-dots after, like current D, you'd still get an auto-expanding tuple): Expression make_exp(A, B, ...C)(Operator op, A first, B second, C... more) { return make_exp(op, make_exp(op, first, second), more...); } Basically, the rule is simple: three dots before an expression means "pack", three dots after it means "expand". In the example above, the template argument C is a packed tuple type. Expanding C in the function's argument list means that we're expecting arguments to come as separate argument and not as one packed tuple argument. Those separate arguments get packed into the "more" parameter variable, which is of type C, which is then expanded as requested by the three-dot suffix when calling the function. Extrapolating things a little, a packed tuple type could be expressed like this: ...(int, double) x; // a packed type tuple variable x = ...(1, 2.3); // create a packed value tuple and assign it to x. writeln(x...); // expand tuple to make it two separate arguments writeln(x); // keep it packed and you're passing it as one argument ...(int, ...(double, float)) y; // nested tuples Also, you can take an auto-expanding tuple and make it packed: template (X...) { ...(X) x; // auto-expanding tuple becomes packed } Which is the same as making it packed directly from the argument list: template (...X) { X x; // already packed tuple } And since this is a "language-type" tuple, it can contain a mix of expression, types, aliases, etc, and therefore can be used like this: ...(int, "ha!", writeln); // can contain anything usable as a template argument Other examples: int x; double y; ...(x, y) = ...(1, 2.3); // multiple assignments ...(x, y) = getPackedTuple(); And finally, we could support expanding whole expressions that have a packed tuple in them by shifting the expanding three-dot outward, as you can do with C++11: ...(int, double) x; func(exp(x+5)...); // expands to: func(exp(x[0]+5), exp(x[1]+5)); Wouldn't that be great? After some time, if desired, auto-expanding tuples could be deprecated. The migration path wouldn't be too hard, nor too verbose: just add those three-dots right and left as needed. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Aug 20 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 8:43 AM, Kenji Hara wrote:
 2013/8/20 Dicebot <public dicebot.lv <mailto:public dicebot.lv>>

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


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

Ome question would be whether appropriate inlining could solve the performance disadvantage of Tuple. Andrei
Aug 20 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 20, 2013 at 02:40:00AM +0200, Meta wrote:
 On Tuesday, 20 August 2013 at 00:29:17 UTC, H. S. Teoh wrote:
Sounds like you're confused about what built-in tuples are (and
you wouldn't be the first -- they're rather confusing things).

I know the difference between std.typecons.Tuple and the built-in tuples. What I'm confused about is I thought that the main objective of the tuple literal syntax (destructuring/pattern matching aside) was a means to have first-class tuples. That is, tuples that have their own literal syntax, have a list of valid operations that can be done on them, can be passed to functions, and can be returned from functions.

Actually, reading through DIP32 again, it sounds like Kenji is proposing the *same* syntax for both built-in tuples and std.typecons.Tuple. In the code example under "Generic type/expression tuple syntax", he refers to them respectively as "tuple type" and "tuple value". Mixing is also allowed (e.g., in the "alias Fields" line). So it sounds like this is similar to what bearophile was suggesting -- the unification of built-in tuples and Phobos Tuples. I suppose the intention is that if a built-in tuple like (1, "a", 1.0) is used as a value, it would be automatically translated into a runtime tuple value. I'm not sure if the reverse is possible, though, since if the tuple contains some runtime values, then it's not possible to translate it back into a built-in tuple. Actually, going in either direction requires some restrictions; for example, if a tuple contains a type, like (1, int), then it's impossible to translate it into a runtime tuple (types have no runtime value in and of themselves). Similarly, if a tuple contains a runtime variable, then it's impossible to use it as a compile-time tuple. But if a tuple contains only compile-time known values, then it's in theory usable both as a built-in tuple and a runtime tuple. There might be some areas where this conflation may cause trouble, though; for example, if you have a tuple (1, x) where x is a runtime variable, then should it be treated as (1, {alias of x}) or (1, {runtime value of x})? The former would happen if you pass it to a template that expects an int and and alias parameter, for example, and the latter if you try to store this tuple into a variable. It may lead to this weird situation: template Tmpl(int x, alias y) { ... } int x=123; auto tup = {1; x}; alias T = Tmpl!tup; // OK, 1 -> int x, x -> alias y auto tup2 = tup; // store {1;123} into variable alias U = Tmpl!tup2; // ERROR: cannot instantiate template with runtime variable Actually, looking at this again, it seems the problem is with the "tup = {1; x}" line. Does {1; x} in the above code mean {1; 123}, or does it mean {1; {alias of x}}? For example, if you wrote this: int x=123; auto tup = {1; x}; x++; writeln(tup); What should be the output? Should the output change if the second line is changed to: alias tup = {1; x}; ? T -- A mathematician is a device for turning coffee into theorems. -- P. Erdos
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
Random idea - what do you thing about merging current Tuple and 
TypeTuple into one and than separating them back with new and 
clear semantics - "run-time tuple" vs "compile-time tuple" with 
two distinct literals? TypeTuple and Tuple then can remain as 
compatibility deprecated implementations.
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 01:06:28 UTC, H. S. Teoh wrote:
 Actually, reading through DIP32 again, it sounds like Kenji is 
 proposing
 the *same* syntax for both built-in tuples and 
 std.typecons.Tuple. In
 the code example under "Generic type/expression tuple syntax", 
 he refers
 to them respectively as "tuple type" and "tuple value". Mixing 
 is also
 allowed (e.g., in the "alias Fields" line).

Maybe mixing should be disallowed, then, unless your tuple was constructed from a variadic template argument list. auto tup = #(1, int); //ERROR template TMP(T...) { auto tup = T; }
 So it sounds like this is similar to what bearophile was 
 suggesting --
 the unification of built-in tuples and Phobos Tuples. I suppose 
 the
 intention is that if a built-in tuple like (1, "a", 1.0) is 
 used as a
 value, it would be automatically translated into a runtime 
 tuple value.
 I'm not sure if the reverse is possible, though, since if the 
 tuple
 contains some runtime values, then it's not possible to 
 translate it
 back into a built-in tuple.

 Actually, going in either direction requires some restrictions; 
 for
 example, if a tuple contains a type, like (1, int), then it's 
 impossible
 to translate it into a runtime tuple (types have no runtime 
 value in and
 of themselves). Similarly, if a tuple contains a runtime 
 variable, then
 it's impossible to use it as a compile-time tuple. But if a 
 tuple
 contains only compile-time known values, then it's in theory 
 usable both
 as a built-in tuple and a runtime tuple.

 There might be some areas where this conflation may cause 
 trouble,
 though; for example, if you have a tuple (1, x) where x is a 
 runtime
 variable, then should it be treated as (1, {alias of x}) or (1, 
 {runtime
 value of x})? The former would happen if you pass it to a 
 template that
 expects an int and and alias parameter, for example, and the 
 latter if
 you try to store this tuple into a variable. It may lead to 
 this weird
 situation:

 	template Tmpl(int x, alias y) { ... }
 	int x=123;
 	auto tup = {1; x};
 	alias T = Tmpl!tup;	// OK, 1 -> int x, x -> alias y
 	auto tup2 = tup;	// store {1;123} into variable
 	alias U = Tmpl!tup2;	// ERROR: cannot instantiate template 
 with runtime variable

 Actually, looking at this again, it seems the problem is with 
 the "tup =
 {1; x}" line. Does {1; x} in the above code mean {1; 123}, or 
 does it
 mean {1; {alias of x}}? For example, if you wrote this:

 	int x=123;
 	auto tup = {1; x};
 	x++;
 	writeln(tup);

 What should be the output? Should the output change if the 
 second line
 is changed to:

 	alias tup = {1; x};

 ?


 T

Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
Aggh, misposted. Let's try that again.

On Tuesday, 20 August 2013 at 02:51:20 UTC, Meta wrote:
 On Tuesday, 20 August 2013 at 01:06:28 UTC, H. S. Teoh wrote:
 Actually, reading through DIP32 again, it sounds like Kenji is 
 proposing
 the *same* syntax for both built-in tuples and 
 std.typecons.Tuple. In
 the code example under "Generic type/expression tuple syntax", 
 he refers
 to them respectively as "tuple type" and "tuple value". Mixing 
 is also
 allowed (e.g., in the "alias Fields" line).


Maybe mixing should be disallowed, then, unless your tuple was constructed from a variadic template argument list. //Error. Tuple containing types //at runtime doesn't make any sense auto tup = #(1, int); //Error auto tup = #(int, string); //Ok auto tup = #(1, "a", true); T[0] Test(T...)(T ts) { //Okay, each element of T can //be statically inspected to ensure //that you don't do something weird auto tup = T; //Also okay alias tup = T; //Error auto tup = #(int, string, bool); //Ok alias tup = #(int, string, bool); }
 There might be some areas where this conflation may cause 
 trouble,
 ...

 Actually, looking at this again, it seems the problem is with 
 the "tup = {1; x}" line. Does {1; x} in the above code mean 
 {1; 123}, or does it mean {1; {alias of x}}? For example, if 
 you wrote this:

 	int x=123;
 	auto tup = {1; x};
 	x++;
 	writeln(tup);

 What should be the output?


I'd say that x++ would not modify the x within the tuple. It's the same as: int x = 123; auto y = x; x++; writeln(y); Y is not changed, of course. However, if the tuple contains a reference type, such as a slice, then it would be modified. int[] x = [123]; auto tup = #(1, x); x[]++; //Prints #(1, [124]) writeln(tupe);
 Should the output change if the second line
 is changed to:

 	alias tup = {1; x};

 ?


I don't think this should be possible. It would be the same as doing: alias two = 3; //Error Unless the tuple contained only types. Then it would be possible. alias intAndStr = #(int, string); //Ok The semantics are fairly easy when a tuple contains only values and only types. The hard part is when it contains both values AND types, so that should be severely limited, maybe only within variadic templates. I can't remember where this was mentioned... I think it was in one of the other tuple threads I linked, and I think you brought it up, Teo. auto tup = #(1, "a"); alias tupType = typeof(tup); While tup is a value, its type is #(int, string). In other words, the type of a tuple value is a TypeTuple (alias tuple, whatever). Which means the type of a tuple is a tuple itself, which is pretty nifty.
Aug 19 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--e89a8f646ff5aa91c004e4587f1f
Content-Type: text/plain; charset=UTF-8

2013/8/20 H. S. Teoh <hsteoh quickfur.ath.cx>

 Actually, reading through DIP32 again, it sounds like Kenji is proposing
 the *same* syntax for both built-in tuples and std.typecons.Tuple. In
 the code example under "Generic type/expression tuple syntax", he refers
 to them respectively as "tuple type" and "tuple value". Mixing is also
 allowed (e.g., in the "alias Fields" line).

Honestly, I had intended DIP32 to provide *uniform* syntax for both built-in tuple and std.typecons.Tuple. However, finally, I noticed that would be _impossible_. I'll withdraw DIP32 and will open new DIP for only built-in tuple syntax proposal. Kenji Hara --e89a8f646ff5aa91c004e4587f1f Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">2013= /8/20 H. S. Teoh <span dir=3D"ltr">&lt;<a href=3D"mailto:hsteoh quickfur.at= h.cx" target=3D"_blank">hsteoh quickfur.ath.cx</a>&gt;</span><br></div><div= class=3D"gmail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;= margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color= :rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=3D"i= m"> Actually, reading through DIP32 again, it sounds like Kenji is proposing<br=
</div>

the code example under &quot;Generic type/expression tuple syntax&quot;, he= refers<br> to them respectively as &quot;tuple type&quot; and &quot;tuple value&quot;.= Mixing is also<br> allowed (e.g., in the &quot;alias Fields&quot; line).<br></blockquote><div>= <br></div><div>=C2=A0Honestly, I had intended DIP32 to provide *uniform* sy= ntax for both built-in tuple and std.typecons.Tuple.</div><div>However, fin= ally, I noticed that would be _impossible_.</div> <div><br></div><div>I&#39;ll withdraw DIP32 and will open new DIP for only = built-in tuple syntax proposal.</div><div><br></div><div>Kenji Hara</div></= div></div></div> --e89a8f646ff5aa91c004e4587f1f--
Aug 19 2013
prev sibling next sibling parent reply Kenji Hara <k.hara.pg gmail.com> writes:
--047d7b6d9bac02aa4504e458b959
Content-Type: text/plain; charset=UTF-8

Sorry I cannot reply to each thread comments quickly, so I discharge my
opinions at once.

----
D's built-in tuple can contain following entities:
 - Type
    int, long, array types, AA types, user-defined types, etc
 - Expressions
    interger, string literal, etc
 - Symbol
    user-defined types, templates, template instances, etc

Note that: an user-defined type would be treated as both Type and Symbol.

template Test() {}
alias X = std.typetuple.TypeTuple!(
    int, long, char[], int[int], const Object,  // Types
    1, "str", [1,2,3],  // Expressions (literal values)
    object.Object, Test, Test!(),   // Symbols
);

If all of the elements in a built-in tuple are Type, today it is normally
called "Type Tuple".
If all of the elements in a built-in tuple are Expressions, today it is
normally called "Expression Tuple".

Note that: today we cannot create a built-in tuple without using
TemplateTupleParameter.
TemplateTupleParameter cannot take expressions non-literal expressions,
therefore
most of current built-in tuples would contains only literal values as the
Expressions.

----
std.typecons.Tuple is an artifact of built-in tuple + alias this.

struct Tuple(T...) {
    T expand;   // 'expand' is a built-in tuple of
                // the implicitly defined fields that
                // typed T[0], T[1], ... T[$-1].
                // In spec, this is called "TupleDeclaration".
    alias expand this;  // forward indexing/slicing operators to
                        // the TupleDeclaration 'expand'
}
Tuple!(int, string) t;
t[];        // t.expand[]
t[0..$];    // t.expand[0..$]
t[1];       // t.expand[1]

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

If you want to return multiple values from a function, you must always wrap
them by std.typecons.Tuple, or other used-defined types. You cannot
directly return built-in tuple from a function.
(Built-in tuple return is mostly equivalent with multiple-value-return
issue. However it would be mostly impossible that defining calling
conversion scheme for that in portable)

----
The combination of built-in tuple and alias this would be one of the case
of built-in tuple of non-literal Expressions.
For example, `t.expand[1]` is equivalent with the dot expression
`t.__field_1` which cannot be taken by TemplateTupleParameter.
Therefore, `t.expand` would be the built-in tuple of the two dot
expressions `t.__field_0` and `t.__field_1`.

Therefore, calling built-in tuple "Alias Tuple" would not be correct so
built-in tuple can contain expressions that cannot be aliased.

----
My opinions agains various syntax proposals:

#(1, "str")
--> The character '#' is already used for the start of "Special Token
Sequences"
http://dlang.org/lex.html#Special Token Sequence

It is recognized in lexing phase, so adding semantic meaning to the '#'
character would be a contradict of D's principle.

Quote from http://dlang.org/lex.html
"The lexical analysis is independent of the syntax parsing and the semantic
analysis."

Kenji Hara

--047d7b6d9bac02aa4504e458b959
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_extra">Sorr=
y I cannot reply to each thread comments quickly, so I discharge my opinion=
s at once.</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_ex=
tra">----<br>
</div><div class=3D"gmail_extra">D&#39;s built-in tuple can contain followi=
ng entities:<br></div><div class=3D"gmail_extra"><div class=3D"gmail_extra"=
=C2=A0- Type</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 int, long, arra=

<div class=3D"gmail_extra">=C2=A0- Expressions</div><div class=3D"gmail_ext= ra">=C2=A0 =C2=A0 interger, string literal, etc</div><div class=3D"gmail_ex= tra">=C2=A0- Symbol</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 user-defi= ned types, templates, template instances, etc</div> <div><br></div></div><div class=3D"gmail_extra">Note that: an user-defined = type would be treated as both Type and Symbol.</div><div class=3D"gmail_ext= ra"><br></div><div class=3D"gmail_extra"><div class=3D"gmail_extra">templat= e Test() {}</div> <div class=3D"gmail_extra">alias X =3D std.typetuple.TypeTuple!(</div><div = class=3D"gmail_extra">=C2=A0 =C2=A0 int, long, char[], int[int], const Obje= ct, =C2=A0// Types</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 1, &quot;s= tr&quot;, [1,2,3], =C2=A0// Expressions (literal values)</div> <div class=3D"gmail_extra">=C2=A0 =C2=A0 object.Object, Test, Test!(), =C2= =A0 // Symbols</div><div class=3D"gmail_extra">);</div><div><br></div></div=
<div class=3D"gmail_extra">If all of the elements in a built-in tuple are =

<div class=3D"gmail_extra">If all of the elements in a built-in tuple are E= xpressions, today it is normally called &quot;Expression Tuple&quot;.</div>= <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Note that: = today we cannot create a built-in tuple without using TemplateTupleParamete= r.</div> <div class=3D"gmail_extra">TemplateTupleParameter cannot take expressions n= on-literal expressions, therefore</div><div class=3D"gmail_extra">most of c= urrent built-in tuples would contains only literal values as the Expression= s.</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">----</div><= div class=3D"gmail_extra">std.typecons.Tuple is an artifact of built-in tup= le + alias this.<br></div><div class=3D"gmail_extra"><br></div><div class= =3D"gmail_extra"> <div class=3D"gmail_extra">struct Tuple(T...) {</div><div class=3D"gmail_ex= tra">=C2=A0 =C2=A0 T expand; =C2=A0 // &#39;expand&#39; is a built-in tuple= of</div><div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 // the implicitly defined fields that</div> <div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 // typed T[0], T[1], ... T[$-1].</div><div class=3D"gmail_extra">= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // In spec, this is= called &quot;TupleDeclaration&quot;.</div><div class=3D"gmail_extra">=C2= =A0 =C2=A0 alias expand this; =C2=A0// forward indexing/slicing operators t= o</div> <div class=3D"gmail_extra">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // the TupleDeclaration &#39;expand&#39= ;</div><div class=3D"gmail_extra">}</div><div class=3D"gmail_extra">Tuple!(= int, string) t;</div><div class=3D"gmail_extra">t[]; =C2=A0 =C2=A0 =C2=A0 = =C2=A0// t.expand[]</div> <div class=3D"gmail_extra">t[0..$]; =C2=A0 =C2=A0// t.expand[0..$]</div><di= v class=3D"gmail_extra">t[1]; =C2=A0 =C2=A0 =C2=A0 // t.expand[1]</div><div=
<br></div></div><div class=3D"gmail_extra">So, std.typecons.Tuple=C2=A0_is=

<div class=3D"gmail_extra">We should not define new syntax for the library = utility std.typecons.Tuple.</div><div class=3D"gmail_extra"><br></div><div = class=3D"gmail_extra">If you want to return multiple values from a function= , you must always wrap them by std.typecons.Tuple, or other used-defined ty= pes.=C2=A0You cannot directly return built-in tuple from a function.</div> <div class=3D"gmail_extra">(Built-in tuple return is mostly equivalent with= multiple-value-return issue. However it would be mostly impossible that de= fining calling conversion scheme for that in portable)</div><div class=3D"g= mail_extra"> <br></div><div class=3D"gmail_extra">----</div><div class=3D"gmail_extra">T= he combination of built-in tuple and alias this would be one of the case of= built-in tuple of non-literal Expressions.</div><div class=3D"gmail_extra"=
For example, `t.expand[1]` is equivalent with the dot expression `t.__fiel=

<div class=3D"gmail_extra">Therefore, `t.expand` would be the built-in tupl= e of the two dot expressions `t.__field_0` and `t.__field_1`.</div><div cla= ss=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Therefore, calling = built-in tuple &quot;Alias Tuple&quot; would not be correct=C2=A0so built-i= n tuple can contain expressions that cannot be aliased.</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">----</div><= div class=3D"gmail_extra">My opinions agains various syntax proposals:</div=
<div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">#(1, &quot=

<div class=3D"gmail_extra">--&gt; The character &#39;#&#39; is already used= for the start of &quot;Special Token Sequences&quot;</div><div class=3D"gm= ail_extra"><a href=3D"http://dlang.org/lex.html#Special">http://dlang.org/l= ex.html#Special</a> Token Sequence</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">It is recog= nized in lexing phase, so adding semantic meaning to the &#39;#&#39; charac= ter would be a contradict of D&#39;s principle.</div><div class=3D"gmail_ex= tra"> <br></div><div class=3D"gmail_extra">Quote from <a href=3D"http://dlang.org= /lex.html">http://dlang.org/lex.html</a></div><div class=3D"gmail_extra">&q= uot;The lexical analysis is independent of the syntax parsing and the seman= tic analysis.&quot;</div> <div><br></div><div>Kenji Hara</div></div></div> --047d7b6d9bac02aa4504e458b959--
Aug 19 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Aug 21, 2013 at 03:43:45AM +0200, bearophile wrote:
 Andrei Alexandrescu:
 
1. What do we need?

We can live fine without a syntax to manage tuples, so strictly speaking we need nothing (almost, I'd like to kill one currently accepted syntax, see below). But when you write D in a high-level style, and you are used to other functional or scripting languages, in several cases you desire a more handy/compact syntax to manage tuples. Tuples are simple data structure, so the operations you want to do with them are few and simple: - To define a tuple of various fields of different type, that is a tuple literal, to create a tuple;

This is adequately taken care of by std.typecons.Tuple, isn't it?
 - A way to read and write items of a tuple (unless it's read-only),
 D uses a nice syntax [i] as arrays indexing, but i can't be a
 run-time value.

You can't make 'i' a runtime value because D is a statically-typed language. The compiler has to know at compile-time what type tup[i] is. Otherwise it couldn't generate machine code for things like: void func(Tuple t, int i) { auto x = t[i]; // what's the type of x? }
 - With the Phobos tuple we are used to giving names to fields. It's
 handy, but it's not so necessary if you have a way to assign tuple
 items to variables, defined in-place. There are several places where
 pulling apart a tuple in that way is useful, here I use a basic
 syntax to be more clear:
 
 Assignments:
 auto (a, b) = t1;

Currently you could do: Tuple!(...) t1; auto a = t1[0]; auto b = t1[1]; Not as nice, certainly, but I wouldn't consider it a deal-breaker.
 In function signatures:
 auto mult = ((int x, int y)) => x * y;

Currently we have: auto mult = (Tuple!(int,int) t) => t[0] * t[1]; Not as pretty, but surely still readable and usable? Or am I missing something?
 In foreach loops:
 
 void main() {
   import std.range, std.stdio;
   auto a = [10, 20];
   auto b = [100, 200];
 
   // Currently D supports this syntax:
   foreach (x, y; zip(a, b))
     writeln(x, " ", y);
 
   // But it's unreliable, now x is the index of the
   // array instead of the first tuple fields, so I
   // think this feature of D should be killed as
   // soon as possible:
   foreach (x, y; zip(a, b).array)
     writeln(x, " ", y);
 }

Isn't this an auto-expanding tuple that Andrei didn't like? Though granted, the current way of expressing it is not as nice: foreach (t; zip(a,b)) { writeln(t[0], " ", t[1]); } [...]
 There are few more little pieces that are useful, like unpacking an
 array:
 
 string s = "red blue";
 auto (col1, col2) = s.split;

What should happen if s is a runtime variable that may not have the same number of words as the number of elements in the tuple on the left-hand side? A runtime error? [...]
 For an use case of the assignment from an array, let's say you have
 a text file containing two numbers in a line, that you want to read:
 
 const (x, y) = filein.byLine.front.split.to!(int[]);

Again, what should happen if at runtime the lines have more or less elements than the tuple on the left-hand side? A runtime error? I didn't look in detail at your red-black tree example, or the Huffman encoding example, but it would seem that currently, std.typecons.Tuple more-or-less suffices for your needs, right? Except for some syntactic unpleasantness, that is. Or is there something that *can't* be expressed in an adequate way by the current Tuple that I missed? Also, I note that none of your examples need TypeTuples at all, so it would appear that your use case do not necessitate the unification of TypeTuple with Tuple. Though that would be nice conceptually, it does introduce a lot of complications into the language and require addressing some non-trivial issues which, taking a step back, perhaps we don't *need* to address, because they are of little or no practical use? T -- Knowledge is that area of ignorance that we arrange and classify. -- Ambrose Bierce
Aug 20 2013
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
H. S. Teoh:

 This is adequately taken care of by std.typecons.Tuple, isn't 
 it?

 You can't make 'i' a runtime value because D is a 
 statically-typed language.

Yep. (From several persons explaining me similar things in answers to my posts it seems I am not expressing well that I know what I am discussing about. In future I will add notes to avoid this).
 Currently you could do:

 	Tuple!(...) t1;
 	auto a = t1[0];
 	auto b = t1[1];

 Not as nice, certainly, but I wouldn't consider it a 
 deal-breaker.

 Currently we have:

 	auto mult = (Tuple!(int,int) t) => t[0] * t[1];

 Not as pretty, but surely still readable and usable? Or am I 
 missing
 something?

 I didn't look in detail at your red-black tree example, or the 
 Huffman
 encoding example, but it would seem that currently, 
 std.typecons.Tuple
 more-or-less suffices for your needs, right? Except for some 
 syntactic unpleasantness, that is.

 Or is there something that *can't* be expressed in an adequate 
 way by the current Tuple that I missed?

See what I wrote at the beginning of the post:
 We can live fine without a syntax to manage tuples, so strictly
 speaking we need nothing


The semantics of tuples is simple and everything you can do when them is very easy to do in a language like C. The point of having tuples is to write code that is more readable, shorter, more expressive, a bit higher level. std.typecons.Tuple misses some expressiveness that some programmers think is handy to have, that I have listed in my post.
 What should happen if s is a runtime variable that may not have 
 the same
 number of words as the number of elements in the tuple on the 
 left-hand
 side? A runtime error?

 Again, what should happen if at runtime the lines have more or 
 less
 elements than the tuple on the left-hand side? A runtime error?

The answer I wrote in another post:
 Runtime boundary checks and tests are not needed if you unpack 
 a fixed-sized array:

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

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

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

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

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


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

 Isn't this an auto-expanding tuple that Andrei didn't like?

I don't know. Ask to him. Bye, bearophile
Aug 21 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 20 August 2013 at 03:33:51 UTC, Kenji Hara wrote:
 ----
 My opinions agains various syntax proposals:

 #(1, "str")
 --> The character '#' is already used for the start of "Special 
 Token
 Sequences"
 http://dlang.org/lex.html#Special Token Sequence

 It is recognized in lexing phase, so adding semantic meaning to 
 the '#'
 character would be a contradict of D's principle.

 Quote from http://dlang.org/lex.html
 "The lexical analysis is independent of the syntax parsing and 
 the semantic
 analysis."

 Kenji Hara

There are various other characters that could be substituted for # e.g. &(1, "string") http://forum.dlang.org/post/cokiixatvjmngggpblma forum.dlang.org
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 03:33:51 UTC, Kenji Hara wrote:
 Sorry I cannot reply to each thread comments quickly, so I 
 discharge my
 opinions at once.

One thing that I think does not get deserved attention is that built-in expression tuple are not limited to compile-time values. Lets consider this simple example: void foo(T...)(T args) { pragma(msg, args); pragma(msg, typeof(args)); } void main() { int a, b; foo(a, b); } ----------------------- /d147/f686.d(3): Error: variable _param_0 cannot be read at compile time /d147/f686.d(3): Error: variable _param_1 cannot be read at compile time tuple(_param_0, _param_1) (int, int) ----------------------- What we have here are two completely different _built-in_ tuple types. "T" is pure template arguments list and is pretty much equal TypeTuple!(int, int). But what is "args"? It uses the very same built-in tuple syntax but it is much closer to std.typecons.Tuple in its behavior (actually, latter is implemented in terms of it as I was pointed out) - it is an entity that provides abstraction of top of group of run-time values. It does not have any binary structure on its own (built on top of existing values) but observable semantic are very "run-time'ish". What bothers me is the question "can we clean this up and bring those two worlds together, even at cost of minor breakage?". I am not speaking about literals here or unpacking or whatever. I am speaking about re-defining semantics so that struct-based Tuple and built-in syntax sugar in form of run-time expression tuple both get merged into one built-in construct which can be used in wider variety of places. At least right now I can't find any technical objections why expression tuple can't use std.typecons.Tuple ABI when returned from function but still be automatically expanded when passed into functions. Kenji, what is your your opinion about complexity to implement something like that in DMD?
Aug 20 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
This is the reason I had originally thought Kenji's DIP was about 
run-time tuples. If it's just syntactic sugar over 
std.typecons.Tuple (plus some extra destructuring/pattern 
matching stuff), it would require no ABI changes and no changes 
to TypeTuple semantics. The one thing it wouldn't do is unify 
Tuple and TypeTuple.

However, with compiler support, we can make this situation 
better. TypeTuple stays as-is, while Tuple becomes a value 
instead of a type, which has its own literal syntax. This means 
that typeof(tuple(1, "a")) is not Tuple!(int, string), as in the 
struct, but TypeTuple!(int, string), as in the compiler tuple.

You could still do all the stuff that can be done with TypeTuple 
currently, but it should be strongly discouraged to mix types and 
values within TypeTuple, or even limited by the compiler. This 
creates a clear distinction between runtime tuples and TypeTuple. 
It becomes much easier to reason about their semantics, as we can 
think of TypeTuple as a type, just like int, string, double, 
etc., and Tuple as a value, just like 1, "a", 2.3, etc. The only 
difference between TypeTuple and regular types is that there are 
a few special static operations that can be used to manipulate 
it. Otherwise it behaves as a type.
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 13:17:44 UTC, Meta wrote:
 This is the reason I had originally thought Kenji's DIP was 
 about run-time tuples. If it's just syntactic sugar over 
 std.typecons.Tuple (plus some extra destructuring/pattern 
 matching stuff), it would require no ABI changes and no changes 
 to TypeTuple semantics. The one thing it wouldn't do is unify 
 Tuple and TypeTuple.

Syntax sugar will only hide and eventually increase confusion, it won't solve the semantical issue. This is why we are having this topic IMHO, bunch of quite experienced D developers can't even agree on how existing feature behaves :) Including those who is it all the time! It is clear indicator that syntax is not the one to blame.
 However, with compiler support, we can make this situation 
 better. TypeTuple stays as-is, while Tuple becomes a value 
 instead of a type, which has its own literal syntax. This means 
 that typeof(tuple(1, "a")) is not Tuple!(int, string), as in 
 the struct, but TypeTuple!(int, string), as in the compiler 
 tuple.

I am proposing something more radical. Deprecate _both_ TypeTuple and Tuple. Clearly define the difference between built-in type tuple and expression tuple (latter being instance of former). Preserve auto-expansion. Provide two different literals to remove ambiguity between referencing symbol as a value and referencing it as an alias. Make compiler auto-generate Tuple-like struct type for expression tuples that need to be returned from functions. Create some new type in std.typecons for those who don't want auto-expansion. It won't even break stuff.
Aug 20 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 13:57:49 UTC, Dicebot wrote:
 Syntax sugar will only hide and eventually increase confusion, 
 it won't solve the semantical issue. This is why we are having 
 this topic IMHO, bunch of quite experienced D developers can't 
 even agree on how existing feature behaves :) Including those 
 who is it all the time! It is clear indicator that syntax is 
 not the one to blame.

My suggestions are predicated on the fact that I think tuples are more or less fine as-is. They just need some syntactic sugar for literals and destructuring/pattern matching to make them more usable. Built-in tuples are confusing, I think, because they're named TypeTuple, which makes people conflate them with std.typecons.Tuple. Another reason is that TypeTuple can contain both values and types at the same time, so it's confusing as to what you can do with them. "Why can you only assign a TypeTuple to a variable if it contains values but not types? Why, then, can't you return TypeTuple!(1, 2.3) from a function? Is it not really a variable? Why does `alias t = TypeTuple!(1, 2.3)` work, but `alias n = 3` not work? Is this f*$#ing thing a value or a type?" - D Newbie Everything else aside, I think the best possible change that would make the whole tuple situation better is to limit or outright ban the mixing of values and types within TypeTuple. Even better is to always treat TypeTuple as a type, and not a value. That ship has already sailed, but we can at least try to enforce it through convention.
 I am proposing something more radical. Deprecate _both_ 
 TypeTuple and Tuple. Clearly define the difference between 
 built-in type tuple and expression tuple (latter being instance 
 of former). Preserve auto-expansion. Provide two different 
 literals to remove ambiguity between referencing symbol as a 
 value and referencing it as an alias. Make compiler 
 auto-generate Tuple-like struct type for expression tuples that 
 need to be returned from functions. Create some new type in 
 std.typecons for those who don't want auto-expansion.

 It won't even break stuff.

I think my position has changed to suggest nearly the same thing. There needs to be a clear separation between built-in tuples and tuple values. A runtime tuple literal syntax helps with that. Making typeof(tuple(1, 2.3)) == TypeTuple!(int, double) helps as well, because it is now clear that one is a value and one is a type. Limiting the mixing of values and types within TypeTuple helps with that. This would allow both Tuple and TypeTuple to be deprecated. Tuple wouldn't be needed anymore, because we would have a literal syntax to replace it. It would only be there for backwards compatibility. With Tuple deprecated, std.typetuple.TypeTuple could be renamed Tuple, and we would then have only one thing with the name Tuple in the language.
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Kenji Hara:

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

With your idea is there a way to unpack a short array into variables? This is an handy operation I do often in Python:
 s = "red blue"
 (a, b) = s.split()
 a



 b



Bye, bearophile
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
 s = "red blue"
 (a, b) = s.split()
 a



 b




It's supported in Haskell too: Prelude> let s = "red blue" Prelude> let [a, b] = words s Prelude> a "red" Prelude> b "blue" Bye, bearophile
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
bearophile I really respect informational contribution you have 
been doing in D community but in my opinion mentioning random 
snippets from other languages is the least useful thing possible 
in this thread. It is even less useful than discussing syntax.
Aug 20 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--047d7b66f599f015ba04e462ea1d
Content-Type: text/plain; charset=UTF-8

2013/8/20 Dicebot <public dicebot.lv>

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

"args" is a built-in tuple of two function parameter variables. In binary level, args[0] and args[1] could be bounded to completely individual storage. (Even if args[1] is on stack, args[0] may be on register) On the other hand, std.typecons.Tuple is a struct. Its second field has the memory address which follows of the first field. What bothers me is the question "can we clean this up and bring those two
 worlds together, even at cost of minor breakage?". I am not speaking about
 literals here or unpacking or whatever. I am speaking about re-defining
 semantics so that struct-based Tuple and built-in syntax sugar in form of
 run-time expression tuple both get merged into one built-in construct which
 can be used in wider variety of places.

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

Automatically packing/unpacking would need hidden runtime cost. Kenji Hara --047d7b66f599f015ba04e462ea1d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">2013/8/20 Dicebot <span dir=3D"ltr">&lt;<a href=3D"mailto:= public dicebot.lv" target=3D"_blank">public dicebot.lv</a>&gt;</span><br><d= iv class=3D"gmail_extra"><div class=3D"gmail_quote"><blockquote class=3D"gm= ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-l= eft-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"> <div class=3D"im"><span style=3D"color:rgb(34,34,34)">What we have here are= two completely different _built-in_ tuple types. &quot;T&quot; is pure tem= plate arguments list and is pretty much equal TypeTuple!(int, int). But wha= t is &quot;args&quot;? It uses the very same built-in tuple syntax but it i= s much closer to std.typecons.Tuple in its behavior (actually, latter is im= plemented in terms of it as I was pointed out) - it is an entity that provi= des abstraction of top of group of run-time values. It does not have any bi= nary structure on its own (built on top of existing values) but observable = semantic are very &quot;run-time&#39;ish&quot;.</span></div> </blockquote><div><br></div><div>&quot;args&quot; is a built-in tuple of tw= o function parameter variables. In binary level, args[0] and args[1] could = be bounded to completely individual storage. (Even if args[1] is on stack, = args[0] may be on register)</div> <div>On the other hand, std.typecons.Tuple is a struct. Its second field ha= s the memory address which follows of the first field.</div><div><br></div>= <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"> What bothers me is the question &quot;can we clean this up and bring those = two worlds together, even at cost of minor breakage?&quot;. I am not speaki= ng about literals here or unpacking or whatever. I am speaking about re-def= ining semantics so that struct-based Tuple and built-in syntax sugar in for= m of run-time expression tuple both get merged into one built-in construct = which can be used in wider variety of places.</blockquote> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"> <br> At least right now I can&#39;t find any technical objections why expression= tuple can&#39;t use std.typecons.Tuple ABI when returned from function but= still be automatically expanded when passed into functions. Kenji, what is= your your opinion about complexity to implement something like that in DMD= ?<br> </blockquote></div><br></div><div class=3D"gmail_extra">Automatically packi= ng/unpacking would need hidden runtime cost.</div><div class=3D"gmail_extra= "><br></div><div class=3D"gmail_extra">Kenji Hara</div></div> --047d7b66f599f015ba04e462ea1d--
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 15:43:39 UTC, Kenji Hara wrote:
 On the other hand, std.typecons.Tuple is a struct. Its second 
 field has the
 memory address which follows of the first field.

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

Will it be any more costly then returning std.typecons.Tuple and unpacking it manually? And, well, do we have _any_ other option of returning a tuple with no runtime costs right now anyway? Considering we are far away from stable ABI that does not seem to be a real issue.
Aug 20 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--047d7b6d9bac69daef04e46333de
Content-Type: text/plain; charset=UTF-8

2013/8/20 bearophile <bearophileHUGS lycos.com>

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

With your idea is there a way to unpack a short array into variables? This is an handy operation I do often in Python: s = "red blue"
 (a, b) = s.split()
 a



 b




My position to such a feature is constant. We should not conflate tuple unpacking and array unpacking. But, extending unpacking syntax mentioned in DIP32 might help it. // Just an idea: extending DIP32 unpacking syntax import std.typecons : tuple; auto tup = tuple(1, tuple(2,3), [4,5]); { auto a, {b, c}, [d, e] } = tup; //{ auto a, [b, c], {d, e} } = tup; // cause compile-time error assert(a == 1); assert(b == 2 && c == 3); assert(d == 4 && e == 5); However, array unpacking would require *hidden* runtime boundary check. In above example code, assert(tup[2].length == 2); // or if (tup[2].length != 2) throw Error("Runtime mismatch of unpacking pattern"); // or similar should be implicitly inserted by compiler, even in system code. I'm not sure that is acceptable cost or not. Kenji Hara --047d7b6d9bac69daef04e46333de Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div>2013/8/20 bearophile <span dir=3D"ltr">&lt;<a href=3D= "mailto:bearophileHUGS lycos.com" target=3D"_blank">bearophileHUGS lycos.co= m</a>&gt;</span><br></div><div class=3D"gmail_extra"><div class=3D"gmail_qu= ote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bo= rder-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:so= lid;padding-left:1ex"> <div class=3D"im"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px= 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-= left-style:solid;padding-left:1ex">So, std.typecons.Tuple _is not special_.= You can define another Tuple struct in the same way.<br> We should not define new syntax for the library utility std.typecons.Tuple.= <br> </blockquote> <br></div> With your idea is there a way to unpack a short array into variables? This = is an handy operation I do often in Python:<br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px = 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l= eft-style:solid;padding-left:1ex"> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"> s =3D &quot;red blue&quot;<br> (a, b) =3D s.split()<br> a<br> </blockquote></blockquote></blockquote> &#39;red&#39;<br> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px = 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l= eft-style:solid;padding-left:1ex"> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"> b<br> </blockquote></blockquote></blockquote> &#39;blue&#39;<br></blockquote><div><br></div>My position to such a feature= is constant. We should not conflate tuple unpacking and array unpacking.<b= r><div><br></div><div>But, extending unpacking syntax mentioned in DIP32 mi= ght help it.</div> <div><br></div><div>// Just an idea: extending DIP32 unpacking syntax<br></= div><div>import std.typecons : tuple;<br></div><div>auto tup =3D tuple(1, t= uple(2,3), [4,5]);</div><div>{ auto a, {b, c}, [d, e] } =3D tup;<br></div><= div> //{ auto a, [b, c], {d, e} } =3D tup; =C2=A0 // cause compile-time error</d= iv><div>assert(a =3D=3D 1);</div><div>assert(b =3D=3D 2 &amp;&amp; c =3D=3D= 3);<br></div><div>assert(d =3D=3D 4 &amp;&amp; e =3D=3D 5);<br></div><div>= <br></div><div>However, array unpacking would require *hidden* runtime boun= dary check.</div> <div>In above example code,</div><div><br></div><div>=C2=A0 assert(tup[2].l= ength =3D=3D 2);</div><div>=C2=A0 // or</div><div>=C2=A0 if (tup[2].length = !=3D 2) throw Error(&quot;Runtime mismatch of unpacking pattern&quot;);</di= v><div>=C2=A0 // or similar</div> <div><br></div><div>should be implicitly inserted by compiler, even in sys= tem code.</div><div>I&#39;m not sure that is acceptable cost or not.</div><= div><br></div><div>Kenji Hara</div></div></div></div> --047d7b6d9bac69daef04e46333de--
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Dicebot:

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

Look better at them, those aren't random snippets, they show one more case of de-structuring, creating a tuple of variables out of an array. It's a commonly used operation in two very well designed languages that have tuples. Here we are discussing tuples and their packing and unpacking, so the two examples I've shown are very relevant, even if we decide to not support that specific feature. Bye, bearophile
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Kenji Hara:

 My position to such a feature is constant.

Even if your opinion is not changed, I have to show that common tuple-related features to the other persons that are reading this thread, because it's an an idea to keep in account (even if it's refused), and some other person could have an opinion different from yours.
 However, array unpacking would require *hidden* runtime 
 boundary check.
 In above example code,

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

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

Runtime boundary checks and tests are not needed if you unpack a fixed-sized array: auto tup = Tuple!(int, string[2])(1, ["red", "blue"]); auto {x, [c1, c2]} = tup; Regarding the de-structuring of dynamic arrays, I think it's not too much different than this: void main() { int[] a = [10, 20, 30]; int[2] b = a; } If you compile and run it without switches, you get at run-time: object.Error: lengths don't match for array copy, 2 = 3 While I receive no run-time errors if I compile with -noboundscheck. Bye, bearophile
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 20:16:54 UTC, Andrei Alexandrescu 
wrote:
 On 8/20/13 6:57 AM, Dicebot wrote:
 I am proposing something more radical. Deprecate _both_ 
 TypeTuple and
 Tuple. Clearly define the difference between built-in type 
 tuple and
 expression tuple (latter being instance of former).

But that can't be the case.

Can you elaborate on this? I can only judge by observable behavior which clearly says that typeof(TypeTuple!(2, 3)) is TypeTuple!(int, int). And when you use variadic template argument syntax in functions, you use "T..." (which is a built-in type tuple) to declare arguments (which is built-in expression tuple). There are probably some inconsistencies in implementation but this is the observable behavior that can be declared official.
 Preserve
 auto-expansion.

That would be problematic to say the least. (There have been a few discussions in this group; I've come to think auto expansion is fail.)

:O it is awesome! Stuff like foo(myStructInstance.tupleof) is very powerful tool for generic interfaces. Do you remember any keywords to look for to find those discussions? Ones I remember were mostly about auto-expansion _not_ happening in some reasonable places.
Aug 20 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 21:25:11 UTC, Andrei Alexandrescu 
wrote:
 "Spawn of Satan" would be a tad more appropriate.

I can not agree more.
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 21:25:11 UTC, Andrei Alexandrescu 
wrote:
 Ionno so I just summarized it.


 Andrei

I guess I need just deal with it and accept as given then :) Okay, it does not really change much for main issue I wanted to pay attention to - thin edge between run-time expression tuples and compile-time ones. Only problematic moment I can see so far is that compile-time tuples can contain both types and expressions at the same time. But this can be solved by considering them non-instantiatable type tuples - similar to existing handling. Or just call them "template argument lists" to be 100% straight and reserve word "tuple" for expression tuple while preserving "typeof" relation (and enhancing expression tuples with ABI). Sounds like dreaming? :)
Aug 20 2013
prev sibling next sibling parent "Tyler Jameson Little" <beatgammit gmail.com> writes:
On Tuesday, 20 August 2013 at 21:25:11 UTC, Andrei Alexandrescu 
wrote:
 On 8/20/13 1:24 PM, Dicebot wrote:
 That would be problematic to say the least. (There have been 
 a few
 discussions in this group; I've come to think auto expansion 
 is fail.)

:O it is awesome!

"Spawn of Satan" would be a tad more appropriate.

+1 I can stand explicit expansion though, like Go's variadic argument ellipses syntax: http://golang.org/doc/effective_go.html#append OT: I'm not really a fan of D's variadic function syntax. I'd prefer it to be explicit: int sum(int[] ar ...) { } int[3] foo = [4, 5, 6]; sum(foo...); sum(3, 4, foo...); // on my wish list...
 Stuff like foo(myStructInstance.tupleof) is very
 powerful tool for generic interfaces.

One problem with automatic expansion is that now there's a whole new kind - a single expression that doesn't quite have one value and one type, but instead is an explosion of other expressions. snip... Alternatively, we could do what Go does and prevent all packing altogether (if I understand what Go does correctly). That is, if a function returns a tuple you can't even keep that tuple together unless you use some handcrafted solution. In that case, before long there will be some "Pack" structure and some pack helper function, viz. the converse of .expand.

+1 I've been itching for multiple returns in D for a long time, and this seems like a nice way to add it in. I think I'd prefer to use tuple syntax instead though, just so there's less magic: (int, int) doStuff() { return (1, 2); } // syntax error auto a, b = doStuff(); // ok auto (a, b) = doStuff();
 Clearly both packing and unpacking tuples are necessary.

 snip...

 Andrei

OT: is the only thing stopping us from using the nice (x,y) syntax for tuples the comma operator? If so, can we take that mis-feature behind the woodshed and shoot it? I sincerely hope nobody is relying on it...
Aug 20 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--e89a8f646ff5dfd85904e46aa7a5
Content-Type: text/plain; charset=UTF-8

2013/8/21 Timon Gehr <timon.gehr gmx.ch>

 On 08/20/2013 10:16 PM, Andrei Alexandrescu wrote:

 (There have been a few discussions in this group; I've come to think
 auto expansion is fail.)

+1. :)

+1, too. Since I wrote a compiler patch for the auto expansion on function arguments, but it was rejected by Andrei. http://d.puremagic.com/issues/show_bug.cgi?id=2779 And today, I'm mostly consent in his opinion. Kenji Hara --e89a8f646ff5dfd85904e46aa7a5 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">2013= /8/21 Timon Gehr <span dir=3D"ltr">&lt;<a href=3D"mailto:timon.gehr gmx.ch"= target=3D"_blank">timon.gehr gmx.ch</a>&gt;</span><br><blockquote class=3D= "gmail_quote" style=3D"margin-top:0px;margin-right:0px;margin-bottom:0px;ma= rgin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);bo= rder-left-style:solid;padding-left:1ex"> <div class=3D"im">On 08/20/2013 10:16 PM, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;= margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color= :rgb(204,204,204);border-left-style:solid;padding-left:1ex"> (There have been a few discussions in this group; I&#39;ve come to think<br=

</blockquote> <br></div> +1. :)<br> </blockquote></div><br></div><div class=3D"gmail_extra">+1, too.</div><br c= lass=3D""><div class=3D"gmail_extra">Since I wrote a compiler patch for the= auto expansion on function arguments, but it was rejected by Andrei.<br></= div> <div class=3D"gmail_extra"><a href=3D"http://d.puremagic.com/issues/show_bu= g.cgi?id=3D2779">http://d.puremagic.com/issues/show_bug.cgi?id=3D2779</a>= =C2=A0<br></div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_ex= tra">And today, I&#39;m mostly consent in his opinion.</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">Kenji Hara<= /div></div> --e89a8f646ff5dfd85904e46aa7a5--
Aug 20 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--e89a8f646ff589280004e46b3995
Content-Type: text/plain; charset=UTF-8

2013/8/21 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>

 I think this whole thread is approaching things wrongly. It should be:

 1. What do we need?

Both a. Built-in tuple construction syntax and b. Built-in tuple deconstruction syntax 2. What does a solution look like in the current language?

a. alias Types = {int, long}; auto values = {1, "str"}; b. auto {a, b} = tup; // on variable declaration {a, b} = tup; // on assignment expression ... 3. Which parts of the solution are frequent/cumbersome enough to warrant a
 language change?

a1. To make std.typetuple.TypeTuple template unnecessary. a2. To keep std.typecons.Tuple as-is. a3. To make expression tuple more usable. Today making the built-in tuple of runtime values needs unavoidable runtime cost. int x, y; auto tup = TypeTuple!(x+1, y+2); // NG, template cannot take x+1 and y+2 because they are // expressions which cannot be evaluated in compile time auto tup = tuple(x+1, y+2); // NG, tup is not a builti-in tuple (it is an object of std.typecons.Tuple struct). auto tup = tuple(x+1, y+2).expand; // OK, tup is a builti-in tuple. But we cannot avoid the cost to pack in std.typecons.Tuple. Built-in tuple syntax would solve the issue. auto tup = {x+1, y+2}; // tup is a built-in tuple, and it would be equivalent with: // auto tup[0] = x+1, tup[1] = x*2; // pseudo code // so no packing cost in runtime is there. b. To make deconstruction code more readable. auto tup = std.typecons.tuple(1, "str"); auto a = tup[0], b = tup[1]; // Currrent: // Deconstruct two fields in tup to the two variables a and b auto {a, b} = tup; // New syntax: // Deconstruct syntax would recognize alias this tuple, // and expand it automatically. Kenji Hara --e89a8f646ff589280004e46b3995 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">2013= /8/21 Andrei Alexandrescu <span dir=3D"ltr">&lt;<a href=3D"mailto:SeeWebsit= eForEmail erdani.org" target=3D"_blank">SeeWebsiteForEmail erdani.org</a>&g= t;</span><br> <blockquote class=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;= margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color= :rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=3D"i= m"> I think this whole thread is approaching things wrongly. It should be:<br><= /div> <br> 1. What do we need?<br></blockquote><div><br></div><div>Both</div><div>a.= =C2=A0Built-in tuple construction syntax</div><div>and</div><div>b.=C2=A0Bu= ilt-in tuple deconstruction syntax=C2=A0</div><div><br></div><blockquote cl= ass=3D"gmail_quote" style=3D"margin-top:0px;margin-right:0px;margin-bottom:= 0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,2= 04);border-left-style:solid;padding-left:1ex"> 2. What does a solution look like in the current language?<br></blockquote>= <div><br></div><div><div>a.</div><div>=C2=A0 alias Types =3D {int, long};</= div><div>=C2=A0 auto values =3D {1, &quot;str&quot;};</div><div>b.</div><di= v>=C2=A0 auto=C2=A0{a, b} =3D tup; =C2=A0// on variable declaration</div> <div>=C2=A0 {a, b} =3D tup; =C2=A0 =C2=A0 =C2=A0 // on assignment expressio= n</div><div>=C2=A0 ...</div></div><div><br></div><blockquote class=3D"gmail= _quote" style=3D"margin-top:0px;margin-right:0px;margin-bottom:0px;margin-l= eft:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l= eft-style:solid;padding-left:1ex"> 3. Which parts of the solution are frequent/cumbersome enough to warrant a = language change?<br></blockquote><div><br></div><div><div>a1. To make std.t= ypetuple.TypeTuple template unnecessary.</div><div>a2. To keep std.typecons= .Tuple as-is.</div> <div>a3. To make expression tuple more usable.</div><div><br></div><div>=C2= =A0 Today making the built-in tuple of runtime values needs unavoidable run= time cost.</div><div><br></div><div>=C2=A0 int x, y;</div><div>=C2=A0 auto = tup =3D TypeTuple!(x+1, y+2);</div> <div>=C2=A0 // NG, template cannot take x+1 and y+2 because they are</div><= div>=C2=A0 // expressions which cannot be evaluated in compile time</div><d= iv>=C2=A0 auto tup =3D tuple(x+1, y+2);</div><div>=C2=A0 // NG, tup is not = a builti-in tuple (it is an object of std.typecons.Tuple struct).</div> <div>=C2=A0 auto tup =3D tuple(x+1, y+2).expand;</div><div>=C2=A0 //=C2=A0O= K, tup is a builti-in tuple.=C2=A0But=C2=A0we cannot avoid the=C2=A0cost to= pack in=C2=A0std.typecons.Tuple.</div><div><br></div><div>=C2=A0 Built-in = tuple syntax would solve the issue.</div> <div><br></div><div>=C2=A0 auto tup =3D {x+1, y+2};</div><div>=C2=A0 // tup= is a built-in tuple, and it would be equivalent with:</div><div>=C2=A0 // = auto tup[0] =3D x+1, tup[1] =3D x*2; // pseudo code</div></div><div>=C2=A0 = // so no packing cost in runtime is there.</div> <div><br></div><div>b.</div><div>=C2=A0 To make deconstruction code more re= adable.</div><div><br></div><div>=C2=A0 auto tup =3D std.typecons.tuple(1, = &quot;str&quot;);</div><div>=C2=A0 auto a =3D tup[0], b =3D tup[1]; =C2=A0 = =C2=A0// Currrent:</div><div> =C2=A0 // Deconstruct two fields in tup to the two variables a and b</div><= div>=C2=A0 auto {a, b} =3D tup; =C2=A0 =C2=A0// New syntax:</div><div>=C2= =A0 // Deconstruct syntax would recognize alias this tuple,</div><div>=C2= =A0 // and expand it automatically.</div> <div><br></div><div>Kenji Hara</div></div></div></div> --e89a8f646ff589280004e46b3995--
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 1. What do we need?

We can live fine without a syntax to manage tuples, so strictly speaking we need nothing (almost, I'd like to kill one currently accepted syntax, see below). But when you write D in a high-level style, and you are used to other functional or scripting languages, in several cases you desire a more handy/compact syntax to manage tuples. Tuples are simple data structure, so the operations you want to do with them are few and simple: - To define a tuple of various fields of different type, that is a tuple literal, to create a tuple; - A way to read and write items of a tuple (unless it's read-only), D uses a nice syntax [i] as arrays indexing, but i can't be a run-time value. - With the Phobos tuple we are used to giving names to fields. It's handy, but it's not so necessary if you have a way to assign tuple items to variables, defined in-place. There are several places where pulling apart a tuple in that way is useful, here I use a basic syntax to be more clear: Assignments: auto (a, b) = t1; In function signatures: auto mult = ((int x, int y)) => x * y; In foreach loops: void main() { import std.range, std.stdio; auto a = [10, 20]; auto b = [100, 200]; // Currently D supports this syntax: foreach (x, y; zip(a, b)) writeln(x, " ", y); // But it's unreliable, now x is the index of the // array instead of the first tuple fields, so I // think this feature of D should be killed as // soon as possible: foreach (x, y; zip(a, b).array) writeln(x, " ", y); } Its output: 10 100 20 200 0 Tuple!(int, int)(10, 100) 1 Tuple!(int, int)(20, 200) In (final) switch cases, this also shows one use case and one usefulness of wildcards (and the usage of an unapply() standard method, as explained a bit here: http://d.puremagic.com/issues/show_bug.cgi?id=596 ): final switch (tup1) { case (0, 10): break; case (0, ?): break; case (?, ?): break; } An nice example usage of such basic pattern matching is visible here, to implement the insertion in a red-black-tree. This is a well known hairy operation to do in languages as C: http://rosettacode.org/wiki/Pattern_matching This is how insertion and balancing is done in Haskell (this needs long lines and it probably comes out unreadable here, so see here for a better visualization: http://rosettacode.org/wiki/Pattern_matching#Haskell ): data Color = R | B data Tree a = E | T Color (Tree a) a (Tree a) balance :: Color -> Tree a -> a -> Tree a -> Tree a balance B (T R (T R a x b) y c ) z d = T R (T B a x b) y (T B c z d) balance B (T R a x (T R b y c)) z d = T R (T B a x b) y (T B c z d) balance B a x (T R (T R b y c) z d ) = T R (T B a x b) y (T B c z d) balance B a x (T R b y (T R c z d)) = T R (T B a x b) y (T B c z d) balance col a x b = T col a x b insert :: Ord a => a -> Tree a -> Tree a insert x s = T B a y b where ins E = T R E x E ins s (T col a y b) | x < y = balance col (ins a) y b | x > y = balance col a y (ins b) | otherwise = s T _ a y b = ins s There are few more little pieces that are useful, like unpacking an array: string s = "red blue"; auto (col1, col2) = s.split; Hara has suggested pattern matching in if statements, that is a special case of the pattern matching in switch cases, and it's sometimes useful (similar code is common in Scala): if (auto {1, y} = tup) {...} That is equivalent to: if (tup[0] == 1) { auto y = tup[1]; ... } It looks simple and not so essential, but when tuples become a little more more complex pattern matching shows it usefulness better, as in the Haskell example. Languages as Haskell and Rust also show that even a simple version of pattern matching is handy when you manage types like Nullable() (that need to define an unapply() standard method). (It's not unthinkable to support pattern matching in function signatures too, as often used in many functional languages as OCaML and Haskell, but this is an orthogonal feature, it could be added later, and we can probably live without it for now). Others have suggested a syntax with ... to gather more than one item, or to ignore more than one item with ?... Such syntax is handy with arrays but with tuples, that are often short and of well known size I think it's not so much useful, so it can be left for later.
 2. What does a solution look like in the current language?

The DIP32 shows a complete very small program that I wrote for RosettaCode site, it computes the Huffman encoding of a given string: http://wiki.dlang.org/DIP32 import std.stdio, std.algorithm, std.typecons, std.container, std.array; auto encode(T)(Group!("a == b", T[]) sf) { auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")])) .array.heapify!q{b < a}; while (heap.length > 1) { auto lo = heap.front; heap.removeFront; auto hi = heap.front; heap.removeFront; foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1]; foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1]; heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1])); } return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])}; } void main() { auto s = "this is an example for huffman encoding"d; foreach (p; s.dup.sort().release.group.encode) writefln("'%s' %s", p[]); } That little program shows only three use cases of a tuple syntax: in function signatures, in normal assignments, and in foreach: import std.stdio, std.algorithm, std.container, std.array; auto encode(T)(Group!("a == b", T[]) sf) { auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a}; while (heap.length > 1) { auto (lof, loa) = heap.front; heap.removeFront; auto (hif, hia) = heap.front; heap.removeFront; foreach ((_, ref e); loa) e = '0' ~ e; foreach ((_, ref e); hia) e = '1' ~ e; heap.insert((lof + hif, loa ~ hia)); } return heap.front[1].schwartzSort!((c, e) => (e.length, c)); } void main() { auto s = "this is an example for huffman encoding"d; foreach ((c, e); s.dup.sort().release.group.encode) writefln("'%s' %s", c, e); } For an use case of the assignment from an array, let's say you have a text file containing two numbers in a line, that you want to read: const (x, y) = filein.byLine.front.split.to!(int[]); An example of implementation in a red-black-tree of the insert and balance in C is not too much hard to find with Google. But it's lot of bug-prone code. Bye, bearophile
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei Alexandrescu 
wrote:
 I think this whole thread is approaching things wrongly. It 
 should be:

 1. What do we need?

 2. What does a solution look like in the current language?

 3. Which parts of the solution are frequent/cumbersome enough 
 to warrant a language change?

Exactly. Though if we want to avoid breaking changes as much as possible, maybe it should be more like this: 2. What use cases current language state cover? 3. How it can me remodeled to have less confusing semantics / definitions while covering as much old behavior as possible? I am struggling at (3) because current applications love to contradict each other when any relatively simple rule set is imagined. Basically there are 3 distinct (according to allowed usage) cases for built-in tuples: 1) pure type-tuple 2) mixed compile-time tuple (literals and other compile-time expressions go here) 3) run-time tuple over set of variables/parameters As far as I can see, covering std.typecons.Tuple in similar way is trivial - but re-defining those 3 in a meaningful way is really challenging. Maybe you have any opinion as a concept author? :P
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 21 August 2013 at 01:50:49 UTC, Dicebot wrote:
 On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei 
 Alexandrescu wrote:
 I think this whole thread is approaching things wrongly. It 
 should be:

 1. What do we need?


Also my answer to this question may probably be not very mainstream according to this thread :) I thing that most of all we need definition-driven tuple classification as opposed to current behavior-driven one (here is the built-in tuple and look what shiny stuff it can do). Everything else is just a consequence.
Aug 20 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei Alexandrescu 
wrote:
 1. What do we need?

Nothing. Everything discussed thus far can already be done in D, but with either a little or a lot of tedium and error-prone hackery. What I think would benefit D is a cleanup/simplification/sugarization of the current tuple situation. TypeTuple causes no end of grief and confusion.
 2. What does a solution look like in the current language?

See Kenji's DIP for Bearophile's example of tuple use in the current language. Throughout this discussion there have also been several other examples of how TypeTuple misbehaves.
 3. Which parts of the solution are frequent/cumbersome enough 
 to warrant a language change?

IMO, TypeTuple auto-expansion and mixing of data/types within the same TypeTuple. It's also annoying that TypeTuples are not first-class values, and it would be a pity if we did not come up with some sort of tuple literal syntax, but that situation can be worked around by wrapping it in Tuple.
 Instead there have been 1001 proposals for new syntax for tuple 
 literals, one cuter than the next.

Wouldn't you call this characterization a little unfair, when there were numerous posts also discussing relevant issues and semantics? I'd say the ratio of form:function has been pretty good thus far.
Aug 20 2013
prev sibling next sibling parent "eles" <eles eles.com> writes:
On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei Alexandrescu 
wrote:
 On 8/20/13 5:28 PM, Tyler Jameson Little wrote:
 Instead there have been 1001 proposals for new syntax for tuple 
 literals, one cuter than the next.

I agree. However, that syntax issue is the bikeshed and it keeps everyone's mind busy. So, I propose to pick-up a syntax, even a provisional one, let's say that &(a,b) that I kinda like, then stick with it. This will free the way for more important and fundamental issues and, on the way, it will also allow to discover the eventual shortcomings of the syntax that was picked-up.
Aug 20 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 The current language would be D as it is today, with no 
 syntactic addition.

Right.
 So I guess that would be:

 a.
     alias Types = TypeTuple!(int, long);
     auto values = tuple(1, "str");
 b.
     auto a = tup[0];
     auto b = tup[1];
     tup.scatter(a, b);

 "scatter" is not defined yet. It scatters the content of a 
 tuple over the (ref-passed) arguments.

OK. But there are five missing useful sub-features, that I have listed in my answer: c. unpacking tuples in function signatures; zip(arr1, arr2).map!(ab => ab[0] * ab[1]); ["a", "b"].emumerate.map!(js => js[1].replicate(js[0])); (enumerate is a simple but very useful range not yet present in std.range that yields index-item pairs). d. unpacking tuples in foreach loops; foreach (xy; zip(arr1, arr2)) { // uses xy[0] // uses xy[1] } e. unpacking tuples in switch cases; auto tup = tuple(10, 20); if (tup[0] == 0 && tup[1] == 10) {... } else if (tup[0] == 0) { ... } else { ... } f. unpacking small arrays. auto a = [10, 20]; const x = a[0]; const y = a[1]; g. wildcards (usable in every other a-f case); auto a = tup[0]; // skipped second tuple item auto c = tup[2]; In some cases you have to use: _1, _2, or _ and __, etc. Bye, bearophile
Aug 21 2013
prev sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 21 August 2013 at 17:40:55 UTC, bearophile wrote:
 f. unpacking small arrays.

 auto a = [10, 20];
 const x = a[0];
 const y = a[1];

I don't know if you saw this, but I mentioned in my other post an interesting thing you could do if compiler tuples had an unpacking syntax. You currently can't use tupleof with array, but allowing it would also allow any hypothetical unpacking syntax to unpack an array. An example: int[3] arr = [1, 2, 3]; //a = 1, b = 2, c = 3 auto (a, b, c) = arr.tupleof;
Aug 21 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt wrote:
 Note: I'm leading off with a reply to bearophile transplanted 
 here to stop making OT noise in John's thread about TypeTuple.

 On Friday, 16 August 2013 at 23:23:59 UTC, bearophile wrote:
 It's short, clear, has a precedent with q{}.

Wait, what is q{}?

Check "Token Strings" in http://dlang.org/lex.html
Aug 19 2013
prev sibling next sibling parent "Wyatt" <wyatt.epp gmail.com> writes:
On Monday, 19 August 2013 at 16:57:35 UTC, Dicebot wrote:
 Check "Token Strings" in http://dlang.org/lex.html

Didn't make it to the end of the paragraph? ;)
Aug 19 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 19, 2013 at 06:53:05PM +0200, Wyatt wrote:
[...]
This is the third or fourth time that I know of that tuple syntax
has come up, and as of yet, nothing has been done about it. I'd
really like to get the ball rolling on this, as I think a good
syntax for these tuple operations would do D a world of good. I'm
not a compiler hacker, unfortunately, so I can't implement it
myself as proof of concept... However, I hope that discussing it
and working out all the kinks will help pave the way for an actual
implementation.

Great! After this, let's fix properties. ;)

What I'd like to know, is how all of these proposals address the fundamental differences between "symbol tuples" (compile-time construct) and std.range.Tuple (runtime construct). As far as I can tell, people are still confusing the two, and it's really not helping. Before we solve this, any syntax suggestion seems more like a mortician's work than a real solution. T -- MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
Aug 19 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt wrote:
 Note: I'm leading off with a reply to bearophile transplanted 
 here to stop making OT noise in John's thread about TypeTuple.

 On Friday, 16 August 2013 at 23:23:59 UTC, bearophile wrote:
 It's short, clear, has a precedent with q{}.

Wait, what is q{}? That's something in D? What does that even do? I can infer that q{} is probably some manner of scoping or grouping _something_ somehow, but I have to dig into lexical and manually search for q{ to find out it's [neither of the things I expected]. In my view, this right here is really just a fundamental problem with single-character prefixes and I feel that's something we should endeavour to avoid, if possible.
 I don't like it a lot, but it's way better than not having
 language support for tuples.

 I'd prefer just using parentheses, but I think there were 
 readability problems that caused the DIP to end up with:

More than just readability problems. They were discussed when Kenji presented the DIP 32 in this forum. Timon found a significant problem with the {} syntax.

about parentheses, (). I read over that whole DIP32 thread a couple times, and didn't see any rationale offered for why the likely "cleanest" version "can't be used". It wasn't even brought up (unless I've missed something subtle). In the second thread, linked in the OP here, they were glossed over again. Now, I fully believe there's a very good reason that's been written somewhere, but I _would_ like to know what that is, preferably documented somewhere less ephemeral and difficult to search than the newsgroup (such as in DIP32). The closest I've seen so far is the pull request where Walter and Andrei expressed that it should be considered further. On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

readability, though, even more than q{} or t{}, I have concerns about its ability to be found with an ordinary search engine by an ordinary user. Have you tried looking for documentation on weird operators with a search engine lately? They don't exactly take to it well. :/ (cf. Perl's <=>)

All we have left from the standard keyboard layout as far as single keys go is # and ¬ I don't think the mathematics crowd would be too happy with ¬ not meaning not. The only op() options I can think of that aren't ambiguous: $(a, b) %(a, b) ^(a, b) &(a, b) //I like this one :(a, b) #(a, b) '(a, b) //I think.... /(a, b) \(a, b)
(a, b)

|(a, b) ¬(a, b) //not in std ascii ?(a, b) however, most of those are binary operators too, so it could be quite accident prone and confusing to look at Some of this could be helped by enforcing at least 1 ','. e.g. &(3) //illegal &(3,) //legal There is precedent for this in python.
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:
 What I'd like to know, is how all of these proposals address the
 fundamental differences between "symbol tuples" (compile-time 
 construct)

Those are not symbol tuples. For example, `int` is not a symbol. http://dlang.org/template.html#Symbol - only things that have identifiers and template instances are symbols.
 As far as I can tell, people
 are still confusing the two, and it's really not helping.

Completely removing TypeTuple from library (which native syntax will enable) will help to remove large part of confusion.
Aug 19 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 19, 2013 at 07:34:38PM +0200, Dicebot wrote:
 On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:
What I'd like to know, is how all of these proposals address the
fundamental differences between "symbol tuples" (compile-time
construct)

Those are not symbol tuples. For example, `int` is not a symbol. http://dlang.org/template.html#Symbol - only things that have identifiers and template instances are symbols.

Well, OK, whatever they're supposed to be called. Compiler-tuples, or expression tuples, or whatever. See, part of the problem is that they just don't have any good name that correctly conveys what they are. Calling them "tuple" only adds to the confusion because of the conflation with std.range.Tuple.
As far as I can tell, people are still confusing the two, and it's
really not helping.

Completely removing TypeTuple from library (which native syntax will enable) will help to remove large part of confusion.

That's only part of the problem. It doesn't solve the problem of conflation between these tuples and std.range.Tuple, and from what I can tell in these threads, people are still confusing the two. Both of them being named some kind of "tuple" doesn't help the problem. This is one of the things about D that's seriously WAT-worthy. T -- If it breaks, you get to keep both pieces. -- Software disclaimer notice
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 17:45:44 UTC, H. S. Teoh wrote:
 On Mon, Aug 19, 2013 at 07:34:38PM +0200, Dicebot wrote:
 On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:
What I'd like to know, is how all of these proposals address 
the
fundamental differences between "symbol tuples" (compile-time
construct)

Those are not symbol tuples. For example, `int` is not a symbol. http://dlang.org/template.html#Symbol - only things that have identifiers and template instances are symbols.

Well, OK, whatever they're supposed to be called. Compiler-tuples, or expression tuples, or whatever.

Well, technically they are compile-time tuples of stuff. Yep, that bad :) They don't have a good name because they don't have a good meaning, only behavior.
 See, part of the problem is that they
 just don't have any good name that correctly conveys what they 
 are.
 Calling them "tuple" only adds to the confusion because of the
 conflation with std.range.Tuple.

std.typecons.Tuple ;) I have noticed it is not the first time you want to move it to std.range ;) Well, you see, they are really both tuples. That is also the problem - call them whatever you want but they still both will be tuples. Compile-time tuple and run-time tuple, that is it (and I was recently surprised to learn that even their implementations are deeply tied). I don't think simply changing a name to something irrelevant will magically solve confusion, it is feature in general that need clear re-definition in all relevant documentation. "Tuple" entry on dlang.org does not mention even half of the truth about it...
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:
 What I'd like to know, is how all of these proposals address the
 fundamental differences between "symbol tuples" (compile-time 
 construct) and std.range.Tuple (runtime construct). As far as I 
 can tell, people are still confusing the two, and it's really 
 not helping. Before we solve this, any syntax suggestion seems 
 more like a mortician's work than a real solution.

As far as I can tell, when everyone talks about tuple syntax, they are talking about run-time tuples. That's definitely what I'm talking about whenever I mention tuple syntax, as I don't think it would be a good thing to use it for both run-time and compile-time tuples (and I don't really consider the latter tuples). Bearophile has mentioned a couple times that we could use the tuple syntax for both, and bring about a unification of these two tuple types. I don't like this, as they're both very different entities, and don't really have any relation to each-other whatsoever. I think the best course of action is to keep TypeTuples as is (and possibly provide a new name for them, underdocumenting or outright deprecating the old name), and introduce the new syntax for run-time tuples. Speaking of new names for TypeTuple, I don't know if this was mentioned already, but what about "Variadic Lists"?
Aug 19 2013
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 17:57:45 UTC, Meta wrote:
 As far as I can tell, when everyone talks about tuple syntax, 
 they are talking about run-time tuples. That's definitely what 
 I'm talking about whenever I mention tuple syntax, as I don't 
 think it would be a good thing to use it for both run-time and 
 compile-time tuples (and I don't really consider the latter 
 tuples).

No. I speak exclusively about native syntax for compile-time tuples and stand by the point that run-time tuples are mostly fine as-is and should not be touched at all.
Aug 19 2013
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 20, 2013 at 05:12:43AM +0200, Meta wrote:
 Aggh, misposted. Let's try that again.
 
 On Tuesday, 20 August 2013 at 02:51:20 UTC, Meta wrote:
On Tuesday, 20 August 2013 at 01:06:28 UTC, H. S. Teoh wrote:
Actually, reading through DIP32 again, it sounds like Kenji is
proposing the *same* syntax for both built-in tuples and
std.typecons.Tuple. In the code example under "Generic
type/expression tuple syntax", he refers to them respectively as
"tuple type" and "tuple value". Mixing is also allowed (e.g., in the
"alias Fields" line).


Maybe mixing should be disallowed, then, unless your tuple was constructed from a variadic template argument list.

I don't like this "unless". Either we support mixing, or we don't. Adding in "unless" adds unnecessary complication, which will inevitably have a ripple effect that adds complications everywhere. Next thing you know, Phobos will acquire a template that returns a tuple of its arguments -- as a workaround for the inability to manually construct a mixed tuple, and then we'll have a rehash of this thread, this time surrounding how to merge/get rid of std.typecons.createMixedTuple. I think any workable design of tuples must include a sane way of working with mixed tuples, because they can and do appear in template arguments. T -- Без труда не выловишь и рыбку из пруда.
Aug 20 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu 
wrote:
 I'd call them alias tuples.

Because we don't have strict definition of alias too? :) Actually, I have forgot again that built-in tuples are not always compile-time. They can be used to declare run-time entities with tuple syntax too, that was exactly what was abused in std.typecons.Tuple implementation. As I have already said, it is hard to name something that does not have clear semantics and is essentially just random collection of behavior.
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Wyatt:

 The octothorpe _is_ much better than the t simply in terms of 
 readability, though, even more than q{} or t{}, I have concerns 
 about its ability to be found with an ordinary search engine by 
 an ordinary user.  Have you tried looking for documentation on 
 weird operators with a search engine lately?  They don't 
 exactly take to it well. :/ (cf. Perl's <=>)

I think none of the suggested tuple syntaxes are well searchable on Google, but the "tuple()" syntax. But in the Haskell world the Hoogle direct&reverse search engine supports symbols too (but it's mostly used to search for functions given their signature, I think so far this is something not present in the D world): http://www.haskell.org/hoogle/?hoogle=%3D%3E
 I even don't like how the unicode version of that one looks;

It was just an idea, to show what I meant by representing the bananas with Unicode glyphs. The actual choice of glyphs is not an urgent choice :-) The idea comes from the now dead Fortress language.
 I feel weird admitting this, but if we can't use some manner of 
 bare brace, I think I'd rather have tup(), tup[], tup{} (or 
 even tuple() et al) as a prefix over any single character.

At the moment I prefer #() syntax, with ? for single wildcards. It's better than tup{} or t{} because the # symbol pops out more visually. tuple() syntax is long, but it's readable, and perhaps partially backwards compatible.
 Can't make it a single underscore? Question mark works best 
 then, IMO.  It isn't as burdened with meanings elsewhere (sure 
 there's ternary and possibly-match in regex, but...have I 
 forgotten something?)

The ? of regexes is inside strings, so I think it causes no problems. And I think it doesn't clash with the ternary operator because before the ? wildcard you put a comma, a semicolon or a #(.
 Assuming the "..." syntax for unpacking, it would be useful to 
 name the captured tail. For example, you could unpack #(1, 3, 
 #(4, 6)) into #(a, b, x...), where a = 1, b = 3, x = #(4, 6). 
 Similarly, #(head, rest...) results in head = 1, rest = #(2, 
 #(4, 6)). I think this would be very useful.


In Haskell there is also a way to give a name to the whole tuple and names to its parts: Prelude> let t1 = (10, 20) Prelude> let a (b, c) = t1 Prelude> a (10,20) Prelude> b 10 Prelude> c 20 ------------------------- Meta:
 Bearophile has mentioned a couple times that we could use the 
 tuple syntax for both, and bring about a unification of these 
 two tuple types. I don't like this, as they're both very 
 different entities, and don't really have any relation to 
 each-other whatsoever.

Mine was an idea, but if it turns out to be a bad idea, then let's ignore it. Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 18:19:11 UTC, bearophile wrote:
 Mine was an idea, but if it turns out to be a bad idea, then 
 let's ignore it.

I was initially completely opposed against it but now that I have realized built-in ones do some run-time magic too, it does not sound _that_ crazy anymore. Seriously, if current std.typecons.Tuple is implemented in terms if built-in tuple, than it sounds like only think built-in ones are lacking is ABI. Define it and using one single tuple syntax / implementation for everything becomes real. I mean: import std.typecons; import std.typetuple; void main() { alias TT = TypeTuple!(int, string); // moar confusion for gods of confusion! // what is the difference between twoVars1 and twoVars2 other than latter is wrapped into struct and has ABI? TT twoVars1; Tuple!(int, string) twoVars2; }
Aug 19 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 19, 2013 at 08:10:38PM +0200, Dicebot wrote:
 On Monday, 19 August 2013 at 17:57:45 UTC, Meta wrote:
As far as I can tell, when everyone talks about tuple syntax, they
are talking about run-time tuples. That's definitely what I'm
talking about whenever I mention tuple syntax, as I don't think it
would be a good thing to use it for both run-time and compile-time
tuples (and I don't really consider the latter tuples).

No. I speak exclusively about native syntax for compile-time tuples and stand by the point that run-time tuples are mostly fine as-is and should not be touched at all.

Case in point. :) So we're actually talking at cross purposes here. Bearophile & Meta et al want native syntax for *runtime* tuples (i.e. std.typecons.Tuple -- sorry for the mixup with std.range in my earlier posts), but you're talking about native syntax for alias tuples (aka TypeTuples). Two completely different things. I agree that we shouldn't be making built-in syntax for a library type. If anything, any dedicated syntax should be reserved for alias tuples (aka std.typetuple.Typetuple). Or, at the very least, rename TypeTuple to AliasTuple. Conflating these two concepts has led to endless confusion, which is why I insisted on addressing this issue before we even begin to talk about syntax. Otherwise we're going nowhere. T -- Let's not fight disease by killing the patient. -- Sean 'Shaleh' Perry
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt wrote:
 To be clear, I'm not talking about braces, {}; I'm talking 
 about parentheses, ().  I read over that whole DIP32 thread a 
 couple times, and didn't see any rationale offered for why the 
 likely "cleanest" version "can't be used".  It wasn't even 
 brought up (unless I've missed something subtle).  In the 
 second thread, linked in the OP here, they were glossed over 
 again.  Now, I fully believe there's a very good reason that's 
 been written somewhere, but I _would_ like to know what that 
 is, preferably documented somewhere less ephemeral and 
 difficult to search than the newsgroup (such as in DIP32).  The 
 closest I've seen so far is the pull request where Walter and 
 Andrei expressed that it should be considered further.

I could very well be wrong, but I would bet that one of the reasons is that (a, b, c) expressions already have well-defined semantics in D (as well as (2, "a", func()). Example: void main() { import std.stdio; //Prints "a" writeln((true, false, "a")); } Making this a tuple literal would be a change in semantics, which I don't think would go over well and would break code. Another example: void main() { int a, b; (a, b) = (3, 4); assert(a == 0 && b == 4); } Of course, for the second case, Kenji's proposed syntax used "auto (a, b) = ...", which would disambiguate it, but it could confuse people as to whether the first syntax is somehow related to the second.
 The octothorpe _is_ much better than the t simply in terms of 
 readability, though, even more than q{} or t{}, I have concerns 
 about its ability to be found with an ordinary search engine by 
 an ordinary user.  Have you tried looking for documentation on 
 weird operators with a search engine lately?  They don't 
 exactly take to it well. :/ (cf. Perl's <=>)

I'm not sure how much of a problem that would be. There's only one other syntactic form that uses # in D, but you're right, it may cause some difficulty trying to search "d programming #".
 Addressing the other suggestion I saw that cropped up, I 
 personally find the two-character "bananas" to be impressively 
 ugly.  I considered suggesting some permutation on that same 
 idea, but after toying with a few examples I find it ends up 
 looking awful and I think it's honestly annoying to type them 
 in any form.  I even don't like how the unicode version of that 
 one looks; for doubling up, I think ⟦ ⟧ or ⟪ ⟫ or are easier on 
 the eyes.

My browser can't even display the second set of characters. D seems to have generally shied away from using any unicode operators (for a good reason. Who the hell has Σ on their keyboard?)
 I feel weird admitting this, but if we can't use some manner of 
 bare brace, I think I'd rather have tup(), tup[], tup{} (or 
 even tuple() et al) as a prefix over any single character.

It's not terrible, but it's rather wordy, especially if tuples begin to be used a lot in code.
 Can't make it a single underscore? Question mark works best 
 then, IMO.  It isn't as burdened with meanings elsewhere (sure 
 there's ternary and possibly-match in regex, but...have I 
 forgotten something?)

It *could* be an underscore; the only thing is that the underscore is a valid variable name, so the above expression would actually be binding two variables, which might surprise someone who was expecting otherwise. I don't really care all that much, but it's something to think about.
 #(a, ...) looks like to me like it would make a 2-tuple 
 containing a and a tuple of "everything else", because of the 
 ellipsis' use in templated code.  I think this is a little 
 unclear, so instead I'd prefer #(a, ? ...) (or whatever ends up 
 used for the discard character) to make it explicit.

To be clear, what I have in mind is that this would be "a, plus (none/one?) or more things that can either be elements or nested tuples". Then, in a construction such as #(head, rest...), rest would be exactly as you describe: a tuple consisting of everything after head. The semantics could get tricky, maybe this needs more thought.
 As a bonus, explicit discard means a simple comma omission is 
 less likely to completely change the meaning of the statement.  
 Compare:
 #(a, b, ...)   //bind the first two elements, discard the rest.
 #(a, b ...)    //bind the first element to a and everything 
 else to b
 #(a, b, ? ...) //same as the first
 #(a, b ? ...)  //syntax error

 Granted, there's this case:
 #(a, ?, ...)
 ...but that seems like it would be less common just based on 
 how people conventionally order their data structures.

That's true. Something to think about. Maybe combine the question mark and ellipsis like so: #(a, b, ?..)
 Thought: Is there sufficient worth in having different tokens 
 for discarding a single element vs. a range? e.g.
 #(a, ?, c, * ...) //bind first and third elements; discard the 
 rest
 // I'm not attached to the asterisk there.
 // +, #, or   would also make some amount of sense to me.

Not sure. I need to think about it.
 - Concatenating tuples with ~. This is nice to have, but not 
 particularly important.

auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right? auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b == #(1,2,3,4,5)?

I think it should work the same as with arrays. So: auto a = #(1, 2) ~ 3; //Error: 3 is not a tuple auto a = #(1, 2) ~ #(3); //Result: #(1, 2, 3), just like an array auto b = a ~ #(4, 5); //Result: #(1, 2, 3, 4, 5). Again, like arrays. I think keeping the same semantics as arrays would be the best way to do it. I think it nicely follows the principle of least astonishment. If you wanted to explicitly append a tuple and have it nested, you'd need to do: auto b = a ~ #(#(4, 5)); Which is messy, but at least it's explicit about what is going on.
 Great! After this, let's fix properties. ;)

Oh boy, no need to start *another* flame war.
Aug 19 2013
prev sibling next sibling parent "Wyatt" <wyatt.epp gmail.com> writes:
On Monday, 19 August 2013 at 18:19:11 UTC, bearophile wrote:
 The ? of regexes is inside strings, so I think it causes no 
 problems. And I think it doesn't clash with the ternary 
 operator because before the ? wildcard you put a comma, a 
 semicolon or a #(.

_meanings_ attached to the same character. This was brought up before when someone talked about using an asterisk, but it was pointed out that it would be a bad choice because it's already commonly seen in multiplication, pointers, and exponentiation (**). If anything, I'm inclined to think the regex heritage of the question mark improves its case. -Wyatt
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
Realistically, Andrei, how amenable are you and Walter to adding 
tuple literal/packing&unpacking/pattern matching syntax to D, be 
it Tuple, TypeTuple, whatever? I don't recall either of you 
commenting much in the two other discussion threads linked. We 
can discuss this all day, but it what are the actual chances of 
you agreeing to such a large change in the language?
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Meta:

 It *could* be an underscore; the only thing is that the 
 underscore is a valid variable name, so the above expression 
 would actually be binding two variables, which might surprise 
 someone who was expecting otherwise. I don't really care all 
 that much, but it's something to think about.

You can't define a variable more than once in a scope, so this can't be valid: void main() { auto t1 = #(5, "hello", 1.5); auto (_, _, x) = t1; auto (_, gr, _) = t1; } While ? defines nothing, so this is OK: void main() { auto t1 = #(5, "hello", 1.5); auto (?, ?, x) = t1; auto (?, gr, ?) = t1; } Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 19:54:43 UTC, bearophile wrote:
 ...

That too.
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
 void main() {
     auto t1 = #(5, "hello", 1.5);
     auto (_,  _, x) = t1;
     auto (_, gr, _) = t1;
 }

I need to get used to the proposed syntax, sorry: void main() { auto t1 = #(5, "hello", 1.5); auto #(_, _, x) = t1; auto #(_, gr, _) = t1; } Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 20:36:10 UTC, Andrei Alexandrescu 
wrote:
 On 8/19/13 11:14 AM, Dicebot wrote:
 On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu 
 wrote:
 I'd call them alias tuples.

Because we don't have strict definition of alias too? :)

I'm thinking such a tuple may hold everything that one may define an alias to.

Normal alias or template alias parameter? ;) Because those two are different :P Former can't take lambda literals. Latter won't accept built-in types like int. But built-in tuple is fine with both. "T..." is a _very_ special thing in D.
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 20:46:02 UTC, Andrei Alexandrescu 
wrote:
 It's stuff like this that's just useless and gives a bad 
 direction to the whole discussion. There's hardly anything 
 wrong with auto x = t1[2] or auto gr = t1[1], but once the 
 bikeshed is up for painting, the rainbow won't suffice.

I started this discussion to build on Kenji's DIP, which discusses destructuring and pattern matching syntax in addition to tuple literal syntax, as well as the previous discussion that's already gone on in the two "DIP discussion" threads. Are you saying that you dislike the destructuring/pattern matching discussion as a whole?
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 It's stuff like this that's just useless and gives a bad 
 direction to the whole discussion. There's hardly anything 
 wrong with auto x = t1[2] or auto gr = t1[1], but once the 
 bikeshed is up for painting, the rainbow won't suffice.

I was just explaining why _ can't be used as wildcard (unless you also make _ a not valid variable name), it wasn't meant to be an example of why wildcards are useful in the first place. Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 20:51:47 UTC, Andrei Alexandrescu 
wrote:
 Normal alias. Yah, perhaps "template tuples" are more 
 descriptive.

And how would you call _instance_ of template tuple then? (which is also built-in tuple but not template tuple)
Aug 19 2013
prev sibling next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Monday, 19 August 2013 at 19:24:32 UTC, Timon Gehr wrote:
 On 08/19/2013 07:44 PM, H. S. Teoh wrote:
 Well, OK, whatever they're supposed to be called. 
 Compiler-tuples, or
 expression tuples, or whatever. See, part of the problem is 
 that they
 just don't have any good name that correctly conveys what they 
 are.

They are simply template argument lists. (http://wiki.dlang.org/The_D_Programming_Language/Seq)

Nice short FAQ for one of the more confusing parts of D. The name "template argument list" clears things up quite a bit actually (but is too long for a type name). Is it your idea to use Seq instead of TypeTuple?
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu 
wrote:
 I'm saying that there's a mix of useful stuff and just 
 syntactic additions that are arguably less so.

Wanted to note here that while discussing syntax at this moment is indeed mostly useless but playing with imaginary code snippets does help to understand what behavior people want to see and that can be used as a basis for formalizing semantics.
Aug 19 2013
prev sibling next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Monday, 19 August 2013 at 21:16:43 UTC, Brad Anderson wrote:
 On Monday, 19 August 2013 at 19:24:32 UTC, Timon Gehr wrote:
 On 08/19/2013 07:44 PM, H. S. Teoh wrote:
 Well, OK, whatever they're supposed to be called. 
 Compiler-tuples, or
 expression tuples, or whatever. See, part of the problem is 
 that they
 just don't have any good name that correctly conveys what 
 they are.

They are simply template argument lists. (http://wiki.dlang.org/The_D_Programming_Language/Seq)

Nice short FAQ for one of the more confusing parts of D. The name "template argument list" clears things up quite a bit actually (but is too long for a type name). Is it your idea to use Seq instead of TypeTuple?

Pretty heavy on the snark though :P
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu 
wrote:
 I'm saying that there's a mix of useful stuff and just 
 syntactic additions that are arguably less so. In my opinion:

 a) destructuring tuples in auto declarations - good to have:

 auto (a, b, c) = 
 functionReturningTupleOrStaticArrayWith3Elements();

 b) syntactic support for ignoring certain members in a 
 destructuring - is that really needed?

 auto (a, ?, c) = 
 functionReturningTupleOrStaticArrayWith3Elements();

In fairness, it is very common in other languages with pattern matching/destructuring. Off the top of my head I can think of Haskell, ML, Racket, Javascript (destructuring only) and Rust. This syntax is more important when pattern matching, but also seems to be almost universally used in destructuring. From the DIP: switch (tup) { case {1, 2}: case {$, 2}: //Don't care what the first value is, only match on second case {1, x}: default: } You could just replace {$, 2} with {x, 2} and never use x, but this creates the problem that Bearophile mentioned. auto t1 = #(5, "hello", 1.5); //Fine auto #(_, _, x) = t1; //Dammit, can't use _ twice as it's a variable If you replace _ with throwaway variable names, it becomes much less clear (IMO) exactly what is going on. Any programmer reading your code would have to examine the function to see if the bindings introduced are ever used, or if they are just throwaways. Maybe it's unproductive to argue over the colour of the bike shed, but we need to know whether it's worth adding windows.
Aug 19 2013
prev sibling next sibling parent "ixid" <nuaccount gmail.com> writes:
On Friday, 16 August 2013 at 23:48:53 UTC, bearophile wrote:
 Meta:

 Andrei/Walter didn't want to merge that pull request without a 
 full consideration of the different design issues involved, 
 which in retrospect was a good decision.

I agree that before adding some new syntax you have to think well.
 - {a, b} is not as pretty, but it's not that bad of an 
 alternative (though it may still have issues as well)

It has technical issues, they were discussed in one of the last threads. Such problems should be added in a note in the DIP32, so they don't get lost in time.
 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

It looks nice (but I don't know if it's technically usable), I have added it at the end of the list of alternative syntaxes: http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
 I personally think #(a, ?) or #(a, *) would be best, but all 
 that's  really necessary is a symbol that cannot also be an 
 identifier.

I think ? is clear, unambiguous, etc, and I like it. The * is already used for pointers, product, dereferencing, ** is used for pow, so it's better to not add further meanings to it.
 - Concatenating tuples with ~. This is nice to have, but not 
 particularly important.

In theory I like this operation, but in practice in my D code I don't need it often, so I think it should be left out, for later. In Python I sometimes concatenate tuples, but in such use cases they are essentially immutable dynamically typed arrays, losing their positional meaning. Tuples could also be used in switch/case statements, to support a very basic form of pattern matching. See also a standard method named "unapply" I have discussed a bit here, coming from Scala language, that is a very simple solution to solve a significant problem: http://d.puremagic.com/issues/show_bug.cgi?id=596 Bye, bearophile

What about using : as people had intended to use the comma operator? uint a, b; (a : b) = (1 : 2); (a : b) = tupleReturningFunction; auto c = (1 : (2 : 3)); // A tuple containing a tuple auto d = (1 : ((2 : 3) : (4 : 5))); // a tuple with a tuple of tuples as a member auto assoc_array = [1 : (2 : 3)]; // A tuple associative value auto assoc_array2 = [(1 : 2) : 3]; // A tuple associative key auto ternary = value? (1 : 2) : (3 : 4); // tuple values in a ternary operator It's nicer looking than #().
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
ixid:

 auto assoc_array = [1 : (2 : 3)]; // A tuple associative value
 auto assoc_array2 = [(1 : 2) : 3]; // A tuple associative key

 auto ternary = value? (1 : 2) : (3 : 4); // tuple values in a 
 ternary operator

 It's nicer looking than #().

Are singleton tuples represented with (1:) ? Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 18:43:37 UTC, Meta wrote:
 What does concatenating a tuple actually do?  That is:
 auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right?
 auto b = a ~ #(4,5); //Is  b == #(1,2,3,#(4,5)) or is b == 
 #(1,2,3,4,5)?

I think it should work the same as with arrays. So: auto a = #(1, 2) ~ 3; //Error: 3 is not a tuple auto a = #(1, 2) ~ #(3); //Result: #(1, 2, 3), just like an array auto b = a ~ #(4, 5); //Result: #(1, 2, 3, 4, 5). Again, like arrays.

I was being dumb, [1, 2] ~ 3 is of course valid for arrays, so that should work for tuples as well. Furthermore, #(1, 2) ~ "a" should be valid, and will result in #(1, 2, "a").
 I think keeping the same semantics as arrays would be the best 
 way to do it. I think it nicely follows the principle of least 
 astonishment. If you wanted to explicitly append a tuple and 
 have it nested, you'd need to do:

 auto b = a ~ #(#(4, 5));

 Which is messy, but at least it's explicit about what is going 
 on.

The tricky part of this that I forgot to mention is that you can't do this with arrays, so we're in unknown territory, but I think this is sensible. Again, it's quite ugly, but oh well.
Aug 19 2013
prev sibling next sibling parent "ixid" <nuaccount gmail.com> writes:
On Monday, 19 August 2013 at 22:36:34 UTC, bearophile wrote:
 ixid:

 auto assoc_array = [1 : (2 : 3)]; // A tuple associative value
 auto assoc_array2 = [(1 : 2) : 3]; // A tuple associative key

 auto ternary = value? (1 : 2) : (3 : 4); // tuple values in a 
 ternary operator

 It's nicer looking than #().

Are singleton tuples represented with (1:) ? Bye, bearophile

Sure, why not? It looks happy enough. :) Are singleton tuples actually useful for anything?
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
ixid:

 Are singleton tuples actually useful for anything?

They are not much useful, but unless you want to outlaw them, you have to keep them in account when you design a syntax. Bye, bearophile
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 18:40:58 UTC, H. S. Teoh wrote:
 Case in point. :)

 So we're actually talking at cross purposes here. Bearophile & 
 Meta et
 al want native syntax for *runtime* tuples (i.e. 
 std.typecons.Tuple --
 sorry for the mixup with std.range in my earlier posts), but 
 you're
 talking about native syntax for alias tuples (aka TypeTuples). 
 Two
 completely different things.

Now that I reread Kenji's DIP for a third time, I see/recall that his intention was for this syntax to be for alias tuples. In that case, wouldn't this necessitate a change in semantics? Will these alias tuples using built-in syntax still auto-expand?
 I agree that we shouldn't be making built-in syntax for a 
 library type.
 If anything, any dedicated syntax should be reserved for alias 
 tuples
 (aka std.typetuple.Typetuple). Or, at the very least, rename 
 TypeTuple
 to AliasTuple.

I don't necessarily want built-in syntax for a library type, but making tuples first-class would be nice. I mean, it's a bummer that they can't be returned from functions. That should definitely be changed.
 Conflating these two concepts has led to endless confusion, 
 which is why
 I insisted on addressing this issue before we even begin to 
 talk about
 syntax. Otherwise we're going nowhere.


 T

Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 19 August 2013 at 23:48:36 UTC, Meta wrote:
 ...

An addendum: void main() { //Prints 1 writeln(func(TypeTuple!(1, 2))); } int func(int i, int j) { return i; } This is bad and should never be allowed with some hypothetical tuple literal syntax. The desired behaviour is: void main() { //Error: func is not callable using argument types (#(int, int)) writeln(func(#(1, 2)); } *Unless* you use .expand/[] (pick your poison): void main() { writeln(func(#(1, 2).expand)); //Or #(1, 2)[] }
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 19 August 2013 at 23:55:32 UTC, Meta wrote:
 On Monday, 19 August 2013 at 23:48:36 UTC, Meta wrote:
 ...

An addendum: void main() { //Prints 1 writeln(func(TypeTuple!(1, 2))); } int func(int i, int j) { return i; } This is bad and should never be allowed with some hypothetical tuple literal syntax. The desired behaviour is: void main() { //Error: func is not callable using argument types (#(int, int)) writeln(func(#(1, 2)); } *Unless* you use .expand/[] (pick your poison): void main() { writeln(func(#(1, 2).expand)); //Or #(1, 2)[] }

No. No. Absolutely no. What you want is simply syntax sugar for std.typecons.Tuple - it is not worth any language change, contrary to semantical issues with built-in tuples. Auto-expansion and integration with function/template parameter lists is what makes D built-in tuple that useful and it should stay so with hypothetical tuple literals.
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu 
wrote:
 On 8/19/13 4:48 PM, Meta wrote:
 I don't necessarily want built-in syntax for a library type, 
 but making
 tuples first-class would be nice. I mean, it's a bummer that 
 they can't
 be returned from functions. That should definitely be changed.

return tuple(1, "a");

That's not a TypeTuple, though, it's a built-in tuple. void main() { writeln(func()); } TypeTuple!(int, string) func() { return tuple(1, "a"); //Error } Nor does it work the other way around: Tuple!(int, string) func() { return TypeTuple!(1, "a"); //Error } How would this work for some hypothetical built-in syntax? #(int, string) func() { return tuple(1, "a"); //Error? }
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 00:14:30 UTC, Meta wrote:
 That's not a TypeTuple, though, it's a built-in tuple.

s/built-in tuple/library tuple
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 00:13:24 UTC, Dicebot wrote:
 No. No. Absolutely no. What you want is simply syntax sugar for 
 std.typecons.Tuple - it is not worth any language change, 
 contrary to semantical issues with built-in tuples. 
 Auto-expansion and integration with function/template parameter 
 lists is what makes D built-in tuple that useful and it should 
 stay so with hypothetical tuple literals.

Yes, changing semantics is a bad thing, which is why I was originally thinking of the tuple syntax as sugar for std.typecons.Tuple. The proposed syntax takes a hit if it is just sugar for the compiler tuples. They will break in some cases when being passed to functions, and will still not be able to be returned from functions.
Aug 19 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 20, 2013 at 02:14:28AM +0200, Meta wrote:
 On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu
 wrote:
On 8/19/13 4:48 PM, Meta wrote:
I don't necessarily want built-in syntax for a library type, but
making tuples first-class would be nice. I mean, it's a bummer that
they can't be returned from functions. That should definitely be
changed.

return tuple(1, "a");

That's not a TypeTuple, though, it's a built-in tuple.

Sounds like you're confused about what built-in tuples are (and you wouldn't be the first -- they're rather confusing things). They are perhaps best thought of as template argument lists. As such, they have no runtime value or, as Andrej puts it, they have no ABI. So it doesn't make sense to return them from a function. What should be the meaning, for example, of: template fun(A...) { auto fun() { return A; } } ? The answer is, this code makes no sense, because you can't return template arguments from a function. It makes as much sense as returning a function's signature from a function. You can't do that, because a function's signature isn't a runtime value that can be returned. Similarly: return TypeTuple!(int, 1); doesn't really make sense. The tuple (int, 1) isn't a runtime value that you can return from a function. It's a compile-time concept that doesn't exist at runtime. T -- MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
Aug 19 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 20 August 2013 at 00:28:47 UTC, Meta wrote:
 Yes, changing semantics is a bad thing, which is why I was 
 originally thinking of the tuple syntax as sugar for 
 std.typecons.Tuple. The proposed syntax takes a hit if it is 
 just sugar for the compiler tuples. They will break in some 
 cases when being passed to functions, and will still not be 
 able to be returned from functions.

It is not about sugar. It is about having entity in standard library to express concept that is built in into language and confusion it creates. Fixing semantics to allow _even more auto-expansion_ is a nice possible side effect. What you ask it is done by Tuple and there is nothing special about it - it is a struct, normal value type. One may be disappointed with relatively verbose syntax but it is not a real issue. But conflating it with built-in possible is simply impossible - if you even start thinking about syntax that does it, you probably need to re-read all documentation linked in this topic on tuple topic. Of course, we could have changed language in that regard - but this is a huge change, so complex that thinking about literal syntax is last thing we should do. And it does not seem to have much supporters to start with.
Aug 19 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Tuesday, 20 August 2013 at 00:29:17 UTC, H. S. Teoh wrote:
 Sounds like you're confused about what built-in tuples are (and 
 you wouldn't be the first -- they're rather confusing things).

I know the difference between std.typecons.Tuple and the built-in tuples. What I'm confused about is I thought that the main objective of the tuple literal syntax (destructuring/pattern matching aside) was a means to have first-class tuples. That is, tuples that have their own literal syntax, have a list of valid operations that can be done on them, can be passed to functions, and can be returned from functions. Whether this is implemented as a syntactic sugar for std.typecons.Tuple, syntactic sugar for the built-in tuples, or a primitive type analogous to int, char, double[], etc. is not particularly important. It's becoming clear, now, that everyone has a different idea about what tuples should comprise, and I believe I have a better understanding of why this issue has yet to be solved.
 The answer is, this code makes no sense, because you can't 
 return
 template arguments from a function. It makes as much sense as 
 returning
 a function's signature from a function. You can't do that, 
 because a
 function's signature isn't a runtime value that can be returned.

 Similarly:

 	return TypeTuple!(int, 1);

 doesn't really make sense. The tuple (int, 1) isn't a runtime 
 value that
 you can return from a function. It's a compile-time concept 
 that doesn't
 exist at runtime.

All which makes it not first-class. Let's return, then, to Kenji's DIP, and ask how the semantics he described can be implemented in D, unless someone objects to some facet of the DIP, at which point it can be worked out.
Aug 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 return tuple(1, "a");

About the same syntax should work for both packing and unpacking tuples. Bye, bearophile
Aug 19 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, August 19, 2013 13:45:33 Andrei Alexandrescu wrote:
 but once the bikeshed is up for painting, the
 rainbow won't suffice.

LOL! I'm going to have to remember that one. - Jonathan M Davis
Aug 19 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu 
wrote:
 I'm saying that there's a mix of useful stuff and just 
 syntactic additions that are arguably less so. In my opinion:

 a) destructuring tuples in auto declarations - good to have:

 auto (a, b, c) = 
 functionReturningTupleOrStaticArrayWith3Elements();

I propose the following rewrite : auto tmp = functionReturningTupleOrStaticArrayWith3Elements(); assert(tmp.length == 3); auto a = tmp[0]; auto b = tmp[1]; auto c = tmp[2]; That way any type user can take advantage of the new syntax, and it is easy to implement as it is simple rewrite rules. Note that tmp do not need to be an lvalue to avoid uneeded copies. I'd also like to see the term Tuple for variadic template parameter go away. This is confusing the hell out of everybody, as the current conversation is showing.
Aug 19 2013
prev sibling next sibling parent "Mr. Anonymous" <mailnew4ster gmail.com> writes:
On Monday, 19 August 2013 at 18:43:37 UTC, Meta wrote:
 On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt wrote:
 Can't make it a single underscore? Question mark works best 
 then, IMO.  It isn't as burdened with meanings elsewhere (sure 
 there's ternary and possibly-match in regex, but...have I 
 forgotten something?)

It *could* be an underscore; the only thing is that the underscore is a valid variable name, so the above expression would actually be binding two variables, which might surprise someone who was expecting otherwise. I don't really care all that much, but it's something to think about.

Why not just leave an empty space, like php does: $info = array('coffee', 'brown', 'caffeine'); // let's skip to only the third one list( , , $power) = $info; echo "I need $power!\n"; http://php.net/manual/en/function.list.php
Aug 20 2013
prev sibling next sibling parent reply "eles" <eles eles.com> writes:
On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
 A good, comprehensive design has the potential to make tuples 
 easy to use and understand, and hopefully clear up the 
 unpleasant situation we have currently. A summary of what has 
 been discussed so far:

 - (a, b) is the prettiest syntax, and it also completely 
 infeasible

 - {a, b} is not as pretty, but it's not that bad of an 
 alternative (though it may still have issues as well)

 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

What about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .
Aug 20 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/20/2013 12:38 PM, eles wrote:
 What about:

 !!(a, b)

This already has a meaning.
Aug 20 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/20/13 3:38 AM, eles wrote:
 On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
 A good, comprehensive design has the potential to make tuples easy to
 use and understand, and hopefully clear up the unpleasant situation we
 have currently. A summary of what has been discussed so far:

 - (a, b) is the prettiest syntax, and it also completely infeasible

 - {a, b} is not as pretty, but it's not that bad of an alternative
 (though it may still have issues as well)

 - #(a, b) is unambiguous and would probably be the easiest option. I
 don't think it looks too bad, but some people might find it ugly and
 noisy

What about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .

Somebody shoot me. Andrei
Aug 20 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2013 1:10 PM, Jonathan M Davis wrote:
 On Tuesday, August 20, 2013 13:06:27 H. S. Teoh wrote:
 On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:
 Somebody shoot me.

[...] BANG!

Don't kill him. He hasn't finished the allocators yet! ;)

Don't worry, we'll keep sliding food under his door!
Aug 21 2013
prev sibling next sibling parent "Mr. Anonymous" <mailnew4ster gmail.com> writes:
On Tuesday, 20 August 2013 at 10:38:30 UTC, eles wrote:
 On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
 A good, comprehensive design has the potential to make tuples 
 easy to use and understand, and hopefully clear up the 
 unpleasant situation we have currently. A summary of what has 
 been discussed so far:

 - (a, b) is the prettiest syntax, and it also completely 
 infeasible

 - {a, b} is not as pretty, but it's not that bad of an 
 alternative (though it may still have issues as well)

 - #(a, b) is unambiguous and would probably be the easiest 
 option. I don't think it looks too bad, but some people might 
 find it ugly and noisy

What about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .

It's not only long, but also ugly (IMO of course).
Aug 20 2013
prev sibling next sibling parent "Wyatt" <wyatt.epp gmail.com> writes:
On Tuesday, 20 August 2013 at 09:02:29 UTC, Mr. Anonymous wrote:
 Why not just leave an empty space, like php does:

 $info = array('coffee', 'brown', 'caffeine');
 // let's skip to only the third one
 list( , , $power) = $info;
 echo "I need $power!\n";

Bad idea. It's a visual thing-- quick! How wide is this tuple!?: #(,front,,,,var,) How long did it take you to be SURE that it's a seven-tuple? You probably aren't even equipped to measure that so don't worry about answering, but I'm guessing you start to appreciate why it's a fairly inhumane solution (how drearily typical for PHP). Ah, but what if it was supposed to be #(,front,,,,,var,)? Does that change your result, now that you're taking the sixth element rather than the seventh? All you did was forget a comma! By contrast: #(?,front,?,?,?,var,?,?) //at least gives us a better chance of parsing it correctly. My point here is we are human and we are fallible. The sooner we acknowledge and internalise that, the better equipped we are to make systems that don't suck for humans to use. In that sense, I don't even really like this format because it's still not especially resilient. Walter's talk about design that eliminates patterns of human error resonated with me quite strongly, you see. But in terms of language consistency it's not much different from array literals, so I could accept it as a compromise. -Wyatt
Aug 20 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 19, 2013 at 09:41:24PM -0700, Jonathan M Davis wrote:
 On Monday, August 19, 2013 13:45:33 Andrei Alexandrescu wrote:
 but once the bikeshed is up for painting, the
 rainbow won't suffice.

LOL! I'm going to have to remember that one.

That's a classic. I'm st^H^H borrowing that for my random signatures file. :) T -- There's light at the end of the tunnel. It's the oncoming train.
Aug 20 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--001a11c1d6f60237cc04e4621e4a
Content-Type: text/plain; charset=UTF-8

On 20 August 2013 16:39, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:

 Why would it be necessary to return an object of type TypeTuple (i.e.
 template tuple)?

- ABI Multiple return values could use a more efficient ABI than struct instances because they do not have an address.

*** this I've been banging this drum for years! However this discussion resolves, I just hope it allows for convenient and efficient MRV's. Obviously it should be syntactically convenient, and assignment of MRV to callee locals should be convenient too. But more importantly, I'd like to see ALL the argument registers re-used to return multiple values, rather than just the first one. They're just sitting there begging to be used, and in many cases, would lead to some great efficiency improvements across function calls/returns. Especially on non-x86 architectures. Perhaps one of the most common causes for (otherwise unnecessary) inlining of functions is because of the terrible legacy ABI for returning multiple values from functions. --001a11c1d6f60237cc04e4621e4a Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 20 August 2013 16:39, Timon Gehr <span dir=3D"ltr">&lt;= <a href=3D"mailto:timon.gehr gmx.ch" target=3D"_blank">timon.gehr gmx.ch</a=
&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quote=

1px #ccc solid;padding-left:1ex"> <div class=3D"im">On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> <br> Why would it be necessary to return an object of type TypeTuple (i.e.<br> template tuple)?<br> </blockquote> </div><br> - ABI<br> <br> Multiple return values could use a more efficient ABI than struct instances= because they do not have an address.<br></blockquote><div><br></div><div>*= ** this</div><div><br></div><div>I&#39;ve been banging this drum for years!= </div> <div><br></div><div>However this discussion resolves, I just hope it allows= for convenient and efficient MRV&#39;s.</div><div>Obviously it should be s= yntactically convenient, and assignment of MRV to callee locals should be c= onvenient too.</div> <div>But more importantly, I&#39;d like to see ALL the argument registers r= e-used to return multiple values, rather than just the first one. They&#39;= re just sitting there begging to be used, and in many cases, would lead to = some great efficiency improvements across function calls/returns. Especiall= y on non-x86 architectures.</div> <div><br></div><div>Perhaps one of the most common causes for (otherwise un= necessary) inlining of functions is because of the terrible legacy ABI for = returning multiple values from functions.</div></div></div></div> --001a11c1d6f60237cc04e4621e4a--
Aug 20 2013
prev sibling next sibling parent "eles" <eles eles.com> writes:
On Tuesday, 20 August 2013 at 13:14:46 UTC, Timon Gehr wrote:
 On 08/20/2013 12:38 PM, eles wrote:
 What about:

 !!(a, b)

This already has a meaning.

True :( I dunno why I took it for some kind of binary operator instead of a unary one. I was too quick on my keyboard.
Aug 20 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:
 On 8/20/13 3:38 AM, eles wrote:
On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:
A good, comprehensive design has the potential to make tuples easy
to use and understand, and hopefully clear up the unpleasant
situation we have currently. A summary of what has been discussed so
far:

- (a, b) is the prettiest syntax, and it also completely infeasible

- {a, b} is not as pretty, but it's not that bad of an alternative
(though it may still have issues as well)

- #(a, b) is unambiguous and would probably be the easiest option. I
don't think it looks too bad, but some people might find it ugly and
noisy

What about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .

Somebody shoot me.

BANG! T -- They say that "guns don't kill people, people kill people." Well I think the gun helps. If you just stood there and yelled BANG, I don't think you'd kill too many people. -- Eddie Izzard, Dressed to Kill
Aug 20 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, August 20, 2013 13:06:27 H. S. Teoh wrote:
 On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:
 Somebody shoot me.

[...] BANG!

Don't kill him. He hasn't finished the allocators yet! ;) - Jonathan M Davis
Aug 20 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 20, 2013 at 04:10:29PM -0400, Jonathan M Davis wrote:
 On Tuesday, August 20, 2013 13:06:27 H. S. Teoh wrote:
 On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:
 Somebody shoot me.

[...] BANG!

Don't kill him. He hasn't finished the allocators yet! ;)

Well, as my signature line said: They say that "guns don't kill people, people kill people." Well I think the gun helps. If you just stood there and yelled BANG, I don't think you'd kill too many people. -- Eddie Izzard, Dressed to Kill ;-) T -- Why can't you just be a nonconformist like everyone else? -- YHL
Aug 20 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 20 August 2013 at 18:51:23 UTC, Andrei Alexandrescu 
wrote:
 On 8/19/13 11:39 PM, Timon Gehr wrote:
 On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:
 Why would it be necessary to return an object of type 
 TypeTuple (i.e.
 template tuple)?

- Elegance. Eg: auto seq(T...)(T arg){ return arg; } auto fold(alias a,S,R)(S start, R range){ ... } seq(0,[1,2,3]).fold!((a,b)=>a+b);

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

A value tuple IS a tuple. What we call a tuple here as nothing to do with a tuple.
Aug 20 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, August 20, 2013 23:25:03 Michel Fortin wrote:
 On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu
 
 <SeeWebsiteForEmail erdani.org> said:
 1. What do we need?

I think D needs less tuples. It has two kinds (language kind and Phobos's kind), which is confusing. It should have just one that covers most use cases.

I honestly think that trying to combine Tuple and TypeTuple would increase the confusion, because you'd be forcing the compiler to decide what you meant in any given situation, and from the programmer's perspective, it will frequently be non-obvious whether what's being done is being done at compile time or at runtime. The main problem I see is that TypeTuple is badly named. Heck, the fact that it's even referred to as a tuple is problematic, since it isn't really, as it always expands. And the fact that it's the "built-in" tuple but requires a library solution to be able to actually declare it is a bit odd. So, I think that creating as syntax for the built-in tuples in order to get rid of TypeTuple would clean things up. But I see no reason to try and combine any of that with Tuple, as Tuple and TypeTuple do fundamentally different things. The main gain I see is simply in cleaning up the naming mess, and by making it so that the built-in tuple actually has a built-in syntax, the language is cleaner and should be easier to understand (especially if we can come up with a name other than tuple or built-in tuple to call them so that they stop getting confused with Tuple). - Jonathan M Davis
Aug 20 2013
prev sibling next sibling parent "Zach the Mystic" <reachzach gggggmail.com> writes:
On Monday, 19 August 2013 at 20:46:02 UTC, Andrei Alexandrescu 
wrote:
 void main() {
     auto t1 = #(5, "hello", 1.5);
     auto (?,  ?, x) = t1;
     auto (?, gr, ?) = t1;
 }

 Bye,
 bearophile

It's stuff like this that's just useless and gives a bad direction to the whole discussion. There's hardly anything wrong with auto x = t1[2] or auto gr = t1[1], but once the bikeshed is up for painting, the rainbow won't suffice. Andrei

I agree. The negative space *around* the bikeshed should be used... auto (void, void, x) = t1; (Just an idea I had. Don't know whether it's technically sound. It just seemed so funny to me that the idea popped into my head as soon as you said "rainbow". Not trying to waste time. )
Aug 21 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 21 August 2013 at 03:39:32 UTC, Jonathan M Davis 
wrote:
 But I see no reason to try and combine any of that with Tuple, 
 as Tuple and
 TypeTuple do fundamentally different things.

TypeTuple does not cover all built-in tuple cases. There is also built-in expression/run-time tuple which is also native to language but differs from library std.typecons.Tuple _only_ with lack of ABI. You may underestimate the mess here.
Aug 21 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Zach the Mystic:

 I agree. The negative space *around* the bikeshed should be 
 used...

Andrei missed the point of that part of the discussion. That was not an explanation of the usefulness of wildcards, it was a small explanations of why probably you can't use '_' as wildcard symbol. The examples I have shown were not meant to show why wildcards are very useful in a rounded tuple design.
 auto (void, void, x) = t1;

 (Just an idea I had. Don't know whether it's technically sound. 
 It just seemed so funny to me that the idea popped into my head 
 as soon as you said "rainbow". Not trying to waste time. )

That is perhaps technically acceptable, but it's longer. Bye, bearophile
Aug 21 2013
prev sibling next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Meta" <jared771 gmail.com> wrote in message 
news:evamvyfxasouvwzublxc forum.dlang.org...
 That said, I'd like to open the discussion on tuple syntax yet again.

How about angle brackets? auto x = <1, 3>; auto <a, b> = x;
Aug 21 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-08-21 18:01, Daniel Murphy wrote:

 How about angle brackets?

 auto x = <1, 3>;
 auto <a, b> = x;

Aren't we then back to the same problems C++ have with its template syntax? -- /Jacob Carlborg
Aug 21 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/21/13 9:01 AM, Daniel Murphy wrote:
 "Meta" <jared771 gmail.com> wrote in message
 news:evamvyfxasouvwzublxc forum.dlang.org...
 That said, I'd like to open the discussion on tuple syntax yet again.

How about angle brackets? auto x = <1, 3>; auto <a, b> = x;

No please. Andrei
Aug 21 2013
prev sibling parent "QAston" <qaston gmail.com> writes:
On Wednesday, 21 August 2013 at 16:39:14 UTC, Jacob Carlborg 
wrote:
 On 2013-08-21 18:01, Daniel Murphy wrote:

 How about angle brackets?

 auto x = <1, 3>;
 auto <a, b> = x;

Aren't we then back to the same problems C++ have with its template syntax?

and >>. PS. Poor Andrei.
Aug 21 2013