digitalmars.D - A Discussion of Tuple Syntax
- Meta (97/97) Aug 16 2013 Awhile ago Kenji posted this excellent dip
- bearophile (24/37) Aug 16 2013 It has technical issues, they were discussed in one of the last
- Meta (4/10) Aug 16 2013 Why do you say that? It seems to me that it would be better than
- captaindet (12/18) Aug 16 2013 not sure what we are talking about here, new syntax for
- Meta (30/49) Aug 17 2013 First and foremost, a new syntax for std.typecons.Tuple. Creating
- ixid (14/53) Aug 19 2013 What about using : as people had intended to use the comma
- bearophile (4/9) Aug 19 2013 Are singleton tuples represented with (1:) ?
- ixid (3/14) Aug 19 2013 Sure, why not? It looks happy enough. :) Are singleton tuples
- bearophile (5/6) Aug 19 2013 They are not much useful, but unless you want to outlaw them, you
- Wyatt (87/132) Aug 19 2013 Note: I'm leading off with a reply to bearophile transplanted
- Dicebot (2/8) Aug 19 2013 Check "Token Strings" in http://dlang.org/lex.html
- Wyatt (2/3) Aug 19 2013 Didn't make it to the end of the paragraph? ;)
- H. S. Teoh (12/22) Aug 19 2013 [...]
- Dicebot (6/11) Aug 19 2013 Those are not symbol tuples. For example, `int` is not a symbol.
- H. S. Teoh (14/27) Aug 19 2013 Well, OK, whatever they're supposed to be called. Compiler-tuples, or
- Dicebot (15/34) Aug 19 2013 Well, technically they are compile-time tuples of stuff. Yep,
- Andrei Alexandrescu (3/17) Aug 19 2013 I'd call them alias tuples.
- Dicebot (10/11) Aug 19 2013 Because we don't have strict definition of alias too? :)
- Andrei Alexandrescu (4/7) Aug 19 2013 I'm thinking such a tuple may hold everything that one may define an
- Dicebot (7/15) Aug 19 2013 Normal alias or template alias parameter? ;) Because those two
- Andrei Alexandrescu (3/13) Aug 19 2013 Normal alias. Yah, perhaps "template tuples" are more descriptive.
- Dicebot (4/6) Aug 19 2013 And how would you call _instance_ of template tuple then? (which
- Meta (6/6) Aug 19 2013 Realistically, Andrei, how amenable are you and Walter to adding
- Andrei Alexandrescu (9/15) Aug 19 2013 We'd be fools to reject a valuable addition to the language. That being
- Timon Gehr (3/6) Aug 19 2013 They are simply template argument lists.
- Brad Anderson (5/15) Aug 19 2013 Nice short FAQ for one of the more confusing parts of D. The
- Brad Anderson (2/19) Aug 19 2013 Pretty heavy on the snark though :P
- Meta (18/24) Aug 19 2013 As far as I can tell, when everyone talks about tuple syntax,
- Dicebot (4/10) Aug 19 2013 No. I speak exclusively about native syntax for compile-time
- H. S. Teoh (17/27) Aug 19 2013 Case in point. :)
- Meta (9/32) Aug 19 2013 Now that I reread Kenji's DIP for a third time, I see/recall that
- Meta (24/25) Aug 19 2013 An addendum:
- Dicebot (7/32) Aug 19 2013 No. No. Absolutely no. What you want is simply syntax sugar for
- Andrei Alexandrescu (3/6) Aug 19 2013 return tuple(1, "a");
- Meta (21/28) Aug 19 2013 That's not a TypeTuple, though, it's a built-in tuple.
- Meta (2/3) Aug 19 2013 s/built-in tuple/library tuple
- Andrei Alexandrescu (4/30) Aug 19 2013 Why would it be necessary to return an object of type TypeTuple (i.e.
- Timon Gehr (13/16) Aug 19 2013 - Elegance. Eg:
- Manu (15/23) Aug 20 2013 *** this
- Andrei Alexandrescu (3/11) Aug 20 2013 But this is again a value tuple not a template tuple, no?
- Timon Gehr (4/21) Aug 20 2013 In my understanding the former is a special case of the latter. Since
- deadalnix (4/22) Aug 20 2013 A value tuple IS a tuple. What we call a tuple here as nothing to
- H. S. Teoh (25/36) Aug 19 2013 Sounds like you're confused about what built-in tuples are (and you
- Meta (19/35) Aug 19 2013 I know the difference between std.typecons.Tuple and the built-in
- H. S. Teoh (47/58) Aug 19 2013 Actually, reading through DIP32 again, it sounds like Kenji is proposing
- Dicebot (5/5) Aug 19 2013 Random idea - what do you thing about merging current Tuple and
- Meta (8/78) Aug 19 2013 Maybe mixing should be disallowed, then, unless your tuple was
- Meta (55/86) Aug 19 2013 Maybe mixing should be disallowed, then, unless your tuple was
- H. S. Teoh (14/27) Aug 20 2013 [...]
- Kenji Hara (7/12) Aug 19 2013 Honestly, I had intended DIP32 to provide *uniform* syntax for both
- Kenji Hara (71/71) Aug 19 2013 Sorry I cannot reply to each thread comments quickly, so I discharge my
- John Colvin (5/20) Aug 20 2013 There are various other characters that could be substituted for #
- Jacob Carlborg (8/24) Aug 20 2013 If I recall correctly some ABI's passes small structs in registers, at
- Dicebot (41/44) Aug 20 2013 One thing that I think does not get deserved attention is that
- Meta (21/21) Aug 20 2013 This is the reason I had originally thought Kenji's DIP was about
- Dicebot (17/29) Aug 20 2013 Syntax sugar will only hide and eventually increase confusion, it
- Meta (34/50) Aug 20 2013 My suggestions are predicated on the fact that I think tuples are
- Andrei Alexandrescu (6/17) Aug 20 2013 That would be problematic to say the least. (There have been a few
- Dicebot (14/26) Aug 20 2013 Can you elaborate on this? I can only judge by observable
- Andrei Alexandrescu (43/51) Aug 20 2013 One problem with automatic expansion is that now there's a whole new
- Meta (3/4) Aug 20 2013 I can not agree more.
- Dicebot (14/16) Aug 20 2013 I guess I need just deal with it and accept as given then :)
- Tyler Jameson Little (28/52) Aug 20 2013 +1
- Andrei Alexandrescu (9/12) Aug 20 2013 I think this whole thread is approaching things wrongly. It should be:
- Kenji Hara (43/46) Aug 20 2013 Both
- Andrei Alexandrescu (13/29) Aug 21 2013 The current language would be D as it is today, with no syntactic
- bearophile (31/43) Aug 21 2013 OK.
- Meta (9/13) Aug 21 2013 I don't know if you saw this, but I mentioned in my other post an
- bearophile (164/166) Aug 20 2013 We can live fine without a syntax to manage tuples, so strictly
- H. S. Teoh (45/101) Aug 20 2013 You can't make 'i' a runtime value because D is a statically-typed
- bearophile (16/64) Aug 21 2013 Yep. (From several persons explaining me similar things in
- Dicebot (20/26) Aug 20 2013 Exactly. Though if we want to avoid breaking changes as much as
- Dicebot (7/13) Aug 20 2013 Also my answer to this question may probably be not very
- Michel Fortin (32/33) Aug 20 2013 I think D needs less tuples. It has two kinds (language kind and
- Jonathan M Davis (19/27) Aug 20 2013 I honestly think that trying to combine Tuple and TypeTuple would increa...
- Dicebot (7/10) Aug 21 2013 TypeTuple does not cover all built-in tuple cases. There is also
- Andrei Alexandrescu (4/15) Aug 21 2013 I agree. I think we could and should eliminate this requirement right
- Andrei Alexandrescu (18/30) Aug 21 2013 Yah, fewer tuples (or assigning distinct names to what we call today
- Michel Fortin (28/47) Aug 21 2013 That seems like the only thing everyone agrees with. :-)
- Meta (19/25) Aug 20 2013 Nothing. Everything discussed thus far can already be done in D,
- eles (9/12) Aug 20 2013 I agree. However, that syntax issue is the bikeshed and it keeps
- Andrei Alexandrescu (8/19) Aug 21 2013 That's wrong, too. Choose a syntax from _within_ the language, not from
- Timon Gehr (2/4) Aug 20 2013 +1. :)
- Kenji Hara (7/12) Aug 20 2013 +1, too.
- Michel Fortin (72/78) Aug 20 2013 I used to like auto expansion, probably because it was convenient for
- Kenji Hara (9/26) Aug 20 2013 "args" is a built-in tuple of two function parameter variables. In binar...
- Dicebot (11/15) Aug 20 2013 Yes but as you have said exact storage of built-in tuple elements
- Andrei Alexandrescu (4/20) Aug 20 2013 Ome question would be whether appropriate inlining could solve the
- bearophile (7/15) Aug 20 2013 With your idea is there a way to unpack a short array into
- bearophile (9/15) Aug 20 2013 It's supported in Haskell too:
- Dicebot (4/4) Aug 20 2013 bearophile I really respect informational contribution you have
- bearophile (10/15) Aug 20 2013 Look better at them, those aren't random snippets, they show one
- Timon Gehr (2/17) Aug 20 2013 Any language with algebraic data types supports this.
- Timon Gehr (3/23) Aug 20 2013 (Some will only allow it if you can prove the match is total within
- Kenji Hara (22/37) Aug 20 2013 My position to such a feature is constant. We should not conflate tuple
- bearophile (22/34) Aug 20 2013 Even if your opinion is not changed, I have to show that common
- bearophile (5/6) Aug 19 2013 About the same syntax should work for both packing and unpacking
- John Colvin (26/73) Aug 19 2013 All we have left from the standard keyboard layout as far as
- bearophile (36/60) Aug 19 2013 I think none of the suggested tuple syntaxes are well searchable
- Dicebot (21/23) Aug 19 2013 I was initially completely opposed against it but now that I have
- Wyatt (10/14) Aug 19 2013 I was primarily addressing the fact that there aren't many
- Meta (60/124) Aug 19 2013 I could very well be wrong, but I would bet that one of the
- bearophile (16/21) Aug 19 2013 You can't define a variable more than once in a scope, so this
- Meta (2/3) Aug 19 2013 That too.
- bearophile (8/13) Aug 19 2013 I need to get used to the proposed syntax, sorry:
- Andrei Alexandrescu (6/27) Aug 19 2013 It's stuff like this that's just useless and gives a bad direction to
- Meta (8/12) Aug 19 2013 I started this discussion to build on Kenji's DIP, which
- bearophile (6/10) Aug 19 2013 I was just explaining why _ can't be used as wildcard (unless you
- Andrei Alexandrescu (14/18) Aug 19 2013 I started this discussion to build on Kenji's DIP, which discusses
- Dicebot (6/8) Aug 19 2013 Wanted to note here that while discussing syntax at this moment
- Meta (26/35) Aug 19 2013 In fairness, it is very common in other languages with pattern
- captaindet (3/13) Aug 19 2013 same in matlab. once destruction->auto assignment is available, (future)...
- deadalnix (14/19) Aug 19 2013 I propose the following rewrite :
- Jonathan M Davis (3/5) Aug 19 2013 LOL! I'm going to have to remember that one.
- H. S. Teoh (7/12) Aug 20 2013 [...]
- Zach the Mystic (8/21) Aug 21 2013 I agree. The negative space *around* the bikeshed should be
- bearophile (9/15) Aug 21 2013 Andrei missed the point of that part of the discussion. That was
- Meta (7/24) Aug 19 2013 I was being dumb, [1, 2] ~ 3 is of course valid for arrays, so
- Mr. Anonymous (7/17) Aug 20 2013 Why not just leave an empty space, like php does:
- Wyatt (23/28) Aug 20 2013 Bad idea. It's a visual thing-- quick! How wide is this tuple!?:
- eles (7/18) Aug 20 2013 What about:
- Mr. Anonymous (2/23) Aug 20 2013 It's not only long, but also ugly (IMO of course).
- Timon Gehr (2/4) Aug 20 2013 This already has a meaning.
- eles (4/11) Aug 20 2013 True :( I dunno why I took it for some kind of binary operator
- Andrei Alexandrescu (3/22) Aug 20 2013 Somebody shoot me.
- H. S. Teoh (6/35) Aug 20 2013 [...]
- Jonathan M Davis (3/9) Aug 20 2013 Don't kill him. He hasn't finished the allocators yet! ;)
- Walter Bright (2/10) Aug 21 2013 Don't worry, we'll keep sliding food under his door!
- H. S. Teoh (10/19) Aug 20 2013 Well, as my signature line said:
- Daniel Murphy (5/6) Aug 21 2013 How about angle brackets?
- Jacob Carlborg (4/7) Aug 21 2013 Aren't we then back to the same problems C++ have with its template synt...
- QAston (5/12) Aug 21 2013 I propose <<<>>> to prevent any token ambiguities with <<<
- Andrei Alexandrescu (3/9) Aug 21 2013 No please.
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) 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[] 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 particular preference in that regard. would introduce too many complications. - There was no consensus on the pattern matching syntax for binding, "a", into the surrounding scope. The question is, what character should go in the place of "_" to signify that a value that's really necessary is a symbol that cannot also be an identifier. pattern matching for this situation. One idea I saw that looked good: * Use "..." to pattern match on the tail of an 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., around with this to get a few other useful constructs, such as etc. Assuming the "..." syntax for unpacking, it would be useful to 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 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
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.option. I don't think it looks too bad, but some people might find it ugly and noisyIt 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_syntaxthat'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
On Friday, 16 August 2013 at 23:48:53 UTC, bearophile wrote:Why do you say that? It seems to me that it would be better than so there's little overlap with other features.option. I don't think it looks too bad, but some people might find it ugly and noisyIt 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
Aug 16 2013
On 2013-08-16 20:02, Meta wrote:On Friday, 16 August 2013 at 23:48:53 UTC, bearophile 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. 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) /detWhy do you say that? It seems to me that it would be better than {}, because with other features.think it looks too bad, but some people might find it ugly and noisyIt 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
Aug 16 2013
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 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); //Passesif 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
On Friday, 16 August 2013 at 23:48:53 UTC, bearophile wrote:Meta: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 operatorAndrei/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.option. I don't think it looks too bad, but some people might find it ugly and noisyIt 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_syntaxthat'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 19 2013
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 operatorAre singleton tuples represented with (1:) ? Bye, bearophile
Aug 19 2013
On Monday, 19 August 2013 at 22:36:34 UTC, bearophile wrote:ixid:Sure, why not? It looks happy enough. :) Are singleton tuples actually useful for anything?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 operatorAre singleton tuples represented with (1:) ? Bye, bearophile
Aug 19 2013
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
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.On this, I think we all agree.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. On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote: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.option. I don't think it looks too bad, but some people might find it ugly and noisyThe 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 <=>) 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 binding, "a", into the surrounding scope. The question is, what character should go in the place of "_" to signify that a value but all that's really necessary is a symbol that cannot also be an identifier.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?)and pattern matching for this situation. One idea I saw that looked good:Ah, I was wondering about the case of a tuple of tuples. It's 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 obviously can't refer to "..." as a variable, so it also becomes a useful way of saying "don't care" for multiple items,containing a and a tuple of "everything else", because of the ellipsis' use in templated code. I think this is a little used for the discard character) to make it explicit.Assuming the "..." syntax for unpacking, it would be useful toAs a bonus, explicit discard means a simple comma omission is less likely to completely change the meaning of the statement. Compare: to b Granted, there's this case: ...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. rest // I'm not attached to the asterisk there.- Concatenating tuples with ~. This is nice to have, but not particularly important.What does concatenating a tuple actually do? That is: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
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:Check "Token Strings" in http://dlang.org/lex.htmlIt's short, clear, has a precedent with q{}.Wait, what is q{}?
Aug 19 2013
On Monday, 19 August 2013 at 16:57:35 UTC, Dicebot wrote:Check "Token Strings" in http://dlang.org/lex.htmlDidn't make it to the end of the paragraph? ;)
Aug 19 2013
On Mon, Aug 19, 2013 at 06:53:05PM +0200, Wyatt 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. T -- MACINTOSH: Most Applications Crash, If Not, The Operating System HangsThis 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. ;)
Aug 19 2013
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
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: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.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.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 noticeAs 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
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: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.On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:Well, OK, whatever they're supposed to be called. Compiler-tuples, or expression tuples, or whatever.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.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
On 8/19/13 10:54 AM, Dicebot wrote:On Monday, 19 August 2013 at 17:45:44 UTC, H. S. Teoh wrote:I'd call them alias tuples. AndreiOn Mon, Aug 19, 2013 at 07:34:38PM +0200, Dicebot wrote:Well, technically they are compile-time tuples of stuff.On Monday, 19 August 2013 at 17:22:26 UTC, H. S. Teoh wrote:Well, OK, whatever they're supposed to be called. Compiler-tuples, or expression tuples, or whatever.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.
Aug 19 2013
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
On 8/19/13 11:14 AM, Dicebot wrote:On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu wrote:I'm thinking such a tuple may hold everything that one may define an alias to. AndreiI'd call them alias tuples.Because we don't have strict definition of alias too? :)
Aug 19 2013
On Monday, 19 August 2013 at 20:36:10 UTC, Andrei Alexandrescu wrote:On 8/19/13 11:14 AM, Dicebot wrote: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.On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu wrote:I'm thinking such a tuple may hold everything that one may define an alias to.I'd call them alias tuples.Because we don't have strict definition of alias too? :)
Aug 19 2013
On 8/19/13 1:41 PM, Dicebot wrote:On Monday, 19 August 2013 at 20:36:10 UTC, Andrei Alexandrescu wrote:Normal alias. Yah, perhaps "template tuples" are more descriptive. AndreiOn 8/19/13 11:14 AM, Dicebot wrote:Normal alias or template alias parameter? ;)On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu wrote:I'm thinking such a tuple may hold everything that one may define an alias to.I'd call them alias tuples.Because we don't have strict definition of alias too? :)
Aug 19 2013
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
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
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
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
On Monday, 19 August 2013 at 19:24:32 UTC, Timon Gehr wrote:On 08/19/2013 07:44 PM, H. S. Teoh wrote: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?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
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:Pretty heavy on the snark though :POn 08/19/2013 07:44 PM, H. S. Teoh wrote: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?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
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
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
On Mon, Aug 19, 2013 at 08:10:38PM +0200, Dicebot wrote:On Monday, 19 August 2013 at 17:57:45 UTC, Meta 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. 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' PerryAs 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
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
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() { int)) } *Unless* you use .expand/[] (pick your poison): void main() { }
Aug 19 2013
On Monday, 19 August 2013 at 23:55:32 UTC, Meta wrote:On Monday, 19 August 2013 at 23:48:36 UTC, Meta 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....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() { int)) } *Unless* you use .expand/[] (pick your poison): void main() { }
Aug 19 2013
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
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
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
On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu wrote:On 8/19/13 4:48 PM, Meta wrote: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? { return tuple(1, "a"); //Error? }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");
Aug 19 2013
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
On 8/19/13 5:14 PM, Meta wrote:On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu wrote:Why would it be necessary to return an object of type TypeTuple (i.e. template tuple)? It has no state. AndreiOn 8/19/13 4:48 PM, Meta wrote: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? { return tuple(1, "a"); //Error? }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");
Aug 19 2013
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
On 20 August 2013 16:39, Timon Gehr <timon.gehr gmx.ch> wrote:On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:*** 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.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.
Aug 20 2013
On 8/19/13 11:39 PM, Timon Gehr wrote:On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:But this is again a value tuple not a template tuple, no? AndreiWhy 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);
Aug 20 2013
On 08/20/2013 08:51 PM, Andrei Alexandrescu wrote:On 8/19/13 11:39 PM, Timon Gehr wrote: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?On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:But this is again a value tuple not a template tuple, no? AndreiWhy 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);
Aug 20 2013
On Tuesday, 20 August 2013 at 18:51:23 UTC, Andrei Alexandrescu wrote:On 8/19/13 11:39 PM, Timon Gehr wrote:A value tuple IS a tuple. What we call a tuple here as nothing to do with a tuple.On 08/20/2013 02:18 AM, Andrei Alexandrescu wrote:But this is again a value tuple not a template tuple, no? AndreiWhy 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);
Aug 20 2013
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: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 HangsOn 8/19/13 4:48 PM, Meta wrote:That's not a TypeTuple, though, it's a built-in tuple.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");
Aug 19 2013
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
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: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. ErdosSounds 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.
Aug 19 2013
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
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. 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
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: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 //Error //Ok 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 //Ok }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).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]; x[]++; writeln(tupe);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 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. 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. alias tupType = typeof(tup); 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.Should the output change if the second line is changed to: alias tup = {1; x}; ?
Aug 19 2013
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:[...] 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 -- Без труда не выловишь и рыбку из пруда.On Tuesday, 20 August 2013 at 01:06:28 UTC, H. S. Teoh wrote:Maybe mixing should be disallowed, then, unless your tuple was constructed from a variadic template argument list.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).
Aug 20 2013
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
Aug 19 2013
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: Sequences" http://dlang.org/lex.html#Special Token Sequence 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
Aug 19 2013
On Tuesday, 20 August 2013 at 03:33:51 UTC, Kenji Hara wrote:---- My opinions agains various syntax proposals: Token Sequences" http://dlang.org/lex.html#Special Token Sequence It is recognized in lexing phase, so adding semantic meaning to 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 Harae.g. &(1, "string") http://forum.dlang.org/post/cokiixatvjmngggpblma forum.dlang.org
Aug 20 2013
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: Sequences" http://dlang.org/lex.html#Special Token Sequence 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 mean tuple literal. -- /Jacob Carlborg
Aug 20 2013
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
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
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
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
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
On Tuesday, 20 August 2013 at 20:16:54 UTC, Andrei Alexandrescu wrote:On 8/20/13 6:57 AM, Dicebot wrote: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.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.: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.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.)
Aug 20 2013
On 8/20/13 1:24 PM, Dicebot wrote:"Spawn of Satan" would be a tad more appropriate.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.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
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
On Tuesday, 20 August 2013 at 21:25:11 UTC, Andrei Alexandrescu wrote:Ionno so I just summarized it. AndreiI 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
On Tuesday, 20 August 2013 at 21:25:11 UTC, Andrei Alexandrescu wrote:On 8/20/13 1:24 PM, Dicebot wrote:+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..."Spawn of Satan" would be a tad more appropriate.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!+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();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.Clearly both packing and unpacking tuples are necessary. snip... AndreiOT: 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
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
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 alanguage 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
Aug 20 2013
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
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
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
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
On Wed, Aug 21, 2013 at 03:43:45AM +0200, bearophile wrote:Andrei Alexandrescu:This is adequately taken care of by std.typecons.Tuple, isn't it?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.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
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: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.We can live fine without a syntax to manage tuples, so strictly speaking we need nothingWhat 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
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
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: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.I think this whole thread is approaching things wrongly. It should be: 1. What do we need?
Aug 20 2013
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
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: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 Davis1. 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.
Aug 20 2013
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
On 8/20/13 8:39 PM, Jonathan M Davis wrote:On Tuesday, August 20, 2013 23:25:03 Michel Fortin wrote:I agree. I think we could and should eliminate this requirement right off the bat. AndreiOn 2013-08-21 00:38:30 +0000, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I honestly think that trying to combine Tuple and TypeTuple would increase the confusion1. 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.
Aug 21 2013
On 8/20/13 8:25 PM, Michel Fortin wrote:On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Yah, fewer tuples (or assigning distinct names to what we call today such) would be awesome.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 argumentI'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
On 2013-08-21 16:59:17 +0000, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:On 8/20/13 8:25 PM, Michel Fortin wrote:That seems like the only thing everyone agrees with. :-)On 2013-08-21 00:38:30 +0000, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Yah, fewer tuples (or assigning distinct names to what we call today such) would be awesome.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'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.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.caint 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.
Aug 21 2013
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
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
On 8/20/13 11:08 PM, eles wrote:On Wednesday, 21 August 2013 at 00:38:31 UTC, Andrei Alexandrescu wrote: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). AndreiOn 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 21 2013
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
2013/8/21 Timon Gehr <timon.gehr gmx.ch>On 08/20/2013 10:16 PM, Andrei Alexandrescu wrote:+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(There have been a few discussions in this group; I've come to think auto expansion is fail.)+1. :)
Aug 20 2013
On 2013-08-20 20:16:48 +0000, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:On 8/20/13 6:57 AM, Dicebot wrote: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.caPreserve 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.)
Aug 20 2013
2013/8/20 Dicebot <public dicebot.lv>What we have here are two completely different _built-in_ tuple types. "T" is pure template arguments list and is pretty much equal TypeTuple!(int, int). But what is "args"? It uses the very same built-in tuple syntax but it is much closer to std.typecons.Tuple in its behavior (actually, latter is implemented in terms of it as I was pointed out) - it is an entity that provides abstraction of top of group of run-time values. It does not have any binary structure on its own (built on top of existing values) but observable semantic are very "run-time'ish"."args" is a built-in tuple of two function parameter variables. In binary level, args[0] and args[1] could be bounded to completely individual storage. (Even if args[1] is on stack, args[0] may be on register) On the other hand, std.typecons.Tuple is a struct. Its second field has the memory address which follows of the first field. What bothers me is the question "can we clean this up and bring those twoworlds 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
Aug 20 2013
On Tuesday, 20 August 2013 at 15:43:39 UTC, Kenji Hara wrote:On the other hand, std.typecons.Tuple is a struct. Its second field has the memory address which follows of the first field.Yes but as you have said exact storage of built-in tuple elements is not defined - it can be distinct elements or struct fields, compiler is free to chose any. I am not asking about internal implementation but about behavior observable by user in typical cases - it is most important topic here.Automatically packing/unpacking would need hidden runtime cost.Will it be any more costly then returning std.typecons.Tuple and unpacking it manually? And, well, do we have _any_ other option of returning a tuple with no runtime costs right now anyway? Considering we are far away from stable ABI that does not seem to be a real issue.
Aug 20 2013
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
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:'red's = "red blue" (a, b) = s.split() a'blue' Bye, bearophileb
Aug 20 2013
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'red's = "red blue" (a, b) = s.split() a'blue'b
Aug 20 2013
bearophile I really respect informational contribution you have been doing in D community but in my opinion mentioning random snippets from other languages is the least useful thing possible in this thread. It is even less useful than discussing syntax.
Aug 20 2013
Dicebot:bearophile I really respect informational contribution you have been doing in D community but in my opinion mentioning random snippets from other languages is the least useful thing possible in this thread. It is even less useful than discussing syntax.Look better at them, those aren't random snippets, they show one more case of de-structuring, creating a tuple of variables out of an array. It's a commonly used operation in two very well designed languages that have tuples. Here we are discussing tuples and their packing and unpacking, so the two examples I've shown are very relevant, even if we decide to not support that specific feature. Bye, bearophile
Aug 20 2013
On 08/20/2013 05:18 PM, bearophile wrote:Any language with algebraic data types supports this.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'red's = "red blue" (a, b) = s.split() a'blue'b
Aug 20 2013
On 08/20/2013 09:57 PM, Timon Gehr wrote:On 08/20/2013 05:18 PM, bearophile wrote:(Some will only allow it if you can prove the match is total within them, of course.)Any language with algebraic data types supports this.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'red's = "red blue" (a, b) = s.split() a'blue'b
Aug 20 2013
2013/8/20 bearophile <bearophileHUGS lycos.com>So, std.typecons.Tuple _is not special_. You can define another TupleMy 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 Harastruct in the same way. We should not define new syntax for the library utility std.typecons.Tuple.With your idea is there a way to unpack a short array into variables? This is an handy operation I do often in Python: s = "red blue"(a, b) = s.split() a'red'b'blue'
Aug 20 2013
Kenji Hara:My position to such a feature is constant.Even if your opinion is not changed, I have to show that common tuple-related features to the other persons that are reading this thread, because it's an an idea to keep in account (even if it's refused), and some other person could have an opinion different from yours.However, array unpacking would require *hidden* runtime boundary check. In above example code, assert(tup[2].length == 2); // or if (tup[2].length != 2) throw Error("Runtime mismatch of unpacking pattern"); // or similar should be implicitly inserted by compiler, even in system code. I'm not sure that is acceptable cost or not.Runtime boundary checks and tests are not needed if you unpack a fixed-sized array: auto tup = Tuple!(int, string[2])(1, ["red", "blue"]); auto {x, [c1, c2]} = tup; Regarding the de-structuring of dynamic arrays, I think it's not too much different than this: void main() { int[] a = [10, 20, 30]; int[2] b = a; } If you compile and run it without switches, you get at run-time: object.Error: lengths don't match for array copy, 2 = 3 While I receive no run-time errors if I compile with -noboundscheck. Bye, bearophile
Aug 20 2013
Andrei Alexandrescu:return tuple(1, "a");About the same syntax should work for both packing and unpacking tuples. Bye, bearophile
Aug 19 2013
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:All we have left from the standard keyboard layout as far as 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) //I think.... /(a, b) \(a, b)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.On this, I think we all agree.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. On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote: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.option. I don't think it looks too bad, but some people might find it ugly and noisyThe 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 <=>)(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
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%3EI 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.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 aIn 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:Assuming the "..." syntax for unpacking, it would be useful toBearophile 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
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
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, aI was primarily addressing the fact that there aren't many _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
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 onlyAddressing 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.containing a and a tuple of "everything else", because of the ellipsis' use in templated code. I think this is a little 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 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: else to b Granted, there's this case: ...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:Thought: Is there sufficient worth in having different tokens for discarding a single element vs. a range? e.g. rest // I'm not attached to the asterisk there.Not sure. I need to think about it.I think it should work the same as with arrays. So: 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: Which is messy, but at least it's explicit about what is going on.- Concatenating tuples with ~. This is nice to have, but not particularly important.What does concatenating a tuple actually do? That is:Great! After this, let's fix properties. ;)Oh boy, no need to start *another* flame war.
Aug 19 2013
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 (_, _, x) = t1; auto (_, gr, _) = t1; } While ? defines nothing, so this is OK: void main() { auto (?, ?, x) = t1; auto (?, gr, ?) = t1; } Bye, bearophile
Aug 19 2013
On Monday, 19 August 2013 at 19:54:43 UTC, bearophile wrote:...That too.
Aug 19 2013
void main() { auto (_, _, x) = t1; auto (_, gr, _) = t1; }I need to get used to the proposed syntax, sorry: void main() { } Bye, bearophile
Aug 19 2013
On 8/19/13 12:54 PM, bearophile wrote:Meta: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. AndreiIt *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 (_, _, x) = t1; auto (_, gr, _) = t1; } While ? defines nothing, so this is OK: void main() { auto (?, ?, x) = t1; auto (?, gr, ?) = t1; } Bye, bearophile
Aug 19 2013
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
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
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
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
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. 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
On 2013-08-19 17:04, Meta wrote:On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu wrote: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. /detb) 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.
Aug 19 2013
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
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
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:[...] 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.but once the bikeshed is up for painting, the rainbow won't suffice.LOL! I'm going to have to remember that one.
Aug 20 2013
On Monday, 19 August 2013 at 20:46:02 UTC, Andrei Alexandrescu wrote: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. )void main() { auto (?, ?, x) = t1; auto (?, gr, ?) = t1; } Bye, bearophileIt'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 21 2013
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
On Monday, 19 August 2013 at 18:43:37 UTC, Meta wrote:I was being dumb, [1, 2] ~ 3 is of course valid for arrays, soWhat does concatenating a tuple actually do? That is:I think it should work the same as with arrays. So: array 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: 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
On Monday, 19 August 2013 at 18:43:37 UTC, Meta wrote:On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt 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"; http://php.net/manual/en/function.list.phpCan'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.
Aug 20 2013
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!?: 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). 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: 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
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) option. I don't think it looks too bad, but some people might find it ugly and noisyWhat about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .
Aug 20 2013
On Tuesday, 20 August 2013 at 10:38:30 UTC, eles wrote:On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:It's not only long, but also ugly (IMO of course).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) option. I don't think it looks too bad, but some people might find it ugly and noisyWhat about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .
Aug 20 2013
On 08/20/2013 12:38 PM, eles wrote:What about: !!(a, b)This already has a meaning.
Aug 20 2013
On Tuesday, 20 August 2013 at 13:14:46 UTC, Timon Gehr wrote:On 08/20/2013 12:38 PM, eles wrote: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.What about: !!(a, b)This already has a meaning.
Aug 20 2013
On 8/20/13 3:38 AM, eles wrote:On Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:Somebody shoot me. AndreiA 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) don't think it looks too bad, but some people might find it ugly and noisyWhat about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .
Aug 20 2013
On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:On 8/20/13 3:38 AM, eles wrote:[...] 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 KillOn Friday, 16 August 2013 at 21:07:52 UTC, Meta wrote:Somebody shoot me.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) don't think it looks too bad, but some people might find it ugly and noisyWhat about: !!(a, b) ? Yes, is long, but is type-able quite fast. Alternative would be: ??(a, b) .
Aug 20 2013
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:Don't kill him. He hasn't finished the allocators yet! ;) - Jonathan M DavisSomebody shoot me.[...] BANG!
Aug 20 2013
On 8/20/2013 1:10 PM, Jonathan M Davis wrote:On Tuesday, August 20, 2013 13:06:27 H. S. Teoh wrote:Don't worry, we'll keep sliding food under his door!On Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:Don't kill him. He hasn't finished the allocators yet! ;)Somebody shoot me.[...] BANG!
Aug 21 2013
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: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? -- YHLOn Tue, Aug 20, 2013 at 11:53:50AM -0700, Andrei Alexandrescu wrote:Don't kill him. He hasn't finished the allocators yet! ;)Somebody shoot me.[...] BANG!
Aug 20 2013
"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
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
On Wednesday, 21 August 2013 at 16:39:14 UTC, Jacob Carlborg wrote:On 2013-08-21 18:01, Daniel Murphy wrote:I propose <<<<a, b>>>> to prevent any token ambiguities with <<< and >>. PS. Poor Andrei.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?
Aug 21 2013
On 8/21/13 9:01 AM, Daniel Murphy wrote:"Meta" <jared771 gmail.com> wrote in message news:evamvyfxasouvwzublxc forum.dlang.org...No please. AndreiThat 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