On Monday, 19 August 2013 at 16:53:06 UTC, Wyatt wrote:
To be clear, I'm not talking about braces, {}; I'm talking
about parentheses, (). I read over that whole DIP32 thread a
couple times, and didn't see any rationale offered for why the
likely "cleanest" version "can't be used". It wasn't even
brought up (unless I've missed something subtle). In the
second thread, linked in the OP here, they were glossed over
again. Now, I fully believe there's a very good reason that's
been written somewhere, but I _would_ like to know what that
is, preferably documented somewhere less ephemeral and
difficult to search than the newsgroup (such as in DIP32). The
closest I've seen so far is the pull request where Walter and
Andrei expressed that it should be considered further.
I could very well be wrong, but I would bet that one of the
reasons is that (a, b, c) expressions already have well-defined
semantics in D (as well as (2, "a", func()). Example:
void main()
{
import std.stdio;
//Prints "a"
writeln((true, false, "a"));
}
Making this a tuple literal would be a change in semantics, which
I don't think would go over well and would break code. Another
example:
void main()
{
int a, b;
(a, b) = (3, 4);
assert(a == 0 && b == 4);
}
Of course, for the second case, Kenji's proposed syntax used
"auto (a, b) = ...", which would disambiguate it, but it could
confuse people as to whether the first syntax is somehow related
to the second.
The octothorpe _is_ much better than the t simply in terms of
readability, though, even more than q{} or t{}, I have concerns
about its ability to be found with an ordinary search engine by
an ordinary user. Have you tried looking for documentation on
weird operators with a search engine lately? They don't
exactly take to it well. :/ (cf. Perl's <=>)
I'm not sure how much of a problem that would be. There's only
one other syntactic form that uses # in D, but you're right, it
may cause some difficulty trying to search "d programming #".
Addressing the other suggestion I saw that cropped up, I
personally find the two-character "bananas" to be impressively
ugly. I considered suggesting some permutation on that same
idea, but after toying with a few examples I find it ends up
looking awful and I think it's honestly annoying to type them
in any form. I even don't like how the unicode version of that
one looks; for doubling up, I think ⟦ ⟧ or ⟪ ⟫ or are easier on
the eyes.
My browser can't even display the second set of characters. D
seems to have generally shied away from using any unicode
operators (for a good reason. Who the hell has Σ on their
keyboard?)
I feel weird admitting this, but if we can't use some manner of
bare brace, I think I'd rather have tup(), tup[], tup{} (or
even tuple() et al) as a prefix over any single character.
It's not terrible, but it's rather wordy, especially if tuples
begin to be used a lot in code.
Can't make it a single underscore? Question mark works best
then, IMO. It isn't as burdened with meanings elsewhere (sure
there's ternary and possibly-match in regex, but...have I
forgotten something?)
It *could* be an underscore; the only thing is that the
underscore is a valid variable name, so the above expression
would actually be binding two variables, which might surprise
someone who was expecting otherwise. I don't really care all that
much, but it's something to think about.
#(a, ...) looks like to me like it would make a 2-tuple
containing a and a tuple of "everything else", because of the
ellipsis' use in templated code. I think this is a little
unclear, so instead I'd prefer #(a, ? ...) (or whatever ends up
used for the discard character) to make it explicit.
To be clear, what I have in mind is that this would be "a, plus
(none/one?) or more things that can either be elements or nested
tuples". Then, in a construction such as #(head, rest...), rest
would be exactly as you describe: a tuple consisting of
everything after head. The semantics could get tricky, maybe this
needs more thought.
As a bonus, explicit discard means a simple comma omission is
less likely to completely change the meaning of the statement.
Compare:
#(a, b, ...) //bind the first two elements, discard the rest.
#(a, b ...) //bind the first element to a and everything
else to b
#(a, b, ? ...) //same as the first
#(a, b ? ...) //syntax error
Granted, there's this case:
#(a, ?, ...)
...but that seems like it would be less common just based on
how people conventionally order their data structures.
That's true. Something to think about. Maybe combine the question
mark and ellipsis like so:
#(a, b, ?..)
Thought: Is there sufficient worth in having different tokens
for discarding a single element vs. a range? e.g.
#(a, ?, c, * ...) //bind first and third elements; discard the
rest
// I'm not attached to the asterisk there.
// +, #, or @ would also make some amount of sense to me.
Not sure. I need to think about it.
- Concatenating tuples with ~. This is nice to have, but not
particularly important.
What does concatenating a tuple actually do? That is:
auto a = #(1,2) ~ 3; //Result: a == #(1,2,3), right?
auto b = a ~ #(4,5); //Is b == #(1,2,3,#(4,5)) or is b ==
#(1,2,3,4,5)?
I think it should work the same as with arrays. So:
auto a = #(1, 2) ~ 3; //Error: 3 is not a tuple
auto a = #(1, 2) ~ #(3); //Result: #(1, 2, 3), just like an array
auto b = a ~ #(4, 5); //Result: #(1, 2, 3, 4, 5). Again, like
arrays.
I think keeping the same semantics as arrays would be the best
way to do it. I think it nicely follows the principle of least
astonishment. If you wanted to explicitly append a tuple and have
it nested, you'd need to do:
auto b = a ~ #(#(4, 5));
Which is messy, but at least it's explicit about what is going on.
Great! After this, let's fix properties. ;)
Oh boy, no need to start *another* flame war.