Sorry ahead of time if some of my terminology is inaccurate, my formal training isn't quite to the level it should be.
Almost all programming languages with types separate built-in functions a + b
and user defined functions f(x)
into different steps of the compiler. a + b
is dictated by some grammar that says something like expr ::= expr + term
, and is dealt with by the parser. The precedence/associativity of operations is also defined by the parser, and all user defined functions are dumped into a common bucket. f(x)
is defined by a declaration that requires x
to be some type, and the result to be a particular type - which is then commonly checked post-parse in static analysis.
Thinking about it, it seems as though f
(assuming for example, f
goes from int
to bool
) could be defined in a grammar similar to
bool ::= "true" | "false" | bool-expr
bool-expr ::= "f" "(" int ")"
int ::= int-constant | int-expr ...
But doing some searches, it seems as though computer science research around types and grammars are formal, but always distinct.
Sure, there are practical concerns. Grammars tend to be static, preventing user defined functions from being... user defined. Grammars tend to be hard to make correctly/unambiguously, and letting random users meddle is troublesome. Having huge grammars would be more troublesome than doing the same sort of work split off to a more limited type-checker.
But there's all sorts of research which is done regardless of practical concerns. I find it hard to believe that the two research areas wouldn't benefit from ideas from each other. And by treating types like non-terminals (or vice versa), it seems as though you get quite a few benefits not commonly available (function overloading by return type, extensible language using types rather than a separate meta-language, better integration of user defined operators).
Given my lack of training though, I'm guessing there's simply something I'm missing that breaks the correspondence or that it was researched and promptly discarded due to something obvious to others. So what am I missing?
Clarification for svick's comment
function overloading by return type:
Since statements/expressions would need to be integrated with types, statement would need to map to void
or unit
or some analogy - and expressions would be typed as above. For example, f(x:int) -> void
and f(x:int) -> int
, only one is viable as a statement. This requires function signatures to be processed before implementations (akin to C), but that is rather implied for all of the approach.
extensible language without meta-language:
By making types act like grammar non-terminals, it would allow the parser behavior to vary based on function declarations (and the various symbols in scope). Consider the above example where statements are required to be void
. f(x)
would not even parse without some declaration that both matches that input and results in void
. The function/variable/type declarations of the language effectively become the meta-language. But that's what programmers do already...
better integration of user defined operators:
Previous extensible languages had approaches to user defined operators, requiring the user to define precedence (usually some numeric value, relative to the built-in operators), and associativity. Having user defined and built-in operators/functions "speak the same language" as it were should provide a more uniform interaction between the two.
But mostly, the benefits I would expect are more theoretical. Things that can be proven/used about grammars could be applied to type checking and vice versa if types and non-terminals had some correspondence.