Image for post

Type inference is a common feature among mainstream programming languages. The functional ones, like ML and Haskell, are pioneers in exploring this programming paradigm where the declaration of a variable or a function may omit a type annotation. Today, even classic imperative languages such as C++ offer, to a certain extent, a kind of type inference.

C# is not an exception to the ever-increasing popularity of inference-enabled languages: since C# 3.0, developers may declare implicitly typed variables with the var keyword (in C++ 11, a similar feature was introduced — re-targeting the then-existing auto keyword). This functionality, however, falls under a provision: a declaration must be accompanied by an initializer.

Although one would not expect to see ML and Haskell’s “whole-program type inference” in C#, could this initializer requirement be relaxed? Why does it exist, altogether?

  • Is it due to any limitation or just a matter of taste?
  • Could the variable’s type be inferred from arbitrary expressions?
  • If yes, what are trade-offs from a language-design perspective?

In this article, I will describe the foundation of a standard type inference technique and ramble about the questions above.

Non-initializing Declarations

What do you answer when someone asks: why is it necessary, in C#, that a local var-declared variable is accompanied with an _initializer? _The accurate reply to this question is: because the language specification says so; it is not because the type would not be inferable otherwise. Consider function f.

The two statements above (a declaration- and an expression-statement) are not fundamentally different from the single statement var num = 42;. In fact, if permitted, the _Intermediate Language _(IL) code produced for the former would probably be equal to that produced for the latter. Also, one may easily observe that int is a valid replacement for var in f.

To set the stage for our discussion, let us quote — with minor adjustments for pedagogical reasons — the relevant fragment of the C# specification to which var is subject:

“When the local variable type is specified as var… the declaration is an implicitly typed local variable declaration, whose type is inferred from the type of the associated initializer expression.”

Another characteristic of C# is that a variable must be definitely assigned before we attempt to obtain its value. Let us also quote the language specification fragment that states such mandatory assignment.

“For an initially unassigned variable to be considered definitely assigned… , an assignment to the variable must occur in every possible execution path…”

It is not my intent to enter the pedantic realm of language specifications. Yet, based on our (informal) observation that var num; num = 42; is equivalent to var num = 42;; and the fact that a variable must be assigned before being used, could we slightly stretch the functionality provided by var?

Image for post

#type-systems #hindley-milner #type-theory #type-inference #csharp #programming-c

Stretching the Reach of Implicitly Typed Variables in C#
1.10 GEEK