Object Typing — Static, Dynamic, Generic
Updated: Jul 13, 2021
“Two books on a desk near a MacBook with lines of code on its screen” by Émile Perron on Unsplash
The world of developers is divided into two types of people — those that swear by static typing and those that prefer dynamic typing. This is a constant debate that we have heard time and again.
This write-up isn’t about what’s better, it’s more about trying to understand what, if any, is the middle ground.
Let’s first talk a little about what static and dynamic typing is and (some) of their pros and cons.
A programming language is said to be statically typed when the type of a variable is defined before the variable is used. Some examples of statically typed languages are C, C++, Java, Scala, C#.
What this means is that a variable, once defined, can only hold values of the type it was defined with.
For example, the following piece of code
The number: 1
Whereas, the following code
would result in a compilation error such as
Error:(3, 19) incompatible types: java.lang.String cannot be converted to int
Consider another example of a RuntimeException due to type incompatibility
This would give an output
Result = 8
This, however, will throw a RuntimeException like so
Potentially fewer bugs — compile time error reporting helps avoid type mismatch error
Better documentation for your code since types are pre-defined
Performance enhancement — fewer runtime checks result in fewer runtime errors
More verbose code provides a form of documentation for future readers of the code. Verbosity can, sometimes, also help make your code more readable especially in scenarios where the business logic is complex.
One can confidently refactor owing to the fact that most major errors can be captured and fixed at compile time.
Potentially slower development — ensuring type conformity can reduce developer throughput. Every change goes through a compile then run cycle
As more data flows into the system, it can make the code harder to extend
More effort may be required to upskill developers as they deep dive into the code. As with any skill, learning type conformity isn’t the easiest task.
Pre-defined types can seem “unnecessarily ceremonious” (This, in part, has been taken care of in more modern statically typed languages such as Scala in the form of Type Inference. Typescript also relies on type inference to an extent).
The oftentimes clumsy syntax and cognitive load of trying to coerce types back and forth at the edges of your app, network or database boundaries stifles productivity. (Source)
Myth: Statically typed languages are slower because all code needs to be compiled every time a change is made
Fact: Only the changed classes are compiled. Also, most modern IDEs compile as you type, so there is no waiting to finish compiling before you can run your code
Myth: Statically typed languages are more restrictive
Fact: It may seem so because one does need to know what they’re writing before they write it for type conformity. This, however, provides a safety net for developers to avoid unexpected errors later in the development cycle.
A popular term associated with dynamic typing is Duck Typing.
Duck typing is concerned with establishing the suitability of an object for some purpose, using the principle, “If it walks like a duck and it quacks like a duck, then it must be a duck.”
For example, the following Ruby commands
would result in
Type of foo = Integer Type of foo = String Type of foo = TrueClass
The “type” of the variable foo changes according to the value that it holds.
Potentially faster development— developers can focus on implementing business logic rather than running around programming structs. Dynamically typed languages provide a simple write and run methodology.
Less verbose code as the variables are defined when and how they are used.
Dynamically typed languages are convenient for scripting with their write and run policy.
Dynamic types provide for writing flexible methods — if the operations written in a method have nothing to do with the type of data being passed in, the same method can be used for any data type.
Dynamic typing may result in more runtime errors, and these errors crop up later in development cycle rather than sooner
Dynamic typing may also result in a performance hit due to more dynamic dispatch and runtime checks
Dynamic typing needs more extensive tests in order to cover multiple possible types and hence prevent unexpected runtime errors.
Myth: Dynamically typed languages are completely free of types
Fact: Some amount of type awareness is needed to implement business logic. You do need to know whether a certain method is available on the concerned object type, even though the type isn’t explicitly set.
Myth: Dynamic typing results in a performance hit
Fact: This is not a given —by using strategies such as caching and employing smarter algorithms the performance concerns can be minimised. It’s possible to execute dynamic languages efficiently, it’s just a tad more complicated than it might be in a statically typed language of a similar calibre.
Enter Generic Types
Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. (Source)
In my opinion, generic types are an underrated provision of statically typed languages. One of the complaints I have heard from developers when using statically typed languages is that they end up writing duplicated code due to the fact that incoming data can be of several different types. This is a problem that can be easily solved using generics. Generic types are a hybrid approach to reaping the benefits of dynamic typing while having the safety net of static typing.
Consider the following code snippets
The output for this would be
Making dog walk: true Making robot walk: true
This is an extremely simple example, but it reflects that this might become a bit of a problem as more types of walkers get added.
Now consider this:
The output for this would be:
Making Animal walk: true Making Robot walk: true
To break it down a little, in case you’re not familiar with Generics in Java -
The method .getType0fWalker() accepts an argument of type T which indicates a “generic type”. The method .makeWalkerWalk() accepts an argument of type T that is a subtype of type Walker which indicates a “bounded generic type”. Both Animal and Robot here are subtypes of Walker (code). This is necessary to use the .walk() method implemented by both the classes defined. It is the same premise as that of dynamic typing, that you are not bound by a type as long as that object implements the method being used.
This is just one of the many ways in which generics provide flexibility within the context of statically typed languages.
Generic types provide a hybrid approach to the static vs. dynamic debate
It is a form of duck typing for static languages
Generic types are a way to leverage flexibility of dynamic typing in a statically typed context
In Java specifically,
Generic types were designed to extend Java’s type system to allow “a type or method to operate on objects of various types while providing compile-time type safety” (source)
Generic types are a good way to leverage polymorphism in Object Oriented programming.
As in the example above, generic types can be limited only to a specific type and its subclasses
Most modern languages that support generic types have provisions not only for generic methods, but generic classes and variables as well. Read more on some ways of using generics in java here.
It needs to be mentioned here that generic types do come with their own set of problems. To mention a couple -
Using generic types can be a tricky thing and often requires a certain level of expertise in the specific programming language.
Problems such as Type Erasure in languages like Java and Scala can lead to unexpected behaviour in code.
While both static and dynamic typing have their own pros and cons, generic types provide some amount of respite in finding a middle ground when required. As is true for any choice, when implementing a system pick the tools that best fit your use case but with a fair understanding of the options available.
(Some others are hyperlinked in the post itself)