Skip to content

Generic specifier

Alex Zimin edited this page Jul 11, 2011 · 4 revisions

Table of Contents

Why not <>?

There were some other proposals for the syntax. As for the reasons we cannot use <>, we have discussed this some time ago.

Basically this is because of our New Brave, Great Parser. It first handles parens ([], {} and ()) as groups. This allows for far more powerful syntax extensions and embedding DSLs (like XML or regular expressions). Anyway, the parser cannot handle <> as parens, because they are used in regular operators.

There are some other advantages here:

  • it is easy possible to write a simple syntax highlighting for types in most editors now,
  • the lexical structure is far more regular,
  • and there is no need for strange lexer hacks they use in C# and C++.

Why not []?

Why cannot we use just [] for generic specifier? Please consider the following code:

class Bar [T] {
  public this [T] () { ... }
}
class Foo {
  public Bar [x : int] : void -> void
  { get { ... } }

  foo () : void
  {
    _ = Bar [qux] ();
  }
}

Now the invocation of Bar[qux] can have two meanings -- it's either construction of a new Bar instance or a reference to a indexer Bar. You could say that it is regular overloading resolution problem. But it is not. What is problematic is how to parse qux. In regular overloading you can parse and even type-check parameters of a call and then try possibilities. Here it is not possible, even parsing depends on the meaning of Bar.

Therefore while we think this would be the best solution, this cannot be used.

For the same reasons we cannot use () nor {} alone for generic specifier.

As for the Foo[_ : int, _ : string] there are two problems -- _ : int is (almost?) a valid expression, so the ambiguity remains, and the second more important problem is that it looks like we were forcing types of regular arguments to be of type int and string. This is not true in general -- there can be for example no formal arguments.

Why not new?

We don't like the new keyword, because allocation is far more frequent in the functional languages and we would like to save typing. Beside it would only solve the problem for constructors, not for generic methods.

Using :

One of the proposals was: Foo () : Foo [int,string] (actually it was Foo[int], but this is not possible, because type argument can be a tuple). For this to be consistent, it would have to be: (Foo : Foo [int,string]) (), otherwise you cannot do things like List.Map (some_list, Foo.[int,string]).

This is however still problematic -- when you see :, you don't know if it's a generic specifier or a type enforcement. Heuristic could be used -- if there are two Foos in a row, it's a generic specifier.

What I don't like with this approach is that it is quite lengthy -- you have to repeat the function name. It is also not immediately clear what does it mean (that it is not a type enforcement). Maybe (Foo : [int,string]) () would be a better option?

The type enforcement can be also used to make compiler know which type we want, so type inference can guess the proper generic parameters. This is however not true in general. There can be a function like:

SomeFun[T] () : void
{
  System.Console.WriteLine (typeof (T));
}
There is no way to infer the type of T here. So dropping generic specifier altogether is not possible for completeness reasons.

Use whitespace or use [] just for generics !

Nemerle syntax comes mostly from C-like languages. This is one of our goals -- make it readable for C programmers. Using just whitespace or using foo.at(1) for indexing is clearly against this goal.

Using prefix generic specifiers also doesn't help readability here. Especially when we use postfix specifiers for types.

What I would personally like to see here is some syntax experiments -- different pluggable parsers/lexers and so on.

Use some other two-character parens for all the generics

This is very sane idea ;-) We could for example use Dictionary [: int, string :] or something like this. But:

  • generic types are used very often -- single characters parens are a much better choice here (this is however not true for generic specifier, which is not going to be used often)
  • there are already some .NET languages using [] for type parameters,
  • we already changed the generics syntax twice, I don't think it is that good idea to change it again.
So while this is a very good idea from the consistency point of view, I don't think we're going to follow it.

Possible solutions

Probably the set of acceptable solutions here could be limited to using some keyword or operator in front of parens (or just after the first paren), preferably [], because they are already used for generic types. Of course other solutions are possible but keep in mind the arguments stated above.

Proposals include:

  • .
  • of
  • with
  • =
  • :

Final solution

As of Nemerle v0.9 the dot notation won and it seems that the language will stick with that. If you cannot understand what is this dot notation then look at some examples.

Clone this wiki locally