I'm designing a syntax for templates/generics. The C++ family languages use angle brackets for this, but I'm looking at using a sep开发者_如何学JAVAarator character instead. For example, where in Java you might write:
Map<String, Foo> foos = new HashMap<String, Foo>();
I'm aiming for:
.foos = hmap*string*foo
I'm trying to decide what the separator character will be; it can't literally be *, because that's already in use for multiplication (not that I couldn't overload it, but the precedence would be wrong). Looking at the available characters, some options are
.foos = hmap!string!foo
.foos = hmap$string$foo
.foos = hmap?string?foo
.foos = hmap^string^foo
.foos = hmap`string`foo
.foos = hmap|string|foo
.foos = hmap~string~foo
As this is to some extent an aesthetic question, I figured I'd take a poll: which option do you like best? Is there another option that would be preferable? (As usual with questions like this, if your answer has already been posted, please upvote rather than duplicate.)
Also, on a standard US keyboard, ` is unshifted, each of the others requires the shift key. Is there a difference on international keyboards? Are there any keyboard layouts on which any of the above candidates are particularly easy or difficult to type?
(As this is a question without a single right answer, should it be a community wiki?)
I don't think any of these symbols does really make the point clear that you apply a list of type arguments to a generic type.
Why not just some kind of bracket syntax like in most common languages, either
Map<String, Foo>
or
Map[String, Foo]
(or {}
/()
respectively)
Note that - like in OCaml or Haskell - whitespace can also be used quite comprehensively.
foos : int list
or
foos :: Map String Foo
Some wider theory: A simple generic type is a type with kind * -> *
- Therefore it has to be seen as a function from types to types
List<Int>
applies the generic type constructor List<α>
on the concrete type Int
, which yields another concrete type - The specialized list.
I therefore like generic specialization to somehow resemble a function application.
The use of *
can make sense as it tuples types! So Map String*Foo
could actually be a good option if you want to rely on operator syntax, as it distinguishes between type constructor and (tupled) type arguments.
Angle brackets work better for me than your options, as they create a visual separation of the elements between them from other code.
I would try something similar with {}
or ()
, if they are not already used.
I think
.foos = hmap(string, foo)
is a nice syntax: allowing types to be used as "functions" which return new types.
I'm not too keen on any of them, for the reasons other people have mentioned. Brackets are just useful to denote this kind of thing, regardless of whether it is < { [ ( etc. There's 4 to choose from there.
Some specific points on the options you listed:
.foos = hmap!string!foo - could be confused with negation.
.foos = hmap$string$foo
.foos = hmap?string?foo - just doesn't look very definitive, the question mark makes me think you are saying it may be a string
.foos = hmap^string^foo
.foos = hmap`string`foo - tricky to find the key!
.foos = hmap|string|foo - could be confused with an 'or' operation
.foos = hmap~string~foo
I don't like an infix operator for this in general because it raises questions about associativity.
For example is hmap*string*foo
an hmap<string, foo>
or an hmap<string<foo>>
or maybe a foo<string<hmap>>
?
Maybe you should use the "of" keyword:
map = HashMap of String, Foo()
In Boo it would look like this:
map = HashMap[of string, Foo]()
精彩评论