Migrating to LIGO v1.0
Version 1.0 of LIGO includes breaking changes, so you must update your source code when you upgrade your installation of LIGO as described in Installation.
Changes to the main
entrypoint
The LIGO compiler no longer auto-detects a function named main
as the sole entrypoint of a contract.
Similarly, you can no longer specify entrypoints and views by passing functions to the --entrypoint
and --view
command-line arguments.
Now, use multiple entrypoints and views denoted with the @entry
and @view
decorators.
In the same way, the Test.originate
function now takes as an argument a module containing multiple entry points instead of a single function.
Contracts can still have a single function named main
decorated with @entry
that manages all entrypoints for the contract, but this code structure is deprecated.
For more information and for workarounds to help you migrate contracts with a single main
function, see Entrypoints and The main function.
Changes to parameters for views and entrypoints
Views and entrypoints used to accept the parameter and current storage as a tuple. Now, they accept these values as separate parameters.
For example, this view uses the old syntax:
This equivalent view uses the new syntax:
Changes to contract_of
and parameter_of
The aforementioned changes to entrypoints, views, and the main
function affect how contracts are tested.
Beginning in version 0.64.2, the behavior of contract_of
and parameter_of
in tests has changed.
For examples of how to use contract_of
, see Testing.
For examples of how to use parameter_of
, see Contracts.
export
and @private
now have the expected effect
Previously, all declarations were exported regardless whether export
, @private
or neither was used.
In LIGO v1.0, JsLIGO definitions which are not marked with export
or designated as an entrypoint are not exported, and CameLIGO definitions which are marked with @private
are not exported.
In other words, the default for JsLIGO is now to make definitions private unless specified otherwise with export
of @entry
, and the default for CameLIGO is now to make definitions public unless specified otherwise with [@private]
.
Furthermore, in JsLIGO nested namespaces need to be exported in order to be accessed. For example, this code accesses a declaration that is inside another module; this is possible only because the declaration is exported:
The comb layout is now used by default
LIGO can format types in Michelson in two basic layouts: combs and trees. Previously, LIGO used trees by default, but in LIGO v1, it uses combs by default.
As described in Interoperability, sometimes you need to match the layout of Michelson values, such as when you call a contract that accepts parameters in combs or trees.
You can use the @layout
decorator in JsLIGO or the [@layout]
attribute in CameLIGO to set the layout of a type.
For more info on why this change happened, see Why did the default datatype layout change to @layout comb
?
If your project has a stable ABI that other tools rely on, you might need to manually set the type of entrypoint arguments and return types with the @layout
decorator in JsLIGO or the [@layout]
attribute in CameLIGO.
Combs and trees can perform differently, so you can try setting types such as variants with many cases as combs or trees and comparing the size and gas consumption of the compiled contracts.
Decorators are not commented
Prior to version 1.0, JsLIGO decorators were put in comments, as in this example:
Now, decorators are not in comments, as in this example:
For more information, see Decorators.
Field and tuple component access
Fields can be accessed with dot notation stuff.y
and brackets stuff["y"]
interchangeably:
Changes to CLI commands
The internal command
ligo daemon
was removed in v0.69.0 (changelog). There should be no noticeable change for the user because the new language server (used by tools such as the VsCode plug-in) does not use this command any more.Starting from v0.64.2 (changelog), the transpilation commands now take the arguments
--from-syntax
and--to-syntax
instead of the argument--syntax
for the source syntax and an unnamed parameter for the destination syntax. The destination syntax can still be inferred from the filename given to the-o
argument, such as-o dest.jsligo
.The command
ligo mutate
has been removed; use Mutation testing instead.
Mutation testing
Support for CST mutation testing was dropped in v0.66.0 (changelog). However, AST mutation testing is still supported; see Mutation testing.
Kathmandu protocol deprecated
Starting from v0.64.2 (changelog), the Kathmandu protocol is deprecated. If you need to recompile an old LIGO contract for an outdated protocol version, you can use the compiler version that the project was developed with.
Package management: use ligo.json instead of package.json or esy.json
To separate LIGO package management from JavaScript package management toolchains such as Node.JS, LIGO now uses a separate manifest in the file ligo.json
.
As part of this change, LIGO no longer uses the esy
tool for package management, and the installation.json
file, formerly located at _esy/ligo/installation.json
, should now be moved to _ligo/ligo/installation.json
.
Changes specific to JsLIGO
Short notation for tez
and mutez
You can now write 3tez
or 3mutez
instead of 3 as tez
or 3 as mutez
.
New bitwise operators
The following operators have been added, and can be used with nat
and bytes
:
&
: Bitwise and|
: Bitwise or^
: Bitwise xor<<
: Bitwise left shift (the shift amount is always anat\, even when shifting
bytes`)>>
: Bitwise right shift (the shift amount is always anat\, even when shifting
bytes`)
Here are examples of these operators in context:
For more information, see Bitwise operations.
Changes to pattern matching
JsLIGO's pattern matching is inspired by the ECMAScript Pattern Matching proposal. This section covers some of the changes this implies:
The new when
keyword makes pattern matching more explicit.
Specifically, pattern matching uses the when
keyword instead of a function that takes an object with cases as fields.
The do { ... }
expression is equivalent to the (() => { ... }) ()
thunk.
It allows a block of code containing statements (like const xyz = ...
or return 42
) to be used where an expression is expected.
For example, this is a pattern match prior to JsLIGO 1.0:
This is an equivalent match in JsLIGO 1.0:
Pattern-matching on lists in version 1.0 uses the syntaxes when([])
and when([head, ...tail])
:
Furthermore, there are a few changes to how patterns are written:
- Patterns for parameterless constructors take a
()
within thewhen(...)
; for exampleNil: () => 1
becomeswhen(Nil()): 1
- Patterns that match a constructor containing a tuple work similarly; for example
Cons: (pair) => pair.1 + f(pair.2)
becomeswhen(Cons(pair)) => pair.1 + f(pair.2)
- Patterns with one variable per parameter are written as expected:
Foo: (a, b) => a + b
becomeswhen(Foo(a, b)): a + b
For more information, see Matching.
A single underscore is now a valid variable name
Previously, following the convention of some functional languages, you could use a single underscore character (_
) to discard the value bound to it, as in this example:
Instead, a single underscore is now a normal variable name, following the JavaScript and TypeScript convention, where the underscore is used as a short name for a namespace containing many utilities, such as an alias for the lodash
library.
This means that the code above should now assign unique names to the discarded value, as in this example:
If multiple variables named with a single underscore are declared in the same scope, the compiler now throws an error (duplicate block-scoped variable) just as in TypeScript.
However, it is still possible to shadow a variable named _
within a smaller scope.
For example, if the variable is globally defined as an alias for another module, a function can still specify a variable named _
as an argument name and shadow the global definition.
Shadowing variables in this way can cause issues and therefore you should review your code for such cases.
Imports are now automatically re-exported
When you import a module with the #import
directive, it is automatically re-exported.
For example, if a file imports the file foo.jsligo
with the code #import "foo.jsligo" "Foo"
, a third file importing bar.jsligo
as Bar
can write Bar.Foo.x
to access the x
defined in foo.jsligo
.
For more information, see #import
.
true
and false
are reserved words
true
and false
are now keywords, not variables, and cannot be shadowed by a local variable declaration.
Changes specific to CameLIGO
Field and tuple component access
Fields and tuple components can be accessed with the same dot notation: