I explained the overall motivation for the where
syntax in this StackOverflow answer:
Partly quoting from there (with some clarifications and edits):
Fundamentally, the problem with F{T}(args...)
in Julia 0.5 and earlier is that the F{T}
part is ambiguous – the parser knows what it means from the broader context, but its meaning depends heavily on that context. The fact that it can mean such different things is pretty confusing:
- In most contexts,
F{T}
means the parametric typeF
with type parameterT
. - Followed by parens in most contexts,
F{T}(args...)
means to apply the typeF{T}
to the argumentsargs...
as a function, typically constructing an instance of the typeF{T}
. - Followed by parens as the left hand side of a method definition, however, as in
F{T}(args...) = expr
, it means to define a method forF
as a function, with type parametersT
, formal argumentsargs...
, and definitionexpr
.
This motley collection of different meanings is not ideal. Indeed, constructor syntax, where these syntaxes collide, was, in my opinion, prior to 0.6, the worst, most confusing part of Julia. Moreover, there were no syntaxes for either of these meanings, both of which can be useful:
- Adding a method to
F{T}
for the concrete value ofT
in the current scope. - Adding a method to
F{T}
for each parametric valueT
.
The former was previously only possible by assigning a name to F{T}
and then adding a method to that. The latter was only possible inside of the parametric type block, where F
by itself was (and still is when you use the deprecated syntax) magically bound to each specific F{T}
when used as the function name in a method definition. In Julia 1.0, on the other hand, type parameters and constructors will be thoroughly consistent, following these general principles uniformly:
- The syntax used to define a method always matches the syntax used to call it.
- The
F{T}
syntax always refers to the typeF
with parameter valueT
. - Type parameters are always introduced by
where
clauses.
I think these principles make the syntax and semantics of parametric types and methods far more understandable and intuitive. Given these principles, semantics like what we now have seem inevitable. The only real question is syntax – and what syntax to use was one of the biggest bikesheds around this issue. I wasn’t initially thrilled with the postfix where
syntax, but it’s grown on me and now it seems quite natural. The only really odd case, as you mention, is f(...) where T = body
without any type bound, but I’ve found that even this case fairly quickly loses its unfamiliarity. Other keywords than where
were discussed, including forall
and ∀
. However, Julia’s “union all” types are not universally quantified types (they’re actually closer to existentially quantified types), so both of these choices would have been actively at odds with existing type theory nomenclature. The where
keyword was the most evocative choice proposed that didn’t clash with well-established terminology. Finally, having the where
clause on the right just seemed to read much more naturally in the vast majority of usages.