- 1.2.55
- 1.2.54
- 1.2.53
- 1.2.52
- 1.2.51
- 1.2.50
- 1.2.49
- 1.2.48
- 1.2.47
- 1.2.46
- 1.2.45
- 1.2.44
- 1.2.43
- 1.2.42
- 1.2.41
- 1.2.40
- 1.2.39
- 1.2.38
- 1.2.37
- 1.2.36
- 1.2.35
- 1.2.34
- 1.2.33
- 1.2.32
- 1.2.31
- 1.2.30
- 1.2.29
- 1.2.28
- 1.2.27
- 1.2.26
- 1.2.25
- 1.2.24
- 1.2.23
- 1.2.22
- 1.2.21
- 1.2.20
- 1.2.19
- 1.2.18
- 1.2.17
- 1.2.16
- 1.2.15
- 1.2.14
- 1.2.13
- 1.2.12
- 1.2.11
- 1.2.10
- 1.2.9
- 1.2.8
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
Overview of Ballerina Swan Lake Preview 4
This release is the fourth preview version of Ballerina Swan Lake. This release includes a new set of language features along with improvements and bug fixes to the compiler, runtime, standard libraries, and developer tooling.
- Updating Ballerina
- Highlights
- What is new in Ballerina Swan Lake Preview 4
- Language
- Class definitions
- Object-constructor expressions
- Distinct objects
- Final fields in objects
- Isolated functions
- Improved support for quoted identifiers
- Subsequent initialization support for local final variables
- Handle errors at a single point
- The
fail
statement - Predeclared module prefixes
- Improved lang library functions
- Runtime
- Standard library
- Developer tools
- Language
Updating Ballerina
You can use the update tool to update to Ballerina Swan Lake Preview 4 as follows.
For existing users
If you are already using Ballerina, you can directly update your distribution to the Swan Lake channel using the Ballerina update tool. To do this, first, execute the command below to get the update tool updated to its latest version.
ballerina update
Next, execute the command below to update to Swan Lake Preview 4.
ballerina dist pull slp4
However, if you are using a Ballerina version below 1.1.0, install via the installers.
For new users
If you have not installed Ballerina, then download the installers to install.
Highlights
- Revised Ballerina object syntax, which differentiates the object type from the
class
, from which you can create object values. - Introducing
isolated
functions to achieve concurrency safety together withreadonly
values. - Introducing
distinct
object types offering the functionality similar to what is provided in nominal type systems. - Improvements to quoted identifiers to support arbitrary, non-empty strings as Ballerina identifiers.
What is new in Ballerina Swan Lake Preview 4
Language
The language implementation is based on the Ballerina Language Specifications Draft 2020-09-22 and the new Transactions proposal.
Class definitions
Module-class definitions
With the introduction of module-class definitions, the type of the object and the implementation of the behavior of the object are separated. Module-class definitions describe both the type of the object and the behavior of that object whereas object-type definitions describe only the type of the object.
The abstract
objects are now plain object-type definitions and the previous object-type definitions with implementations are now module-class definitions.
To migrate existing code easily, you can abstract this change by simply replacing type Obj object {...};
with class Obj {...}
.
Previous syntax:
public type Obj object { int i; function init(int i) { self.i = i; } };
New syntax:
public class Obj { int i; function init(int i) { self.i = i; } }
Object-type descriptor
Object-type descriptors can be used to describe an object type.
Note: They cannot be used to create object values.
Similar to the previous abstract object
, object-type definitions no longer support specifying the default values for fields.
To migrate existing abstract object-type definitions, you can simply remove the abstract
keyword from the type definition.
Previous syntax:
type Obj abstract object { function foo(int i); };
New syntax:
type Obj object { function foo(int i); };
Object-constructor expressions
Object-constructor expressions can be used to define an object inline as opposed to referring to a pre-defined class with a new
expression. The parameter list of an init
method within an object constructor expression must be empty.
public function main() { var ob = object { function foo() { // do something } }; }
Object-constructor expressions also support a type reference in which the referenced type is included in the object type in the same way as in an object-type inclusion.
class RefClass { int x; function init(int y) { self.x = y; } } var objectValue = object RefClass { function init() { self.x = 4; } };
Distinct objects
This release adds support for defining distinct
object types. This provides a way to achieve an effect similar to nominal typing for objects within the Ballerina structural type system.
distinct class Student { function getKind() returns string { return "Student"; } } distinct class Employee { function getKind() returns string { return "Employee"; } } Student p = new (); Employee q = p; // error: incompatible types: expected 'Employee', found 'Student' // Sub-typing relationship is indicated by type inclusion of `Employee`. distinct class Manager { *Employee; function getKind() returns string { return "Manager"; } } Manager r = new (); Employee s = r; // This is allowed since ‘Manager’ is a distinct subtype of ‘Employee’
Final fields in objects
Classes and object-constructor expressions can define fields as final
fields. A value can only be assigned to such a field during the object construction (i.e., via an initializer expression or in the init
method). A final
field of an object cannot be assigned a new value once the object is created.
class Controller { final string id = "default"; final map<decimal> config; int priority; function init(map<decimal> config, int priority) { self.config = config; self.priority = priority; } }
Note: Objects no longer allow
read-only
fields.
Isolated functions
A function that accesses mutable values only via its parameters can now be marked as an isolated
function. Concurrency safety can be guaranteed when isolated
functions are used with immutable values or by controlling the arguments passed to the isolated
function.
isolated function addSum(int[] arr, int i, int j) { arr.push(i + j); }
A function can be marked as isolated
if it
- accesses the global state only if it is immutable (i.e., variables that are implicitly or explicitly
final
and the type is a subtype ofreadonly
(immutable values)) - calls a function or a method only if that function or method is
isolated
- does not start new workers
Improved support for quoted identifiers
The quoted identifier feature has been improved by adding the support for extending the types of the characters that are allowed. This adds the possibility of using arbitrary, non-empty strings as identifiers. The quoted identifiers can be used with a ’
prefix and the following supported character sets.
- Alphanumeric characters
- Underscore
- ASCII special characters with a preceding
\
escape character - The JVM-reserved character set is now supported by Ballerina through an encoding scheme
- Unicode characters
- Characters specified with hexadecimal Unicode code points (e.g.,
\u{1234}
)
// Quoted identifiers in type names and field names. type 'Person_\{name\&ĀǤȆ\} record {| string 'first\ name; int 'ĀǤȆ; |}; // Quoted identifiers in function names. function 'get_ɱȅșșȧǧȅ_with\#(int value) returns string { return value.toString() + " is numeric value"; } public function main() { 'Person_\{name\&ĀǤȆ\} person = {'first\ name: "John", 'ĀǤȆ: 25}; string message = 'get_ɱȅșșȧǧȅ_with\#(5); // Quoted identifiers with hexadecimal code points. string 'unicode_\u{2324} = "John Doe"; }
Subsequent initialization support for local final variables
Local final variables can now be defined without an initializer expression as long as they are initialized before they are referenced, similar to ordinary local variables. However, a value cannot be assigned to a final
variable more than once.
map<int> lengths = {}; function addLength(string key, string|string[] value) { final int length; if value is string { length = value.length(); } else if value.length() == 0 { length = 0; } else { length = value[0].length(); } lengths[key] = length; }
Handle errors at a single point
Ballerina supports handling errors at a single place using the on fail
clause. The on fail
clause can be used optionally with statements such as while
, foreach
, do
, transaction
, retry
, lock
, and match
.
do { int parsedNum = check parse("12"); // Parsing a random string will return an error. // Thereafter, the control is transferred to the `on fail` clause. int parsedStr = check parse("invalid"); var res = commit; } on fail error e { io:println("Error occurred during parsing: ", e.message()); }
The fail
statement
Executing a fail
Statement will cause the control flow to transfer to the on fail
clause of the nearest lexically-enclosing statement that has an on fail
clause. If there is no on fail
clause, then it breaks the current execution and returns an error.
do { if (accountID < 0) { InvalidAccountIDError invalidAccountIdError = InvalidAccountIDError(INVALID_ACCOUNT_ID, accountID = accountID); fail invalidAccountIdError; } else if (accountID > 100) { AccountNotFoundError accountNotFoundError = AccountNotFoundError(ACCOUNT_NOT_FOUND, accountID = accountID); fail accountNotFoundError; } // The type of `e` should be the union of the error types that could // result in transferring control from the `do` statement. } on fail InvalidAccountIDError|AccountNotFoundError e { io:println("Error occurred: ", e.message(),", Account ID: ", e.detail()["accountID"]); }
Predeclared module prefixes
The module prefix t
(which could be boolean
, decimal
, error
, float
, future
, int
, map
, object
, stream
, string
, table
, typedesc
, or xml
) has been predeclared as referring to the lang.t
lang library module now.
Such modules can now be used without explicitly importing them.
public function main() { int max = 'int:max(311, 22, 41234); }
Improved lang library functions
Several changes and improvements have been introduced to the ballerina/lang.value
and ballerina/lang.array
lang library modules.
Improved lang library support for JSON
Two new functions (i.e., fromJsonDecimalString()
and fromJsonFloatString()
) have been introduced to support different numeric types when converting (parsing) a string
as json
. The fromJsonDecimalString()
function converts numeric values to decimal
whereas the fromJsonFloatString()
function converts them to float
.
The fromJsonString()
function now converts numeric values as follows.
If the numeric value starts with the negative sign (-
) and is numerically equal to zero (0), it is converted to float
-0.0
. If the numeric value is syntactically an integer, it is converted to an int
value. All other numeric values are converted to decimal
values.
Changes to toString()
The toString()
function now performs a direct conversion of the value to a string rather than producing a string that describes the value. The details of the conversion are specified by the ToString
abstract operation defined in the Ballerina Language Specification using the direct style.
If a student
is a record value defined as follows,
Student student = { name : "Anne", address : (), age : 23, grades : ["A", "A+", "B"] };
evaluating student.toString()
results in a different output as follows.
Previous result:
name=Anne address= age=23 grades=A A+ B
New result:
{"name":"Anne","address":null,"age":23,"grades":["A","A+","B"]}
Improved lang.array:sort()
function
This release supports an improved ballerina/lang.array:sort()
function. Now, you can specify the direction
in which the sorting should be done and a key
function, which returns a value that is used to order the members when sorting.
The sort()
function returns an array consisting of the members of the original array in the sorted order. If the member type of the array is not ordered, then the key function must be specified.
string[] cars = ["Ford", "Toyota", "Mitsubishi", "BMW", "Tesla"]; string[] sortedCars = cars.sort(array:DESCENDING, car => car.length());
Runtime
jBallerina runtime APIs
The jBallerina runtime APIs were moved to the org.ballerinalang.jvm.api
package and new APIs were introduced. The following APIs can be used to manage various runtime constructs.
Class | Usage |
---|---|
BValueCreator | Create ballerina value instances. |
BErrorCreator | Create ballerina error instances. |
BExecutor | The entry point from the server connector side to the Ballerina side. After finding the resource, server connector implementations can use this API to invoke the Ballerina engine. |
BRuntime | The external API to be used by the interop users to control the Ballerina runtime behavior. |
BStringUtils | Common utility methods used for string manipulation. |
Asynchronous Java interoperability
Calling async Java methods from Ballerina has been formalized using a new API. Previously, this was achieved by setting internal values to the Ballerina Strand
object. With this change, any Java extern method accepting BalEnv
as the first parameter, will be given an instance of the execution context.
The BalEnv
execution context instance provides a markAsync
method, which will mark the current Java method as asynchronous making the Ballerina runtime wait on it in a non-blocking way.
Ballerina Intermediate Representation (BIR) optimizations and improvements
The BIR has been optimized to reuse temporary variables inside Ballerina functions. This reduces the number of instructions in the byte-code representation contributing to reductions in method sizes and slightly-better runtime performance.
Also, The BIR binary format is now represented in a structured form using the Kaitai Struct Language. Kaitai Struct Language is a commonly-used approach to define binary formats. With the structured format, the BIR now can be easily understood and validated, which will help any user who wants to understand and work on generating different target executable code (e.g., generating LLVM-based executable code by reading the BIR).
The BIR binary structure is represented as the Kaitai Structure.
The BIR is now improved by including local variable scope information. With this support, the debugging view of local variables within functions has been improved to show correct-scoped variables during the debugging sessions.
Along with the scoping, BIR now contains a new variable kind named SYNTHETIC
, which identifies the variables generated at the de-sugar phase. These are skipped when adding meta-data so that generated variables do not appear in the scope with a debug hit.
Standard library
Re-align organization names of the connectors.
Modules | Old Organisation | New Organisation |
---|---|---|
mysql | ballerina/mysql | ballerinax/mysql |
kafka | ballerina/kafka | ballerinax/kafka |
rabbitmq | ballerina/rabbitmq | ballerinax/rabbitmq |
nats | ballerina/nats | ballerinax/nats |
Developer tools
The OpenAPI tool
OpenAPI CLI
The behavior of the OpenAPI CLI command was changed to make it easier to use. Now, you can generate Ballerina code from an OpenAPI contract and vice versa.
OpenAPI to Ballerina
$ ballerina openapi -i <contract> -o <output path>
- You can give the contract file in the YAML or JSON format.
- The above command generates both the service and client stubs.
- The command will give an output of three files containing the service, client and schema.
Command output example:
$ ballerina openapi -i petstore.yaml The service generation process is complete. The following files were created. -- petstore-service.bal -- petstore-client.bal -- schema.bal
- If you are interested in creating only a service, you can use the
mode
option to give the required mode. Themode
can be a service or a client.
$ ballerina openapi -i <contract> --mode (service | client ) -o <output Path>
- You can specify the output path with the
-o
option.
$ ballerina openapi -i <contract> --service-name <service name> -o <output Path>
- If you are interested in creating a service with resources having a specific tag or an
operationId
, you can do the following.
$ ballerina openapi -i <contract> --tags <tags> -o <output Path> $ ballerina openapi -i <contract> --operations <operationIds> -o <output Path>
Ballerina to OpenAPI
$ ballerina openapi -i <ballerina service file> -o <output path>
The service name is not mandatory and you can give the service name if you want to document a specific service. Otherwise, it will generate all the services that are included in the Ballerina source file.
$ ballerina openapi -i <ballerina service file> --service <service Name> -o <output path>
Improvements related to code actions
Azure Functions
Fix for Pure HTTP Functions Not Working.
AWS Lambda
Added domain-specific event types support.
Code formatting
A new formatter is introduced with a limited support for language features.