Discussion:
A Discussion of Tuple Syntax
(too old to reply)
Meta
2013-08-16 21:07:50 UTC
Permalink
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.digitalmars-d at puremagic.com,
and further discussion in this thread:
http://forum.dlang.org/thread/dofwinzpbcdwkvhzcgrk at forum.dlang.org.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This is the third or fourth time that I know of that tuple syntax
has come up, and as of yet, nothing has been done about it. I'd
really like to get the ball rolling on this, as I think a good
syntax for these tuple operations would do D a world of good. I'm
not a compiler hacker, unfortunately, so I can't implement it
myself as proof of concept... However, I hope that discussing it
and working out all the kinks will help pave the way for an
actual implementation.
bearophile
2013-08-16 23:48:52 UTC
Permalink
Andrei/Walter didn't want to merge that pull request without a
full consideration of the different design issues involved,
which in retrospect was a good decision.
I agree that before adding some new syntax you have to think well.
- {a, b} is not as pretty, but it's not that bad of an
alternative (though it may still have issues as well)
It has technical issues, they were discussed in one of the last
threads. Such problems should be added in a note in the DIP32, so
they don't get lost in time.
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
It looks nice (but I don't know if it's technically usable), I
have added it at the end of the list of alternative syntaxes:
http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
I personally think #(a, ?) or #(a, *) would be best, but all
that's really necessary is a symbol that cannot also be an
identifier.
I think ? is clear, unambiguous, etc, and I like it. The * is
already used for pointers, product, dereferencing, ** is used for
pow, so it's better to not add further meanings to it.
- Concatenating tuples with ~. This is nice to have, but not
particularly important.
In theory I like this operation, but in practice in my D code I
don't need it often, so I think it should be left out, for later.
In Python I sometimes concatenate tuples, but in such use cases
they are essentially immutable dynamically typed arrays, losing
their positional meaning.


Tuples could also be used in switch/case statements, to support a
very basic form of pattern matching. See also a standard method
named "unapply" I have discussed a bit here, coming from Scala
language, that is a very simple solution to solve a significant
problem:
http://d.puremagic.com/issues/show_bug.cgi?id=596

Bye,
bearophile
Meta
2013-08-17 01:02:31 UTC
Permalink
Post by bearophile
Post by Meta
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
It looks nice (but I don't know if it's technically usable), I
http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
Why do you say that? It seems to me that it would be better than
{}, because there's only 1 other language construct that uses #,
so there's little overlap with other features.
captaindet
2013-08-17 05:48:25 UTC
Permalink
Post by bearophile
- #(a, b) is unambiguous and would probably be the easiest option. I don't think it looks too bad, but some people might find it ugly and noisy
http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
Why do you say that? It seems to me that it would be better than {}, because there's only 1 other language construct that uses #, so there's little overlap with other features.
not sure what we are talking about here, new syntax for
a) TypeTuple (that would be my best guess but i am not sure)
b) std.typecons.Tuple
c) both, a unified syntax
the DIP is not completely clear about this either.

only case (a) is hot at the moment and i fell into some related pits recently myself. so i'd love to have a better syntax, one that makes the dirty hack (status quo) a proper part of the language - as it is widely used already and very powerful.

i am curious too if ..(..) constructs are completely out of the question. if not, i would suggest as shorthand:

!(a,b)

this reminds of template instantiation and is exactly how the awkwardly/confusingly named TypeTuple is realized now, as an alias to its own template arguments. if we need a name for it, it should not remind at all of 'tuple' - since there is also the completely unrelated std.typecons.Tuple. a more verbose/explicit suggestion would be

symbols(a,b)


/det
Meta
2013-08-17 07:02:47 UTC
Permalink
Post by captaindet
not sure what we are talking about here, new syntax for
a) TypeTuple (that would be my best guess but i am not sure)
b) std.typecons.Tuple
c) both, a unified syntax
the DIP is not completely clear about this either.
First and foremost, a new syntax for std.typecons.Tuple. Creating
tuple literals -> #(1, "a", false), pattern matching on tuples ->
switch (#(1, 2)), and destructuring of tuples -> #(a, b) = #(1,
2).

A good question is whether this syntax can (and more importantly,
should) be used for TypeTuples as well. TypeTuples are poorly
named and not at all similar to Tuple, so it doesn't make much
sense to give them both the same syntax. Also, I can't see
TypeTuple seeing nearly as much use as Tuple, so it may be better
to introduce the new syntax for Tuple, and keep TypeTuple as-is.
Post by captaindet
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.
Post by captaindet
i am curious too if ..(..) constructs are completely out of the
!(a,b)
this reminds of template instantiation and is exactly how the
awkwardly/confusingly named TypeTuple is realized now, as an
alias to its own template arguments.
Unfortunately, that won't work, as the value of this expression
is already well-defined in the current language. A list of
comma-separated expressions means that each is evaluated from
left to right, and then the result of the entire expression is
the result of the rightmost expression, e.g.:

auto a = true;
auto b = false;
//Evaluate a, then b. The result of the expression
//in the brackets is b. Then the ! gets applied to b
auto x = !(a, b);
assert(x == true); //Passes
Post by captaindet
if we need a name for it, it should not remind at all of
'tuple' - since there is also the completely unrelated
std.typecons.Tuple. a more verbose/explicit suggestion would be
symbols(a,b)
I 100% agree that TypeTuple needs a better name. A couple other
suggestions were put forward as well in the other tuple thread
currently active.
ixid
2013-08-19 22:08:25 UTC
Permalink
Post by bearophile
Andrei/Walter didn't want to merge that pull request without a
full consideration of the different design issues involved,
which in retrospect was a good decision.
I agree that before adding some new syntax you have to think
well.
- {a, b} is not as pretty, but it's not that bad of an
alternative (though it may still have issues as well)
It has technical issues, they were discussed in one of the last
threads. Such problems should be added in a note in the DIP32,
so they don't get lost in time.
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
It looks nice (but I don't know if it's technically usable), I
http://wiki.dlang.org/DIP32#Use_case_of_uniform_tuple_syntax
I personally think #(a, ?) or #(a, *) would be best, but all
that's really necessary is a symbol that cannot also be an
identifier.
I think ? is clear, unambiguous, etc, and I like it. The * is
already used for pointers, product, dereferencing, ** is used
for pow, so it's better to not add further meanings to it.
- Concatenating tuples with ~. This is nice to have, but not
particularly important.
In theory I like this operation, but in practice in my D code I
don't need it often, so I think it should be left out, for
later.
In Python I sometimes concatenate tuples, but in such use cases
they are essentially immutable dynamically typed arrays, losing
their positional meaning.
Tuples could also be used in switch/case statements, to support
a very basic form of pattern matching. See also a standard
method named "unapply" I have discussed a bit here, coming from
Scala language, that is a very simple solution to solve a
http://d.puremagic.com/issues/show_bug.cgi?id=596
Bye,
bearophile
What about using : as people had intended to use the comma
operator?
uint a, b;
(a : b) = (1 : 2);
(a : b) = tupleReturningFunction;
auto c = (1 : (2 : 3)); // A tuple containing a tuple
auto d = (1 : ((2 : 3) : (4 : 5))); // a tuple with a tuple of
tuples as a member

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

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

It's nicer looking than #().
bearophile
2013-08-19 22:36:32 UTC
Permalink
Post by ixid
auto assoc_array = [1 : (2 : 3)]; // A tuple associative value
auto assoc_array2 = [(1 : 2) : 3]; // A tuple associative key
auto ternary = value? (1 : 2) : (3 : 4); // tuple values in a
ternary operator
It's nicer looking than #().
Are singleton tuples represented with (1:) ?

Bye,
bearophile
ixid
2013-08-19 23:23:39 UTC
Permalink
Post by bearophile
Post by ixid
auto assoc_array = [1 : (2 : 3)]; // A tuple associative value
auto assoc_array2 = [(1 : 2) : 3]; // A tuple associative key
auto ternary = value? (1 : 2) : (3 : 4); // tuple values in a
ternary operator
It's nicer looking than #().
Are singleton tuples represented with (1:) ?
Bye,
bearophile
Sure, why not? It looks happy enough. :) Are singleton tuples
actually useful for anything?
bearophile
2013-08-19 23:31:50 UTC
Permalink
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
Wyatt
2013-08-19 16:53:05 UTC
Permalink
Note: I'm leading off with a reply to bearophile transplanted
here to stop making OT noise in John's thread about TypeTuple.
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.
I'd prefer just using parentheses, but I think there were
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.
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.
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
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 <=>)

Addressing the other suggestion I saw that cropped up, I
personally find the two-character "bananas" to be impressively
ugly. I considered suggesting some permutation on that same
idea, but after toying with a few examples I find it ends up
looking awful and I think it's honestly annoying to type them in
any form. I even don't like how the unicode version of that one
looks; for doubling up, I think ? ? or ? ? or are easier on the
eyes.

It's times like these that I wish the standard PC keyboard had
something like guillemets ? ?, or corner brackets ? ? (big fan of
these) in addition to everything else. (Or even that we could use
< > for bracing, though at this point I don't think I could
easily condone that move for D).

I feel weird admitting this, but if we can't use some manner of
bare brace, I think I'd rather have tup(), tup[], tup{} (or even
tuple() et al) as a prefix over any single character.

Another stray thought: is there room for a little box of syntax
chocolate so that e.g. tuple(), [||], and ? ? are all valid? I
don't know if we have a precedent like that off the top of my
head and I'm pretty sure I don't like it, but I thought I'd at
least mention it.
- There was no consensus on the pattern matching syntax for
unpacking. For example, #(a, _) = #(1, 2) only introduces one
binding, "a", into the surrounding scope. The question is, what
character should go in the place of "_" to signify that a value
#(a, ?). I personally think #(a, ?) or #(a, *) would be best,
but all that's really necessary is a symbol that cannot also
be an identifier.
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?)
Also up for debate was nested patterns, e.g., #(1, 2, #(3,
4, #(5, 6))). I don't think there was a consensus on unpacking
and pattern matching for this situation. One idea I saw that
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
expressions, so take the above tuple. The pattern #(1, ?, ...)
would match the two nested sub-tuples. Or, say, #(1, 2, 3)
could be matched by #(1, 2, 3), #(1, ?, 3), #(1, ...), etc. You
obviously can't refer to "..." as a variable, so it also
becomes a useful way of saying "don't care" for multiple items,
e.g., #(a, ...) -> only bind the first item in the tuple. We
#(a, ...) looks like to me like it would make a 2-tuple
containing a and a tuple of "everything else", because of the
ellipsis' use in templated code. I think this is a little
unclear, so instead I'd prefer #(a, ? ...) (or whatever ends up
used for the discard character) to make it explicit.
Assuming the "..." syntax for unpacking, it would be useful to
name the captured tail. For example, you could unpack #(1, 3,
#(4, 6)) into #(a, b, x...), where a = 1, b = 3, x = #(4, 6).
Similarly, #(head, rest...) results in head = 1, rest = #(2,
#(4, 6)). I think this would be very useful.
As a bonus, explicit discard means a simple comma omission is
less likely to completely change the meaning of the statement.
Compare:
#(a, b, ...) //bind the first two elements, discard the rest.
#(a, b ...) //bind the first element to a and everything else
to b
#(a, b, ? ...) //same as the first
#(a, b ? ...) //syntax error

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

Thought: Is there sufficient worth in having different tokens for
discarding a single element vs. a range? e.g.
#(a, ?, c, * ...) //bind first and third elements; discard the
rest
// I'm not attached to the asterisk there.
- Concatenating tuples with ~. This is nice to have, but not
particularly important.
What does concatenating a tuple actually do? That is:
auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right?
auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b ==
#(1,2,3,4,5)?
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
Dicebot
2013-08-19 16:57:33 UTC
Permalink
Post by Wyatt
Note: I'm leading off with a reply to bearophile transplanted
here to stop making OT noise in John's thread about TypeTuple.
It's short, clear, has a precedent with q{}.
Wait, what is q{}?
Check "Token Strings" in http://dlang.org/lex.html
Wyatt
2013-08-19 17:17:38 UTC
Permalink
Post by Dicebot
Check "Token Strings" in http://dlang.org/lex.html
Didn't make it to the end of the paragraph? ;)
H. S. Teoh
2013-08-19 17:20:58 UTC
Permalink
On Mon, Aug 19, 2013 at 06:53:05PM +0200, Wyatt wrote:
[...]
Post by Wyatt
Post by Meta
This is the third or fourth time that I know of that tuple syntax
has come up, and as of yet, nothing has been done about it. I'd
really like to get the ball rolling on this, as I think a good
syntax for these tuple operations would do D a world of good. I'm
not a compiler hacker, unfortunately, so I can't implement it
myself as proof of concept... However, I hope that discussing it
and working out all the kinks will help pave the way for an actual
implementation.
Great! After this, let's fix properties. ;)
[...]

What I'd like to know, is how all of these proposals address the
fundamental differences between "symbol tuples" (compile-time construct)
and std.range.Tuple (runtime construct). As far as I can tell, people
are still confusing the two, and it's really not helping. Before we
solve this, any syntax suggestion seems more like a mortician's work
than a real solution.


T
--
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
John Colvin
2013-08-19 17:30:27 UTC
Permalink
Post by Wyatt
Note: I'm leading off with a reply to bearophile transplanted
here to stop making OT noise in John's thread about TypeTuple.
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.
I'd prefer just using parentheses, but I think there were
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.
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.
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
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 <=>)
All we have left from the standard keyboard layout as far as
single keys go is # and ?
I don't think the mathematics crowd would be too happy with ? not
meaning not.

The only op() options I can think of that aren't ambiguous:
$(a, b)
%(a, b)
^(a, b)
&(a, b) //I like this one
:(a, b)
#(a, b)
'(a, b) //I think....
/(a, b)
\(a, b)
Post by Wyatt
(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.
Dicebot
2013-08-19 17:34:38 UTC
Permalink
Post by H. S. Teoh
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.
Post by H. S. Teoh
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.
H. S. Teoh
2013-08-19 17:44:18 UTC
Permalink
Post by Dicebot
Post by H. S. Teoh
What I'd like to know, is how all of these proposals address the
fundamental differences between "symbol tuples" (compile-time
construct)
Those are not symbol tuples. For example, `int` is not a symbol.
http://dlang.org/template.html#Symbol - only things that have
identifiers and template instances are symbols.
Well, OK, whatever they're supposed to be called. Compiler-tuples, or
expression tuples, or whatever. See, part of the problem is that they
just don't have any good name that correctly conveys what they are.
Calling them "tuple" only adds to the confusion because of the
conflation with std.range.Tuple.
Post by Dicebot
Post by H. S. Teoh
As far as I can tell, people are still confusing the two, and it's
really not helping.
Completely removing TypeTuple from library (which native syntax will
enable) will help to remove large part of confusion.
That's only part of the problem. It doesn't solve the problem of
conflation between these tuples and std.range.Tuple, and from what I can
tell in these threads, people are still confusing the two. Both of them
being named some kind of "tuple" doesn't help the problem.

This is one of the things about D that's seriously WAT-worthy.


T
--
If it breaks, you get to keep both pieces. -- Software disclaimer notice
Dicebot
2013-08-19 17:54:20 UTC
Permalink
Post by H. S. Teoh
Post by Dicebot
Post by H. S. Teoh
What I'd like to know, is how all of these proposals address
the
fundamental differences between "symbol tuples" (compile-time
construct)
Those are not symbol tuples. For example, `int` is not a
symbol.
http://dlang.org/template.html#Symbol - only things that have
identifiers and template instances are symbols.
Well, OK, whatever they're supposed to be called.
Compiler-tuples, or
expression tuples, or whatever.
Well, technically they are compile-time tuples of stuff. Yep,
that bad :) They don't have a good name because they don't have a
good meaning, only behavior.
Post by H. S. Teoh
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...
Andrei Alexandrescu
2013-08-19 18:11:33 UTC
Permalink
Post by Dicebot
Post by H. S. Teoh
Post by Dicebot
What I'd like to know, is how all of these proposals address >the
fundamental differences between "symbol tuples" (compile-time
construct)
Those are not symbol tuples. For example, `int` is not a symbol.
http://dlang.org/template.html#Symbol - only things that have
identifiers and template instances are symbols.
Well, OK, whatever they're supposed to be called. Compiler-tuples, or
expression tuples, or whatever.
Well, technically they are compile-time tuples of stuff.
I'd call them alias tuples.

Andrei
Dicebot
2013-08-19 18:14:24 UTC
Permalink
On Monday, 19 August 2013 at 18:11:34 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
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.
Andrei Alexandrescu
2013-08-19 20:36:09 UTC
Permalink
Post by Dicebot
Post by Andrei Alexandrescu
I'd call them alias tuples.
Because we don't have strict definition of alias too? :)
I'm thinking such a tuple may hold everything that one may define an
alias to.

Andrei
Dicebot
2013-08-19 20:41:46 UTC
Permalink
On Monday, 19 August 2013 at 20:36:10 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
Post by Dicebot
Post by Andrei Alexandrescu
I'd call them alias tuples.
Because we don't have strict definition of alias too? :)
I'm thinking such a tuple may hold everything that one may
define an alias to.
Normal alias or template alias parameter? ;) Because those two
are different :P Former can't take lambda literals. Latter won't
accept built-in types like int.

But built-in tuple is fine with both. "T..." is a _very_ special
thing in D.
Andrei Alexandrescu
2013-08-19 20:51:47 UTC
Permalink
Post by Dicebot
Post by Andrei Alexandrescu
Post by Dicebot
Post by Andrei Alexandrescu
I'd call them alias tuples.
Because we don't have strict definition of alias too? :)
I'm thinking such a tuple may hold everything that one may define an
alias to.
Normal alias or template alias parameter? ;)
Normal alias. Yah, perhaps "template tuples" are more descriptive.

Andrei
Dicebot
2013-08-19 21:12:54 UTC
Permalink
On Monday, 19 August 2013 at 20:51:47 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
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)
Meta
2013-08-19 18:54:35 UTC
Permalink
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?
Andrei Alexandrescu
2013-08-19 20:43:19 UTC
Permalink
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
Timon Gehr
2013-08-19 19:24:31 UTC
Permalink
Post by H. S. Teoh
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)
Brad Anderson
2013-08-19 21:16:41 UTC
Permalink
Post by Timon Gehr
Post by H. S. Teoh
Well, OK, whatever they're supposed to be called.
Compiler-tuples, or
expression tuples, or whatever. See, part of the problem is
that they
just don't have any good name that correctly conveys what they are.
They are simply template argument lists.
(http://wiki.dlang.org/The_D_Programming_Language/Seq)
Nice short FAQ for one of the more confusing parts of D. The
name "template argument list" clears things up quite a bit
actually (but is too long for a type name). Is it your idea to
use Seq instead of TypeTuple?
Brad Anderson
2013-08-19 21:27:53 UTC
Permalink
Post by Brad Anderson
Post by Timon Gehr
Post by H. S. Teoh
Well, OK, whatever they're supposed to be called.
Compiler-tuples, or
expression tuples, or whatever. See, part of the problem is
that they
just don't have any good name that correctly conveys what
they are.
They are simply template argument lists.
(http://wiki.dlang.org/The_D_Programming_Language/Seq)
Nice short FAQ for one of the more confusing parts of D. The
name "template argument list" clears things up quite a bit
actually (but is too long for a type name). Is it your idea to
use Seq instead of TypeTuple?
Pretty heavy on the snark though :P
Meta
2013-08-19 17:57:43 UTC
Permalink
Post by H. S. Teoh
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"?
Dicebot
2013-08-19 18:10:38 UTC
Permalink
Post by Meta
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.
H. S. Teoh
2013-08-19 18:39:32 UTC
Permalink
As far as I can tell, when everyone talks about tuple syntax, they
are talking about run-time tuples. That's definitely what I'm
talking about whenever I mention tuple syntax, as I don't think it
would be a good thing to use it for both run-time and compile-time
tuples (and I don't really consider the latter tuples).
No. I speak exclusively about native syntax for compile-time tuples
and stand by the point that run-time tuples are mostly fine as-is
and should not be touched at all.
Case in point. :)

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

I agree that we shouldn't be making built-in syntax for a library type.
If anything, any dedicated syntax should be reserved for alias tuples
(aka std.typetuple.Typetuple). Or, at the very least, rename TypeTuple
to AliasTuple.

Conflating these two concepts has led to endless confusion, which is why
I insisted on addressing this issue before we even begin to talk about
syntax. Otherwise we're going nowhere.


T
--
Let's not fight disease by killing the patient. -- Sean 'Shaleh' Perry
Meta
2013-08-19 23:48:35 UTC
Permalink
Post by H. S. Teoh
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?
Post by H. S. Teoh
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.
Post by H. S. Teoh
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
Meta
2013-08-19 23:55:20 UTC
Permalink
...
An addendum:

void main()
{
//Prints 1
writeln(func(TypeTuple!(1, 2)));
}

int func(int i, int j)
{
return i;
}

This is bad and should never be allowed with some hypothetical
tuple literal syntax. The desired behaviour is:

void main()
{
//Error: func is not callable using argument types (#(int,
int))
writeln(func(#(1, 2));
}

*Unless* you use .expand/[] (pick your poison):

void main()
{
writeln(func(#(1, 2).expand)); //Or #(1, 2)[]
}
Dicebot
2013-08-20 00:13:23 UTC
Permalink
Post by Dicebot
...
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
void main()
{
//Error: func is not callable using argument types (#(int,
int))
writeln(func(#(1, 2));
}
void main()
{
writeln(func(#(1, 2).expand)); //Or #(1, 2)[]
}
No. No. Absolutely no. What you want is simply syntax sugar for
std.typecons.Tuple - it is not worth any language change,
contrary to semantical issues with built-in tuples.
Auto-expansion and integration with function/template parameter
lists is what makes D built-in tuple that useful and it should
stay so with hypothetical tuple literals.
Meta
2013-08-20 00:28:46 UTC
Permalink
Post by Dicebot
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.
Dicebot
2013-08-20 00:36:52 UTC
Permalink
Post by Meta
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.
Andrei Alexandrescu
2013-08-20 00:03:48 UTC
Permalink
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
Meta
2013-08-20 00:14:28 UTC
Permalink
On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
Post by Meta
I don't necessarily want built-in syntax for a library type,
but making
tuples first-class would be nice. I mean, it's a bummer that
they can't
be returned from functions. That should definitely be changed.
return tuple(1, "a");
That's not a TypeTuple, though, it's a built-in tuple.

void main()
{
writeln(func());
}

TypeTuple!(int, string) func()
{
return tuple(1, "a"); //Error
}

Nor does it work the other way around:

Tuple!(int, string) func()
{
return TypeTuple!(1, "a"); //Error
}

How would this work for some hypothetical built-in syntax?

#(int, string) func()
{
return tuple(1, "a"); //Error?
}
Meta
2013-08-20 00:15:21 UTC
Permalink
Post by Meta
That's not a TypeTuple, though, it's a built-in tuple.
s/built-in tuple/library tuple
Andrei Alexandrescu
2013-08-20 00:18:39 UTC
Permalink
Post by Meta
Post by Andrei Alexandrescu
I don't necessarily want built-in syntax for a library type, but making
tuples first-class would be nice. I mean, it's a bummer that they can't
be returned from functions. That should definitely be changed.
return tuple(1, "a");
That's not a TypeTuple, though, it's a built-in tuple.
void main()
{
writeln(func());
}
TypeTuple!(int, string) func()
{
return tuple(1, "a"); //Error
}
Tuple!(int, string) func()
{
return TypeTuple!(1, "a"); //Error
}
How would this work for some hypothetical built-in syntax?
#(int, string) func()
{
return tuple(1, "a"); //Error?
}
Why would it be necessary to return an object of type TypeTuple (i.e.
template tuple)? It has no state.

Andrei
Timon Gehr
2013-08-20 06:39:04 UTC
Permalink
Post by Andrei Alexandrescu
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.
Post by Andrei Alexandrescu
It has no state.
It may alias variables that do.
Manu
2013-08-20 14:46:08 UTC
Permalink
Post by Timon Gehr
Post by Andrei Alexandrescu
Why would it be necessary to return an object of type TypeTuple (i.e.
template tuple)?
- ABI
Multiple return values could use a more efficient ABI than struct
instances because they do not have an address.
*** this

I've been banging this drum for years!

However this discussion resolves, I just hope it allows for convenient and
efficient MRV's.
Obviously it should be syntactically convenient, and assignment of MRV to
callee locals should be convenient too.
But more importantly, I'd like to see ALL the argument registers re-used to
return multiple values, rather than just the first one. They're just
sitting there begging to be used, and in many cases, would lead to some
great efficiency improvements across function calls/returns. Especially on
non-x86 architectures.

Perhaps one of the most common causes for (otherwise unnecessary) inlining
of functions is because of the terrible legacy ABI for returning multiple
values from functions.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130821/aaa2f2e7/attachment.html>
Andrei Alexandrescu
2013-08-20 18:51:23 UTC
Permalink
Post by Timon Gehr
Post by Andrei Alexandrescu
Why would it be necessary to return an object of type TypeTuple (i.e.
template tuple)?
auto seq(T...)(T arg){ return arg; }
auto fold(alias a,S,R)(S start, R range){ ... }
seq(0,[1,2,3]).fold!((a,b)=>a+b);
But this is again a value tuple not a template tuple, no?

Andrei
Timon Gehr
2013-08-20 20:04:28 UTC
Permalink
Post by Andrei Alexandrescu
Post by Timon Gehr
Post by Andrei Alexandrescu
Why would it be necessary to return an object of type TypeTuple (i.e.
template tuple)?
auto seq(T...)(T arg){ return arg; }
auto fold(alias a,S,R)(S start, R range){ ... }
seq(0,[1,2,3]).fold!((a,b)=>a+b);
But this is again a value tuple not a template tuple, no?
Andrei
In my understanding the former is a special case of the latter. Since
you invented those terms, I might be mistaken. How do you distinguish
between them?
H. S. Teoh
2013-08-20 00:27:46 UTC
Permalink
Post by Meta
On Tuesday, 20 August 2013 at 00:03:48 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
Post by Meta
I don't necessarily want built-in syntax for a library type, but
making tuples first-class would be nice. I mean, it's a bummer that
they can't be returned from functions. That should definitely be
changed.
return tuple(1, "a");
That's not a TypeTuple, though, it's a built-in tuple.
Sounds like you're confused about what built-in tuples are (and you
wouldn't be the first -- they're rather confusing things). They are
perhaps best thought of as template argument lists. As such, they have
no runtime value or, as Andrej puts it, they have no ABI. So it doesn't
make sense to return them from a function. What should be the meaning,
for example, of:

template fun(A...) {
auto fun() {
return A;
}
}

?

The answer is, this code makes no sense, because you can't return
template arguments from a function. It makes as much sense as returning
a function's signature from a function. You can't do that, because a
function's signature isn't a runtime value that can be returned.

Similarly:

return TypeTuple!(int, 1);

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


T
--
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
Meta
2013-08-20 00:40:00 UTC
Permalink
Post by H. S. Teoh
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.
Post by H. S. Teoh
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.
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.
H. S. Teoh
2013-08-20 01:05:00 UTC
Permalink
Post by Meta
Post by H. S. Teoh
Sounds like you're confused about what built-in tuples are (and
you wouldn't be the first -- they're rather confusing things).
I know the difference between std.typecons.Tuple and the built-in
tuples. What I'm confused about is I thought that the main objective
of the tuple literal syntax (destructuring/pattern matching aside)
was a means to have first-class tuples. That is, tuples that have
their own literal syntax, have a list of valid operations that can
be done on them, can be passed to functions, and can be returned
from functions.
Actually, reading through DIP32 again, it sounds like Kenji is proposing
the *same* syntax for both built-in tuples and std.typecons.Tuple. In
the code example under "Generic type/expression tuple syntax", he refers
to them respectively as "tuple type" and "tuple value". Mixing is also
allowed (e.g., in the "alias Fields" line).

So it sounds like this is similar to what bearophile was suggesting --
the unification of built-in tuples and Phobos Tuples. I suppose the
intention is that if a built-in tuple like (1, "a", 1.0) is used as a
value, it would be automatically translated into a runtime tuple value.
I'm not sure if the reverse is possible, though, since if the tuple
contains some runtime values, then it's not possible to translate it
back into a built-in tuple.

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

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

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

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

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

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

alias tup = {1; x};

?


T
--
A mathematician is a device for turning coffee into theorems. -- P. Erdos
Kenji Hara
2013-08-20 03:17:36 UTC
Permalink
2013/8/20 H. S. Teoh <hsteoh at quickfur.ath.cx>
Post by H. S. Teoh
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130820/08396c99/attachment.html>
Kenji Hara
2013-08-20 03:33:38 UTC
Permalink
Sorry I cannot reply to each thread comments quickly, so I discharge my
opinions at once.

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

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

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

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

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

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

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

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

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

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

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

----
My opinions agains various syntax proposals:

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

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

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

Kenji Hara
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130820/e594044b/attachment-0001.html>
John Colvin
2013-08-20 10:50:05 UTC
Permalink
Post by Kenji Hara
----
#(1, "str")
--> The character '#' is already used for the start of "Special
Token
Sequences"
http://dlang.org/lex.html#Special Token Sequence
It is recognized in lexing phase, so adding semantic meaning to
the '#'
character would be a contradict of D's principle.
Quote from http://dlang.org/lex.html
"The lexical analysis is independent of the syntax parsing and
the semantic
analysis."
Kenji Hara
There are various other characters that could be substituted for #
e.g.
&(1, "string")

http://forum.dlang.org/post/cokiixatvjmngggpblma at forum.dlang.org
Jacob Carlborg
2013-08-20 11:01:22 UTC
Permalink
Post by Kenji Hara
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.
Post by Kenji Hara
#(1, "str")
--> The character '#' is already used for the start of "Special Token
Sequences"
http://dlang.org/lex.html#Special Token Sequence
It is recognized in lexing phase, so adding semantic meaning to the '#'
character would be a contradict of D's principle.
Quote from http://dlang.org/lex.html
"The lexical analysis is independent of the syntax parsing and the
semantic analysis."
It depends on how it's lexed. If the compiler lexes "#line" as a single
token I cannot see how it will be a problem. Then the "#" token would
mean tuple literal.
--
/Jacob Carlborg
Dicebot
2013-08-20 11:10:32 UTC
Permalink
Post by Kenji Hara
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?
Meta
2013-08-20 13:17:43 UTC
Permalink
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.
Dicebot
2013-08-20 13:57:47 UTC
Permalink
Post by Meta
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.
Post by Meta
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.
Meta
2013-08-20 14:22:23 UTC
Permalink
Post by Dicebot
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.
Post by Dicebot
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.
Andrei Alexandrescu
2013-08-20 20:16:48 UTC
Permalink
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
Dicebot
2013-08-20 20:24:42 UTC
Permalink
On Tuesday, 20 August 2013 at 20:16:54 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
Post by Dicebot
I am proposing something more radical. Deprecate _both_
TypeTuple and
Tuple. Clearly define the difference between built-in type
tuple and
expression tuple (latter being instance of former).
But that can't be the case.
Can you elaborate on this? I can only judge by observable
behavior which clearly says that typeof(TypeTuple!(2, 3)) is
TypeTuple!(int, int). And when you use variadic template argument
syntax in functions, you use "T..." (which is a built-in type
tuple) to declare arguments (which is built-in expression tuple).
There are probably some inconsistencies in implementation but
this is the observable behavior that can be declared official.
Post by Andrei Alexandrescu
Post by Dicebot
Preserve
auto-expansion.
That would be problematic to say the least. (There have been a
few discussions in this group; I've come to think auto
expansion is fail.)
:O it is awesome! Stuff like foo(myStructInstance.tupleof) is
very powerful tool for generic interfaces. Do you remember any
keywords to look for to find those discussions? Ones I remember
were mostly about auto-expansion _not_ happening in some
reasonable places.

Kenji Hara
2013-08-20 15:43:26 UTC
Permalink
2013/8/20 Dicebot <public at dicebot.lv>
What we have here are two completely different _built-in_ tuple types. "T"
is pure template arguments list and is pretty much equal TypeTuple!(int,
int). But what is "args"? It uses the very same built-in tuple syntax but
it is much closer to std.typecons.Tuple in its behavior (actually, latter
is implemented in terms of it as I was pointed out) - it is an entity that
provides abstraction of top of group of run-time values. It does not have
any binary structure on its own (built on top of existing values) but
observable semantic are very "run-time'ish".
"args" is a built-in tuple of two function parameter variables. In binary
level, args[0] and args[1] could be bounded to completely individual
storage. (Even if args[1] is on stack, args[0] may be on register)
On the other hand, std.typecons.Tuple is a struct. Its second field has the
memory address which follows of the first field.

What bothers me is the question "can we clean this up and bring those two
worlds together, even at cost of minor breakage?". I am not speaking about
literals here or unpacking or whatever. I am speaking about re-defining
semantics so that struct-based Tuple and built-in syntax sugar in form of
run-time expression tuple both get merged into one built-in construct which
can be used in wider variety of places.
At least right now I can't find any technical objections why expression
tuple can't use std.typecons.Tuple ABI when returned from function but
still be automatically expanded when passed into functions. Kenji, what is
your your opinion about complexity to implement something like that in DMD?
Automatically packing/unpacking would need hidden runtime cost.

Kenji Hara
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130821/064cbe8a/attachment.html>
Dicebot
2013-08-20 15:54:36 UTC
Permalink
Post by Kenji Hara
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.
Post by Kenji Hara
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.
Andrei Alexandrescu
2013-08-20 20:20:45 UTC
Permalink
2013/8/20 Dicebot <public at dicebot.lv <mailto:public at 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
bearophile
2013-08-20 14:57:36 UTC
Permalink
Post by 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
Post by Kenji Hara
s = "red blue"
(a, b) = s.split()
a
'red'
Post by Kenji Hara
b
'blue'


Bye,
bearophile
bearophile
2013-08-20 15:18:45 UTC
Permalink
Post by bearophile
s = "red blue"
(a, b) = s.split()
a
'red'
b
'blue'
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
Dicebot
2013-08-20 15:30:20 UTC
Permalink
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.
bearophile
2013-08-20 16:10:09 UTC
Permalink
Post by 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
Timon Gehr
2013-08-20 19:57:12 UTC
Permalink
Post by bearophile
Post by bearophile
s = "red blue"
(a, b) = s.split()
a
'red'
b
'blue'
Prelude> let s = "red blue"
Prelude> let [a, b] = words s
Prelude> a
"red"
Prelude> b
"blue"
Bye,
bearophile
Any language with algebraic data types supports this.
Timon Gehr
2013-08-20 19:59:15 UTC
Permalink
Post by Timon Gehr
Post by bearophile
Post by bearophile
s = "red blue"
(a, b) = s.split()
a
'red'
b
'blue'
Prelude> let s = "red blue"
Prelude> let [a, b] = words s
Prelude> a
"red"
Prelude> b
"blue"
Bye,
bearophile
Any language with algebraic data types supports this.
(Some will only allow it if you can prove the match is total within
them, of course.)
Kenji Hara
2013-08-20 16:03:42 UTC
Permalink
2013/8/20 bearophile <bearophileHUGS at lycos.com>
Post by Kenji Hara
So, std.typecons.Tuple _is not special_. You can define another Tuple
Post by Kenji Hara
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
s = "red blue"
Post by Kenji Hara
Post by bearophile
(a, b) = s.split()
a
'red'
b
Post by bearophile
'blue'
My position to such a feature is constant. We should not conflate tuple
unpacking and array unpacking.

But, extending unpacking syntax mentioned in DIP32 might help it.

// Just an idea: extending DIP32 unpacking syntax
import std.typecons : tuple;
auto tup = tuple(1, tuple(2,3), [4,5]);
{ auto a, {b, c}, [d, e] } = tup;
//{ auto a, [b, c], {d, e} } = tup; // cause compile-time error
assert(a == 1);
assert(b == 2 && c == 3);
assert(d == 4 && e == 5);

However, array unpacking would require *hidden* runtime boundary check.
In above example code,

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

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

Kenji Hara
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130821/5b536545/attachment-0001.html>
bearophile
2013-08-20 16:20:54 UTC
Permalink
Post by 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.
Post by Kenji Hara
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
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
Dicebot
2013-08-20 01:32:14 UTC
Permalink
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.
Meta
2013-08-20 02:50:49 UTC
Permalink
Post by H. S. Teoh
Actually, reading through DIP32 again, it sounds like Kenji is
proposing
the *same* syntax for both built-in tuples and
std.typecons.Tuple. In
the code example under "Generic type/expression tuple syntax",
he refers
to them respectively as "tuple type" and "tuple value". Mixing
is also
allowed (e.g., in the "alias Fields" line).
Maybe mixing should be disallowed, then, unless your tuple was
constructed from a variadic template argument list.

auto tup = #(1, int); //ERROR

template TMP(T...)
{

auto tup = T;
}
Post by H. S. Teoh
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
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
int x=123;
auto tup = {1; x};
x++;
writeln(tup);
What should be the output? Should the output change if the
second line
alias tup = {1; x};
?
T
Meta
2013-08-20 03:12:43 UTC
Permalink
Aggh, misposted. Let's try that again.
Post by H. S. Teoh
Actually, reading through DIP32 again, it sounds like Kenji is
proposing
the *same* syntax for both built-in tuples and
std.typecons.Tuple. In
the code example under "Generic type/expression tuple syntax",
he refers
to them respectively as "tuple type" and "tuple value". Mixing
is also
allowed (e.g., in the "alias Fields" line).
Maybe mixing should be disallowed, then, unless your tuple was
constructed from a variadic template argument list.

//Error. Tuple containing types
//at runtime doesn't make any sense
auto tup = #(1, int);
//Error
auto tup = #(int, string);
//Ok
auto tup = #(1, "a", true);

T[0] Test(T...)(T ts)
{
//Okay, each element of T can
//be statically inspected to ensure
//that you don't do something weird
auto tup = T;
//Also okay
alias tup = T;
//Error
auto tup = #(int, string, bool);
//Ok
alias tup = #(int, string, bool);
}
Post by H. S. Teoh
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
int x=123;
auto tup = {1; x};
x++;
writeln(tup);
What should be the output?
I'd say that x++ would not modify the x within the tuple. It's
the same as:

int x = 123;
auto y = x;
x++;
writeln(y);

Y is not changed, of course. However, if the tuple contains a
reference type, such as a slice, then it would be modified.

int[] x = [123];
auto tup = #(1, x);
x[]++;
//Prints #(1, [124])
writeln(tupe);
Post by H. S. Teoh
Should the output change if the second line
alias tup = {1; x};
?
I don't think this should be possible. It would be the same as
doing:

alias two = 3; //Error

Unless the tuple contained only types. Then it would be possible.

alias intAndStr = #(int, string); //Ok

The semantics are fairly easy when a tuple contains only values
and only types. The hard part is when it contains both values AND
types, so that should be severely limited, maybe only within
variadic templates.

I can't remember where this was mentioned... I think it was in
one of the other tuple threads I linked, and I think you brought
it up, Teo.

auto tup = #(1, "a");
alias tupType = typeof(tup);

While tup is a value, its type is #(int, string). In other words,
the type of a tuple value is a TypeTuple (alias tuple, whatever).
Which means the type of a tuple is a tuple itself, which is
pretty nifty.
bearophile
2013-08-20 01:38:51 UTC
Permalink
Post by Andrei Alexandrescu
return tuple(1, "a");
About the same syntax should work for both packing and unpacking
tuples.

Bye,
bearophile
bearophile
2013-08-19 18:19:10 UTC
Permalink
Post by Wyatt
The octothorpe _is_ much better than the t simply in terms of
readability, though, even more than q{} or t{}, I have concerns
about its ability to be found with an ordinary search engine by
an ordinary user. Have you tried looking for documentation on
weird operators with a search engine lately? They don't
exactly take to it well. :/ (cf. Perl's <=>)
I think none of the suggested tuple syntaxes are well searchable
on Google, but the "tuple()" syntax.

But in the Haskell world the Hoogle direct&reverse search engine
supports symbols too (but it's mostly used to search for
functions given their signature, I think so far this is something
not present in the D world):

http://www.haskell.org/hoogle/?hoogle=%3D%3E
Post by Wyatt
I even don't like how the unicode version of that one looks;
It was just an idea, to show what I meant by representing the
bananas with Unicode glyphs. The actual choice of glyphs is not
an urgent choice :-) The idea comes from the now dead Fortress
language.
Post by Wyatt
I feel weird admitting this, but if we can't use some manner of
bare brace, I think I'd rather have tup(), tup[], tup{} (or
even tuple() et al) as a prefix over any single character.
At the moment I prefer #() syntax, with ? for single wildcards.
It's better than tup{} or t{} because the # symbol pops out more
visually. tuple() syntax is long, but it's readable, and perhaps
partially backwards compatible.
Post by Wyatt
Can't make it a single underscore? Question mark works best
then, IMO. It isn't as burdened with meanings elsewhere (sure
there's ternary and possibly-match in regex, but...have I
forgotten something?)
The ? of regexes is inside strings, so I think it causes no
problems. And I think it doesn't clash with the ternary operator
because before the ? wildcard you put a comma, a semicolon or a
#(.
Post by Wyatt
Post by Meta
Assuming the "..." syntax for unpacking, it would be useful to
name the captured tail. For example, you could unpack #(1, 3,
#(4, 6)) into #(a, b, x...), where a = 1, b = 3, x = #(4, 6).
Similarly, #(head, rest...) results in head = 1, rest = #(2,
#(4, 6)). I think this would be very useful.
In Haskell there is also a way to give a name to the whole tuple
and names to its parts:

Prelude> let t1 = (10, 20)
Prelude> let a@(b, c) = t1
Prelude> a
(10,20)
Prelude> b
10
Prelude> c
20

-------------------------
Post by Wyatt
Bearophile has mentioned a couple times that we could use the
tuple syntax for both, and bring about a unification of these
two tuple types. I don't like this, as they're both very
different entities, and don't really have any relation to
each-other whatsoever.
Mine was an idea, but if it turns out to be a bad idea, then
let's ignore it.

Bye,
bearophile
Dicebot
2013-08-19 18:37:30 UTC
Permalink
Post by bearophile
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;
}
Wyatt
2013-08-19 18:45:28 UTC
Permalink
Post by bearophile
The ? of regexes is inside strings, so I think it causes no
problems. And I think it doesn't clash with the ternary
operator because before the ? wildcard you put a comma, a
semicolon or a #(.
I 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
Meta
2013-08-19 18:43:35 UTC
Permalink
Post by Wyatt
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.
Post by 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'm not sure how much of a problem that would be. There's only
one other syntactic form that uses # in D, but you're right, it
may cause some difficulty trying to search "d programming #".
Post by Wyatt
Addressing the other suggestion I saw that cropped up, I
personally find the two-character "bananas" to be impressively
ugly. I considered suggesting some permutation on that same
idea, but after toying with a few examples I find it ends up
looking awful and I think it's honestly annoying to type them
in any form. I even don't like how the unicode version of that
one looks; for doubling up, I think ? ? or ? ? or are easier on
the eyes.
My browser can't even display the second set of characters. D
seems to have generally shied away from using any unicode
operators (for a good reason. Who the hell has ? on their
keyboard?)
Post by Wyatt
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.
Post by Wyatt
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.
Post by Wyatt
#(a, ...) looks like to me like it would make a 2-tuple
containing a and a tuple of "everything else", because of the
ellipsis' use in templated code. I think this is a little
unclear, so instead I'd prefer #(a, ? ...) (or whatever ends up
used for the discard character) to make it explicit.
To be clear, what I have in mind is that this would be "a, plus
(none/one?) or more things that can either be elements or nested
tuples". Then, in a construction such as #(head, rest...), rest
would be exactly as you describe: a tuple consisting of
everything after head. The semantics could get tricky, maybe this
needs more thought.
Post by Wyatt
As a bonus, explicit discard means a simple comma omission is
less likely to completely change the meaning of the statement.
#(a, b, ...) //bind the first two elements, discard the rest.
#(a, b ...) //bind the first element to a and everything
else to b
#(a, b, ? ...) //same as the first
#(a, b ? ...) //syntax error
#(a, ?, ...)
...but that seems like it would be less common just based on
how people conventionally order their data structures.
That's true. Something to think about. Maybe combine the question
mark and ellipsis like so:

#(a, b, ?..)
Post by Wyatt
Thought: Is there sufficient worth in having different tokens
for discarding a single element vs. a range? e.g.
#(a, ?, c, * ...) //bind first and third elements; discard the
rest
// I'm not attached to the asterisk there.
Not sure. I need to think about it.
Post by Wyatt
Post by Meta
- Concatenating tuples with ~. This is nice to have, but not
particularly important.
auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right?
auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b ==
#(1,2,3,4,5)?
I think it should work the same as with arrays. So:

auto a = #(1, 2) ~ 3; //Error: 3 is not a tuple
auto a = #(1, 2) ~ #(3); //Result: #(1, 2, 3), just like an array

auto b = a ~ #(4, 5); //Result: #(1, 2, 3, 4, 5). Again, like
arrays.

I think keeping the same semantics as arrays would be the best
way to do it. I think it nicely follows the principle of least
astonishment. If you wanted to explicitly append a tuple and have
it nested, you'd need to do:

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

Which is messy, but at least it's explicit about what is going on.
Post by Wyatt
Great! After this, let's fix properties. ;)
Oh boy, no need to start *another* flame war.
bearophile
2013-08-19 19:54:42 UTC
Permalink
Post by Meta
It *could* be an underscore; the only thing is that the
underscore is a valid variable name, so the above expression
would actually be binding two variables, which might surprise
someone who was expecting otherwise. I don't really care all
that much, but it's something to think about.
You can't define a variable more than once in a scope, so this
can't be valid:

void main() {
auto t1 = #(5, "hello", 1.5);
auto (_, _, x) = t1;
auto (_, gr, _) = t1;
}


While ? defines nothing, so this is OK:

void main() {
auto t1 = #(5, "hello", 1.5);
auto (?, ?, x) = t1;
auto (?, gr, ?) = t1;
}

Bye,
bearophile
Meta
2013-08-19 19:57:37 UTC
Permalink
...
That too.
bearophile
2013-08-19 19:57:41 UTC
Permalink
Post by bearophile
void main() {
auto t1 = #(5, "hello", 1.5);
auto (_, _, x) = t1;
auto (_, gr, _) = t1;
}
I need to get used to the proposed syntax, sorry:

void main() {
auto t1 = #(5, "hello", 1.5);
auto #(_, _, x) = t1;
auto #(_, gr, _) = t1;
}

Bye,
bearophile
Andrei Alexandrescu
2013-08-19 20:45:33 UTC
Permalink
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
void main() {
auto t1 = #(5, "hello", 1.5);
auto (_, _, x) = t1;
auto (_, gr, _) = t1;
}
void main() {
auto t1 = #(5, "hello", 1.5);
auto (?, ?, x) = t1;
auto (?, gr, ?) = t1;
}
Bye,
bearophile
It's stuff like this that's just useless and gives a bad direction to
the whole discussion. There's hardly anything wrong with auto x = t1[2]
or auto gr = t1[1], but once the bikeshed is up for painting, the
rainbow won't suffice.


Andrei
Meta
2013-08-19 20:57:17 UTC
Permalink
On Monday, 19 August 2013 at 20:46:02 UTC, Andrei Alexandrescu
Post by 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 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?
bearophile
2013-08-19 20:59:24 UTC
Permalink
Post by 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
Andrei Alexandrescu
2013-08-19 21:03:50 UTC
Permalink
Post by 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 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
Dicebot
2013-08-19 21:16:48 UTC
Permalink
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
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.
Meta
2013-08-19 22:04:06 UTC
Permalink
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
I'm saying that there's a mix of useful stuff and just
auto (a, b, c) =
functionReturningTupleOrStaticArrayWith3Elements();
b) syntactic support for ignoring certain members in a
destructuring - is that really needed?
auto (a, ?, c) =
functionReturningTupleOrStaticArrayWith3Elements();
In fairness, it is very common in other languages with pattern
matching/destructuring. Off the top of my head I can think of
Haskell, ML, Racket, Javascript (destructuring only) and Rust.
This syntax is more important when pattern matching, but also
seems to be almost universally used in destructuring. From the
DIP:

switch (tup) {
case {1, 2}:
case {$, 2}: //Don't care what the first value is, only match
on second
case {1, x}:
default:
}

You could just replace {$, 2} with {x, 2} and never use x, but
this creates the problem that Bearophile mentioned.

auto t1 = #(5, "hello", 1.5); //Fine
auto #(_, _, x) = t1; //Dammit, can't use _ twice as it's a
variable

If you replace _ with throwaway variable names, it becomes much
less clear (IMO) exactly what is going on. Any programmer reading
your code would have to examine the function to see if the
bindings introduced are ever used, or if they are just throwaways.

Maybe it's unproductive to argue over the colour of the bike
shed, but we need to know whether it's worth adding windows.
captaindet
2013-08-19 23:17:18 UTC
Permalink
Post by Dicebot
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
b) syntactic support for ignoring certain members in a
destructuring - is that really needed?
auto (a, ?, c) =
functionReturningTupleOrStaticArrayWith3Elements();
In fairness, it is very common in other languages with pattern
matching/destructuring. Off the top of my head I can think of
Haskell, ML, Racket, Javascript (destructuring only) and Rust.
same in matlab. once destruction->auto assignment is available, (future) library functions will make heavy use of it, e.g. statistics functions returning lots of parameters/characteristics for a dataset. more often than not one is only interested in a few.

/det
deadalnix
2013-08-20 05:29:40 UTC
Permalink
On Monday, 19 August 2013 at 21:03:50 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
I'm saying that there's a mix of useful stuff and just
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.
Jonathan M Davis
2013-08-20 04:41:24 UTC
Permalink
Post by Andrei Alexandrescu
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
H. S. Teoh
2013-08-20 14:26:00 UTC
Permalink
Post by Jonathan M Davis
Post by Andrei Alexandrescu
but once the bikeshed is up for painting, the
rainbow won't suffice.
LOL! I'm going to have to remember that one.
[...]

That's a classic. I'm st^H^H borrowing that for my random signatures
file. :)


T
--
There's light at the end of the tunnel. It's the oncoming train.
Meta
2013-08-19 23:18:08 UTC
Permalink
Post by Meta
Post by Wyatt
auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right?
auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b ==
#(1,2,3,4,5)?
auto a = #(1, 2) ~ 3; //Error: 3 is not a tuple
auto a = #(1, 2) ~ #(3); //Result: #(1, 2, 3), just like an
array
auto b = a ~ #(4, 5); //Result: #(1, 2, 3, 4, 5). Again, like
arrays.
I was being dumb, [1, 2] ~ 3 is of course valid for arrays, so
that should work for tuples as well. Furthermore, #(1, 2) ~ "a"
should be valid, and will result in #(1, 2, "a").
Post by Meta
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
auto b = a ~ #(#(4, 5));
Which is messy, but at least it's explicit about what is going
on.
The tricky part of this that I forgot to mention is that you
can't do this with arrays, so we're in unknown territory, but I
think this is sensible. Again, it's quite ugly, but oh well.
Mr. Anonymous
2013-08-20 09:02:28 UTC
Permalink
Post by Meta
Post by Wyatt
Can't make it a single underscore? Question mark works best
then, IMO. It isn't as burdened with meanings elsewhere (sure
there's ternary and possibly-match in regex, but...have I
forgotten something?)
It *could* be an underscore; the only thing is that the
underscore is a valid variable name, so the above expression
would actually be binding two variables, which might surprise
someone who was expecting otherwise. I don't really care all
that much, but it's something to think about.
Why not just leave an empty space, like php does:

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

http://php.net/manual/en/function.list.php
Wyatt
2013-08-20 12:47:27 UTC
Permalink
Post by Mr. Anonymous
$info = array('coffee', 'brown', 'caffeine');
// let's skip to only the third one
list( , , $power) = $info;
echo "I need $power!\n";
Bad idea. It's a visual thing-- quick! How wide is this tuple!?:
#(,front,,,,var,)

How long did it take you to be SURE that it's a seven-tuple? You
probably aren't even equipped to measure that so don't worry
about answering, but I'm guessing you start to appreciate why
it's a fairly inhumane solution (how drearily typical for PHP).

Ah, but what if it was supposed to be #(,front,,,,,var,)? Does
that change your result, now that you're taking the sixth element
rather than the seventh? All you did was forget a comma! By
contrast:
#(?,front,?,?,?,var,?,?) //at least gives us a better chance of
parsing it correctly.

My point here is we are human and we are fallible. The sooner we
acknowledge and internalise that, the better equipped we are to
make systems that don't suck for humans to use.

In that sense, I don't even really like this format because it's
still not especially resilient. Walter's talk about design that
eliminates patterns of human error resonated with me quite
strongly, you see. But in terms of language consistency it's not
much different from array literals, so I could accept it as a
compromise.

-Wyatt
eles
2013-08-20 10:38:29 UTC
Permalink
Post by Meta
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
- (a, b) is the prettiest syntax, and it also completely
infeasible
- {a, b} is not as pretty, but it's not that bad of an
alternative (though it may still have issues as well)
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
What about:

!!(a, b)

? Yes, is long, but is type-able quite fast.

Alternative would be:

??(a, b)

.
Mr. Anonymous
2013-08-20 10:44:58 UTC
Permalink
Post by eles
Post by Meta
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
- (a, b) is the prettiest syntax, and it also completely
infeasible
- {a, b} is not as pretty, but it's not that bad of an
alternative (though it may still have issues as well)
- #(a, b) is unambiguous and would probably be the easiest
option. I don't think it looks too bad, but some people might
find it ugly and noisy
!!(a, b)
? Yes, is long, but is type-able quite fast.
??(a, b)
.
It's not only long, but also ugly (IMO of course).
Timon Gehr
2013-08-20 13:14:46 UTC
Permalink
Post by eles
!!(a, b)
This already has a meaning.
eles
2013-08-20 15:57:47 UTC
Permalink
Post by Timon Gehr
Post by eles
!!(a, b)
This already has a meaning.
True :( I dunno why I took it for some kind of binary operator
instead of a unary one.

I was too quick on my keyboard.
Andrei Alexandrescu
2013-08-20 18:53:50 UTC
Permalink
Post by eles
A good, comprehensive design has the potential to make tuples easy to
use and understand, and hopefully clear up the unpleasant situation we
- (a, b) is the prettiest syntax, and it also completely infeasible
- {a, b} is not as pretty, but it's not that bad of an alternative
(though it may still have issues as well)
- #(a, b) is unambiguous and would probably be the easiest option. I
don't think it looks too bad, but some people might find it ugly and
noisy
!!(a, b)
? Yes, is long, but is type-able quite fast.
??(a, b)
.
Somebody shoot me.

Andrei
H. S. Teoh
2013-08-20 20:06:27 UTC
Permalink
Post by Andrei Alexandrescu
Post by eles
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
- (a, b) is the prettiest syntax, and it also completely infeasible
- {a, b} is not as pretty, but it's not that bad of an alternative
(though it may still have issues as well)
- #(a, b) is unambiguous and would probably be the easiest option. I
don't think it looks too bad, but some people might find it ugly and
noisy
!!(a, b)
? Yes, is long, but is type-able quite fast.
??(a, b)
.
Somebody shoot me.
[...]

BANG!


T
--
They say that "guns don't kill people, people kill people." Well I think the gun helps. If you just stood there and yelled BANG, I don't think you'd kill too many people. -- Eddie Izzard, Dressed to Kill
Jonathan M Davis
2013-08-20 20:10:29 UTC
Permalink
Post by Andrei Alexandrescu
Somebody shoot me.
[...]
BANG!
Don't kill him. He hasn't finished the allocators yet! ;)

- Jonathan M Davis
H. S. Teoh
2013-08-20 20:17:03 UTC
Permalink
Post by Jonathan M Davis
Post by Andrei Alexandrescu
Somebody shoot me.
[...]
BANG!
Don't kill him. He hasn't finished the allocators yet! ;)
Well, as my signature line said:

They say that "guns don't kill people, people kill people." Well
I think the gun helps. If you just stood there and yelled BANG,
I don't think you'd kill too many people. -- Eddie Izzard,
Dressed to Kill

;-)


T
--
Why can't you just be a nonconformist like everyone else? -- YHL
Continue reading on narkive:
Loading...