Deprecation of constructors keyword
Migrate your code to remove the obsolete
constructorskeyword
On November 20, 2018 the language standard changed
to remove the need for the constructors keyword and beginning the deprecation cycle for the
constructors keyword. This section describes what changed and how to migrate your code.
Changes
Before this change users would generate constructors for a union type using the constructors
keyword, which converted a union type into a record of constructors:
let Example = < Left : Natural | Right : Bool >
let example = constructors Example
in [ example.Left 1, example.Right True ]
After this change, you can now access union constructors as if they were fields of the
original union type instead of creating an intermediate record of constructors. For
example, this is now valid:
let Example = < Left : Natural | Right : Bool >
in [ Example.Left 1, Example.Right True ]
Phases
The constructors keyword is being phased out in three steps:
Phase 1 - Allow accessing constructors as fields of the union types
The first phase is backwards compatible, adding support for accessing constructors directly from a union type without changing the behavior of the
constructorskey word.Phase 2 -
constructors x = xThe second phase slightly breaks backwards compatibility by changing the constructors keyword to behaves as if it were the identity function for both type-checking and normalization purposes. In other words, any Dhall expression of the form:
constructors x
… behaves exactly as if it were just:
x
For the common idiom of:
let SomeUnionType = … let someUnionType = constructors SomeUnionType in … someUnionType.SomeConstructor …
… this is not a breaking change because
someUnionTypebecomes a synonym forSomeUnionTypeand you can access constructors directly off the original union type just as you did for the oldconstructorsrecord.This change also improves type-checking and normalization performance because the interpreter no longer needs to materialize the intermediate record of constructors. Now the interpreter only needs to type-check and normalize the constructors that you actually use.
However, this is still a breaking change because
constructors xis now a type instead of a term. For example, this means that you can no longer store the expressionconstructors xinside of a record containing other terms:-- This expression used to type-check before this change and -- no longer type-checks afterwards { foo = constructors MyUnionType , bar = 1 }
This change would also break any code that gave an explicit type annotation to a
constructorsexpression (unlikely, but possible).Phase 3 - Remove the
constructorskeywordThis change is strongly backwards-incompatible by removing support for the
constructorskeyword, breaking all code that still uses the keyword.
Migration
Phase 1 - Manually migrate your code
During Phase 1 the
dhallinterpreter does not provide support for code migration since replacingconstructors xwithxis not a safe transformation until Phase 2. If you wish to migrate your code you will need to do so manually.The main benefit of migrating your code manually (before Phase 2) is to get early access to the performance improvement from eliminating the intermediate
constructorsrecords.Phase 2 - Automatically migrate your code
During Phase 2 you can automatically migrate your code using
dhall lint, which will automatically replace all occurrences ofconstructors xwithxnow that this is a behavior-preserving transformation.Phase 3 - Your code breaks if you haven’t migrated
During Phase 3 the deprecation cycle is complete and if you haven’t migrated then your code will fail to type-check with an “Unbound variable: constructors” error message.