Type inference by context is a modern feature of several programming languages that allows compilers or interpreters to automatically infer the type of a variable based on the context in which it is declared.
The choice between typed and untyped languages has been a constant topic of debate in the programming realm (and it’s more boring than carrying a camel in your arms 🐫).
One of the undeniable advantages of dynamically typed languages like JavaScript or Python is that the syntax is more concise and straightforward, as it avoids the need to specify the type of the variables we create.
However, as programming languages evolve, mechanisms have also emerged that seek to simplify the verbosity of typed languages, without sacrificing the safety and robustness that typing provides.
Thus, languages like C# and C++, use the reserved word var
or auto
, respectively, to indicate to the compiler that we want it to infer the type of the variable during compilation.
Context type inference allows declaring variables in typed languages almost as comfortably as in untyped languages.
In fact, “untyped” languages are internally typed. They simply make very intensive use of these mechanisms.
Examples of type inference in different languages
Let’s look at some examples of context type inference in different programming languages.
In C#, the keyword var
is used to infer the type of a variable based on the initialization expression.
var number = 42; // The compiler infers that 'number' is of type int
var text = "Hello, world"; // The compiler infers that 'text' is of type string
var list = new List<string> { "one", "two", "three" }; // The compiler infers that 'list' is of type List<string>
In C++, the keyword auto
is used to indicate that the type of the variable should be inferred from the initialization value. This is especially useful for long or complicated types.
auto number = 42; // The compiler infers that 'number' is of type int
auto text = std::string("Hello, world"); // The compiler infers that 'text' is of type std::string
auto list = std::vector<std::string>{"one", "two", "three"}; // The compiler infers that 'list' is of type std::vector<std::string>
In JavaScript, type inference is implicit and does not require special keywords. The type of a variable is automatically inferred based on the assigned value.
let number = 42; // The interpreter infers that 'number' is of type Number
let text = "Hello, world"; // The interpreter infers that 'text' is of type String
let list = ["one", "two", "three"]; // The interpreter infers that 'list' is of type Array
In Python, variable types are automatically inferred at the time of assignment. It is not necessary to specify the type, as Python is a dynamically typed language.
number = 42 # Python infers that 'number' is of type int
text = "Hello, world" # Python infers that 'text' is of type str
list = ["one", "two", "three"] # Python infers that 'list' is of type list
Best practices Tips
Context type inference reduces repetitive code, and avoids the redundancy of having to specify the type explicitly when it is already evident from the assignment.
Additionally, it improves code readability. For example, consider the following case in C#.
// it's easier to read
var list = new List<string> { "one", "two", "three" };
// than this
List<string> list = new List<string> { "one", "two", "three" };
On the other hand, it also facilitates maintenance. By not relying on an explicit declaration, changes in data types are propagated automatically if the initial assignment changes.
For example, if we have a function that returns a type,
// method that returns an object of type myClass
myClass DoSomething()
{
// ... function content
}
// many lines down, create an object with the method
var myObject = DoSomething();
If at any point someone changes DoSomething
to return something else (for example, ImyInterface
), there is no need to change var myObject = DoSomething();
, the changes “propagate” automatically.
However, there are also many detractors of context type inference. Especially those who are very accustomed to programming with traditionally strongly typed languages.
Thus, it is often advised not to use it in situations where the type is not obvious. For example,
// here the type is obvious
var myList = new List<string>();
// here the type is not obvious
List<string> myList = myMethod();
In the end, the decision is yours. Personally, I recommend using context type inference even in soup. But it’s not an absolute truth. The best thing is to make your own judgment.