On 01/11/2013 10:50 AM, Niko Matsakis wrote:
Hi,
Right now we use no delimiter at all to separate multiple trait bounds
for a single type variable:
fn foo<T: Ord Eq Hash>(...) {...}
Supertraits share the same syntax, so we should consider them together.
If or when impls can implement multiple traits they may also need a
similar syntax.
trait Foo: Ord Eq Hash { }
Originally we thought to use commas, but inserting commas into the
list creates an ambiguity between the comma that separates type
parameters, as illustrated here:
fn foo<T: Ord, Eq, Hash, U: Hash, V>(...) {...}
Marijn and I hashed through all kinds of delimeters and failed to find
one, and hence he settled on spaces. It seemed like a good idea at the
time.
However, over time, I have found that this syntax is very hard for me
to parse, visually speaking. Moreover, Patrick recently observed that
there is an ambiguity when the trait names are multi-component paths:
fn foo<T: Ord ::Eq>(...) {...}
Does this indicate one bound `Ord::Eq` or two bounds `Ord` and `::Eq`?
The current fix for this is to make the tokenizer treat `id::`
differently from `id ::` (note the separating space in the latter
example). The first is 1 token. The second is 2 tokens. Actually, I
think this behavior already existed, and I can't remember why—I think
it had something to do with the flexible treatment of keywords that we
used to have. @brson, do you remember?
No, but it's the ugliest part of the lexer. Let's make it go away.
Anyway, it was proposed on IRC today that we could do something like
this instead:
fn foo<T:Eq>(..) {...} // One bound is the same
fn foo<T:(Ord, Eq, Hash)>(...) {...} // Multiple bounds require
parentheses
As an example, this is why the parens are needed:
fn foo<T:(Ord, Eq, Hash), U>(...) {...}
so you _could_ still allow `foo<T: Ord, Eq, Hash>` since there's no
ambiguity, but that's more complex that necessary.
Here's how it looks like in a trait:
trait Foo:(Ord, Eq, Hash) { }
The parens aren't necessary here for disambiguation. Would we want them
anyway?
With the parens, the colons aren't necessary so you could instead have:
fn foo<T(Eq)>(...) {...}
fn foo<T(Ord, Eq, Hash), U>(...) {...}
I find this visually appealing. It's easier for my eye to read,
particularly if the bounds are complicated.
It does contain many new tokens though.
I know it's a syntax change, and we're trying to avoid those, but I
thought I'd throw it out for a wider audience to ponder, particularly
as it would eliminate a rather surprising whitespace dependency.
One thing to consider is that presumably trait inheritance will
eventually make multi-trait bounds less common. It could even replace
multi-trait bounds entirely, though I don't think that's a great idea.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev