Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

Metadata

Number:

GEP-8

Title:

Static Type Checking

Version:

7

Type:

Feature

Status:

Draft

Leader:

Cédric Champeau

Created:

2011-10-08

Last modification:

2011-11-09

Abstract: Static Type Checking

This GEP introduces a new feature in the language known as static type checking. It is often disturbing for developers coming from a statically typed language (say Java) to discover that the Groovy compiler will not complain at compile time:

  • when assignments are made on different types
  • when a method doesn't exist
  • when a property or variable doesn't exist
  • when returned object type doesn't match the method signature
  • ...

All those are silent because the dynamic nature of the Groovy language makes such code perfectly valid. However, in some situations, a developper may want Groovy to behave like a statically typed language and have the compiler give hints about such "errors". To do this, Groovy must introduce static type checking.

Rationale: Static Type Checking vs Static compilation

It is important to make the difference between static type checking and static compilation. The goal of this GEP is to have an option to turn static type checking (STC) on. If STC is activated, the compiler will be more verbose (you will also see the term "grumpy"), but in the end, the generated bytecode and runtime behaviour will be exactly the same as if you did not activate this mode. This is a major difference from an alternate compiler like Groovy++ which will perform STC then produce a different bytecode and therefore produce different runtime semantics. The scope of this GEP is only a static type checker, and therefore should only be considered as a feature which allows developers to write statically checked code, so is an elegant way for example to leverage the Groovy syntax to reduce verbosity of Java code while still getting strongly checked code. Eventually, IDE could support the STC mode and provide information to the developper.

Implementation details

Development branch

The code is currently in heavy development, so make sure that you checkout the code from Git. The code is in the grumpy branch. It adds an AST transformation named TypeChecked. If set, then the AST transformation will perform type inference and store type information in AST nodes metadata. Eventually, if errors are found, it will add errors to the compiler through a dedicated addStaticTypeError method which basically does the same as the traditional addError method but prefixes the messages with a "Static type checking" message. This is done to help the developer determine whether the error he is seeing is a "plain Groovy" error, or an error thrown by the STC mode.

The StaticTypeCheckingTestCase class

Static type checking behaviour must be tested. As there are tons of possible checks to be done, a base test class provides a framework for testing this mode. Unit tests for static type checking should override this class.

Decisions made

About this section

The goal of this section is to provide code samples which demonstrates in what case the STC transformation will actually complain and what is the expected error message, and serves as a basis to future STC documentation. This section may not be up-to-date, and one should always take a look at the STC unit tests found in the src/test/groovy/transform/stc directory.

Features

Feature

Example

Behaviour

Status

Method does not exist

Complains about undefined method

Implemented

Property does not exist

Complains about undefined property "y"

Implemented

Assignment type checking

Assigning a String to an int is forbidden

Implemented

Incompatible binary expressions

Checks that arguments of a binary expression are compatible (here, no 'plus' method is available

Implemented

Possible loss of precision (1/2)

Complains about possible loss of precision

Implemented

Possible loss of precision (2/2)

Will not complain because '2' can be represented as an int

Implemented

Arrays components

Cannot assign an int value in an array of type String[]

Implemented

Method return type check

Ensures that assignments are compatible with method return type

Implemented

Explicit return type checking

Ensures that returned value is compatible with declared return type

Implemented

Implicit return type checking

Ensures that returned value is compatible with declared return type

Implemented

Implicit toString()

Implicit call to toString()

Implemented

Basic type inference

Method calls as well as property access are checked against inferred type

Implemented

Basic flow analysis

Last method call will not complain because type of 'o' at this point can be inferred

Implemented

Instance of

Casts should not be necessary when type can be inferred from a previous instanceof check

Implemented

DefaultGroovyMethods support

Method calls can be resolved against Groovy extension methods

In progress (no type inference for closure arguments)

with

Static type checking should be aware of the "with" structure

In progress

Categories

Compiler should be aware that extension method is found in a category

N/A (support will be limited as category support is inherently dynamic

Groovy list constructor

Type checks the arguments and the number of arguments

Implemented

Groovy map constructor

Type checks the properties and checks for wrong property names

Implemented

Closure parameter types

Type checking the arguments when calling a closure

Implemented

Closure return type inference

Closure return type can be inferred from block

Implemented

Method return type inference

Return type can be inferred from a method if the method is itself annotated with @TypeChecked (or class is annotated with @TypeChecked)

Implemented

Multiple assignments

In case of inline declaration, type check arguments.

Implemented

Multiple assignments from a variable

In case of inline declaration, type check arguments.

Unsupported

Generics

Type checking of generic parameters

Mostly implemented (some edge cases may fail)

Spread operator

Type checking against component type

Implemented

Open discussions

Closure parameter type inference

With the current version of the checker, idiomatic constructs like :

Are not properly recognized. You have to explicitly set the type of the "it" parameter inside the closure. It is because the expected parameter types of closures are unknown at compile time. There is a discussion about how to add this type information to source code so that the inference engine can deal with them properly.

Unification Types

In cases of for example "x instanceof A || x instanceof B" with A and B being unrelated we could still make an artificial union kind of type, that contains everthing present in A and B, to allow those kinds of method calls. The alternative to this is to allow only methods from Object here, which is less interesintg. This typing can also be used for multicatch, ensuring that a method call is only valid if it exists on each of the exceptions for the multicatch. In the current implementation (Okt-14-2011) the multicatch is already expanded at the point @TypeChecked will check. Meaning effectively this already represents a kind of union type, as the same code is in each catch block and thus the method call would fail, if the method is not available on each type. The proposed behaviour is therefore to align the instanceof case with multicatch.

References

Mailing-list discussions

JIRA issues

  • No labels