DISCOVERY

July 15th, 2018

Optional Typing in Groovy

Groovy

Type Systems

Java

While reading a book on Groovy recently I came across two different definitions that apply to the languages type system. The first states that Groovy is an optionally typed language. Optional typing in Groovy allows certain variables defined without a type (using the def keyword) and others with a type similar to Java. The second definition given to Groovy's type system is that it is dynamically typed. In the past I always associated dynamic typing with not having to explicitly declare types in code (in languages like Python and JavaScript). So how can Groovy have dynamic typing along with optional type declarations? To answer these questions I had to dig deeper into programming languages type system and sharpen up my definitions of dynamic and static typing.

As previously mentioned, I used to associate dynamic typing with a lack of type definitions. I likely made this association because languages that don't declare types in code are often dynamically typed - such as JavaScript and Python. While both JavaScript and Python are dynamically typed, the meaning of dynamic typing is less about existence of type definitions and more about when types are enforced.

Dynamic Vs. Static Typing

Dynamic Typing

A language is dynamically typed when types are enforced at runtime. Dynamic typing is a form of type safety - making sure there are no discrepancies between expected types and actual types in the language1. Dynamic typed languages enforce type safety dynamically at runtime. Dynamically typed languages often syntactically lack type definitions2.

Static Typing

A language that is statically typed enforces types at compile time and runtime. The ability to enforce types at compile time allows a language to safely fail the compilation stage when type definitions mismatch their values. Knowing types early on gives the compiler enough knowledge to optimize code even further based on the type3. Languages that are statically typed are generally categorized as safer and faster, albeit with less flexibility and more up front work when building code due to syntactic type definitions.

Quickly before moving further, here is a refresher of what I mean by types and type safety:

Type

A type consists of certain characteristics that describe a piece of data4. The characteristics alter how the compiler/interpreter handles the data's value5. Developers can perform different operations with a value depending of the characteristics defined in its type. Examples of data types are integers and objects (int in Java and instances of Object in Groovy/Java).

Type Safety

Type safety defines the handling of type errors and type mismatches in a programming language. Enforcement of type safety can occur at compile time or runtime. An example of a compile time type safety check in a statically typed language is failing the compilation stage if an object defined as type Integer is given a value of type String. Type safety in a dynamic programming language is handled at runtime, which is arguably a less elegant solution then failing before the code gets a chance to execute.

Since Groovy is dynamically typed, it enforces type safety at runtime instead of compile time. In some of the definitions I've seen about dynamic typing, dynamically typed languages are said to lack type definitions. However, in Groovy we know that type definitions are available for use similar to Java. The difference between using type definitions in Groovy and Java is enforcement at runtime in Groovy and enforcement at both compile time and runtime in Java. This makes Groovy dynamically typed and Java statically typed.

The following code and comments show the unique behavior of dynamically typed Groovy:

// The following code will compile yet fail at runtime since casting an // ArrayList to an Integer is not valid Integer hello = ['h', 'e', 'l', 'l', 'o'] println hello // Interestingly the same code will pass if you use a String type, // casting an ArrayList to a String String helloString = ['h', 'e', 'l', 'l', 'o'] println helloString

Groovy's ability to use type definitions leads to the definition of optionally typed.

As explored in my first Groovy discovery the def keyword actually just assigns a value to type Object. def does not define a value without a type - the type is just not explicitly declared. Everything in Groovy is an object, so everything has a type at runtime6.

The phrase "optionally typed" comes from the fact that syntactically declaring types in code is optional in Groovy. Developers can use the def keyword, allowing for implicit type declarations. Let's officially define optional typing and show some example Groovy code.

Optionally Typed

Optional typing is the syntactic ability to leave out type definitions. All values still have types, however they can be implicitly assigned.

// When a type is not specified, the type is Object. // It does not mean there is no type def hiWorld = "Hello World" assert hiWorld instanceof Object assert hiWorld instanceof String

If you are like me you probably also heard the terms strong and weak typing (loosely typing) before. I've often heard strong typing interchanged with static typing (and weak typing interchanged with dynamic typing). Unfortunately these definitions are incorrect, along with many of the textbooks and blog entries you hear the terms used in. Even I have used the terms incorrectly numerous times.

There is no real correct definition for strict and weak typing. It is often agreed upon that the terms should not be used due to the confusion they cause7. I won't go into the many definitions here, but you can read more about the history of the terms and their various uses elsewhere.

A common use of dynamically typed languages is duck typing.

Duck Typing

The general phrase that applies to duck typing is "If it walks like a duck and it quacks like a duck, then it must be a duck8." At its core this phrase is a conditional statement. If a value is able to quack, then the value must be a duck. In other words, if a values type definition has a method quack(), then we can safely assume that it is an instance of Duck or another compatible object with a quack() method. Bringing it all together, if an object has the quack() method it can be treated as a duck without even checking the type definition at all.

The following code takes advantage of Groovy's dynamic type system and duck typing. The value passed to outputAll() can be of any type with the assumption that its type definition has a each() method.

def static outputAll(item) { def str = "[" item.each { str += "${it}" } str += "]" return str } def outputList = outputAll([1,2,3,4,5]) def outputMap = outputAll([name:'Andy', age:'23']) println outputMap println outputList
[name=Andyage=23] [12345]

Groovy is unique because it allows for static typing with the use of annotations. I explored the @TypeChecked annotation in my second Groovy discovery and its ability to enable static typing on methods. Groovy can even take things to the next level with the @CompileStatic annotation. This annotation takes away even more of Groovy's dynamic language features. These annotations deserve an article of their own and I still don't understand them fully, but they seem to give even more flexibility to the Groovy programmer.

It turns out I really didn't know my definitions of dynamic and static typing at all. A future discovery can explore the differences between dynamic programming languages and static programming languages (these topics are different than static and dynamic typing but related). I can also look into static typing with Groovy. I'm really happy with the new knowledge I gained from the research for this post and look forward to reading more about Groovy soon.

[1] "Type safety", https://en.wikipedia.org/wiki/Type_safety

[2] "Dynamic Typing", http://wiki.c2.com/?DynamicTyping

[3] "JavaScript’s type system", http://2ality.com/2013/09/types.html

[4] "Data type", https://en.wikipedia.org/wiki/Data_type

[5] Dierk König & Paul King, Groovy In Action, 2nd ed (Shelter Island, NY: Manning, 2015), 55

[6] Kyle Simpson, You Don't Know JavaScript: Types & Grammar (Beijing: O'Reilly, 2015), 1

[7] "What is the difference between a strongly typed language and a statically typed language?", https://stackoverflow.com/a/2690593

[8] König., 63