Dynamic Vs. Static 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.
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:
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 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:
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.
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.
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.
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.