Ballerina 0.991.0 consists of improvements to the language syntax and semantics based on the language specification and new features and improvements to the standard library modules, extensions, and tooling.
- Improved error handling with new checkpanic expression. Now, error values cannot be ignored using "_".
- Improved type checking with the union type.
- Improved syntax for the closed record, closed arrays, and string/XML interpolation etc.
- Additionally, this release includes several fixes to address Ballerina language specification deviations from the Ballerina 0.990 specification.
- Closed record syntax was updated to use the {| and |} delimiters to indicate that the record is closed.
Previous syntax
type Person record {
string name;
int age;
!...;
};
New syntax
type Person record {|
string name;
int age;
|};
- The syntax for destructure binding pattern for closed records was also updated to use the {| and |} delimiters.
Previous syntax
Person p = { name: "John Doe", age: 25 };
Person { name: pName, age: pAge, !... } = p;
New syntax
Person p = { name: "John Doe", age: 25 };
Person {| name: pName, age: pAge |} = p;
- The syntax for closed arrays with inferred length was changed as follows.
Previous syntax
string[!...] array = ["a", "b", "c"];
New syntax
string[*] array = ["a", "b", "c"];
-
It is now mandatory for list element types to have an implicit initial value. Where a type
T
does not have an implicit initial value, aT?[]
could be used. -
Use of the
null
literal is now restricted to JSON contexts.
json response = null; // Allowed
string? name = null; // Compile error
- String template expression interpolation syntax was updated.
Previous syntax
string s = string `Hello {{name}}!`;
New syntax
string s = string `Hello ${name}!`;
- XML literal interpolation syntax was updated.
Previous syntax
xml x = xml `<Person name={{name}}>{{content}}</Person>`;
New syntax
xml x = xml `<Person name=${name}>${content}</Person>`;
-
Interpolating XML elements and attribute names are no longer supported.
-
The XML attribute expression now directly returns the attributes of a singleton
xml
element as amap<string>
or()
if the operand is not a singletonxml
.
Previous syntax
map<anydata> attributeMap = map<anydata>.convert(x1@);
New syntax
map<string>? attributeMap = x1@;
-
Error values can no longer be ignored using “”. If the result of an expression is an
error
type or is a union that contains anerror
type, the result cannot be ignored using “”. This is to enforce the user to handle all possible errors. -
The capability to consider (run) any public function as an entry point to a Ballerina program was removed.
-
The types of the parameters and the return type of the
main
function were restricted to subtypes ofanydata
anderror?
respectively. -
The diamond operator was updated to perform type-casting as follows:
Foo f = <Foo> value;
If value
belongs to Foo
, casting will be successful and value
will be assigned to f
. Else, casting will result in a panic.
-
The type of the
error
detail is now restricted to be a mapping that could only have fields of types that are subtypes ofanydata|error
. -
The default record rest field type was changed to
anydata|error
fromanydata
. -
anydata
was updated to include structures of pure values (values whose types are subtypes ofanydata|error
).anydata
is now the union of the following:
() | boolean | int | float | decimal | string | (anydata|error)[] | map<anydata|error> | xml | table
-
Module variable declarations are not allowed to be
public
now and also require an assignment. -
The syntax for functions with external implementations has been changed as follows:
Previous syntax
extern function externFunction();
New syntax
function externFunction() = external;
- The signature of the
__attach()
method ofAbstractListener
has been changed as follows:
Previous signature
public function __attach(service s, map<any> annotationData) returns error?
New signature
public function __attach(service s, string? name = ()) returns error?;
- Type narrowing does not apply to global variables now.
- Ballerina crypto stdlib was made flexible enough to introduce new features and algorithms in future.
Previous syntax
string input = "Hello Ballerina";
crypto:hash(input, crypto:MD5)
New syntax
string input = "Hello Ballerina";
byte[] inputArr = input.toByteArray("UTF-8");
byte[] output = crypto:hashMd5(inputArr);
Ballerina gRPC client initialization in the generated code is changed. Generated file(*.pb.bal) from previous versions of Ballerina distributions will not be worked with this release. Regenerate the client stub using proto to Ballerina tool and replace the previously generated file with the new one.
Redesigned the Task library to function as a service. The previous task implementation of task:Timer
and task:Appointment
will be deferred and new task:Listener
and task:Scheduler
objects are introduced to create task timers and appointments.
Tasks now can be defined as a service and as an object. Both the previously existed Timer and Appointment functionalities can be used by new Listener and/or Scheduler.
Timer was previously created by providing onTrigger
and onError
functions along with the interval
and delay
parameters. Now interval
and delay
parameters are provided through a task:TimerConfiguration
record type, while onTrigger
function should be implemented as a resource function inside the attaching service.
Service can be created on top of a task:Listener
or can be manually attached to a task:Scheduler
object.
Previous Syntax
function startTimer() {
((function) returns error?) onTriggerFunction = cleanup;
function (error) onErrorFunction = cleanupError;
timer = new task:Timer(onTriggerFunction, onErrorFunction, 1000, delay = 500);
timer.start();
}
function cleanup() returns error? {
// onTriggerFunction
}
function cleanupError(error e) {
// handle error
}
New Syntax
function startTimer() {
task:TimerConfiguration timerConfiguration = {
interval: 1000,
initialDelay: 500
}
task:Scheduler timer = new(timerConfguration);
var attachResult = timer.attach(timerService);
if (attachResult is error) {
// handle error
} else {
var startResult = timer.start();
if (startResult is error) {
// handle error
} else {
// successfully started timer
}
}
}
Service timerService = service {
resource function onTrigger() {
// onTrigger function
}
}
OR
task:TimerConfiguration timerConfiguration = {
interval: 1000,
initialDelay: 3000
};
listener task:Listener timer = new(timerConfiguration);
Service timerService on timer {
resource function onTrigger() {
// onTrigger function
}
}
task:Appointment
functionality can be implemented using task:Listener
and the task:Scheduler
objects. Previously the cronExpression
used for the appointment given as a parameter, along with the onTrigger
and onError
functions. Now the cronExpression
should be provided using appointmentDetails
field inside the task:AppointmentConfiguration
record type. Alternatively, task:AppointmentData
record can also be provided as the appointmentDetails
field (see below examples).
onTrigger
function should be implemented inside a service, and the service can be created on top a task:Listener
or the service can be attached to a task:Scheduler
object, manually.
Previous Syntax
function startAppointment() {
((function) returns error?) onTriggerFunction = cleanup;
function (error) onErrorFunction = cleanupError;
appointment = new task:Appointment(onTriggerFunction, onErrorFunction, "0/2 * * * * ?");
appointment.schedule();
}
function cleanup() returns error? {
// onTrigger function
}
function cleanupError(error e) {
// handle error
}
New Syntax
task:AppointmentData appointmentData = {
seconds: "0/2",
minutes: "*",
hours: "*",
daysOfMonth: "?",
months: "*",
daysOfWeek: "*",
year: "*"
};
task:AppointmentConfiguration appointmentConfiguration = {
appointmentDetails: appointmentData
};
listener task:Listener appointment = new(appointmentConfiguration);
service appointmentService on appointment {
resource function onTrigger() {
// onTriggerFunction
}
}
OR
function startAppointment() {
task:AppointmentConfiguration appointmentConfiguration = {
appointmentDetails: “0/2 * * * * ?”
};
task:Scheduler appointment = new(appointmentConfiguration);
var attachResult = appointment.attach(appointmentService);
if (attachResult is error) {
// handle error
} else {
var startResult = appointment.start();
if (startResult is error) {
// handle error
} else {
// successfully started the appointment
}
}
}
service appointmentService = service {
resource function onTrigger() {
// onTrigger function
}
}
The format
, parse
, createTime
and toTimeZone
functions are changed to return errors when there is an issue.
Previous Syntax
time:Time timeVal = time:parse("2016-03-01T09:46:22.444", yyyy-MM-dd'T'HH:mm:ss.SSS");
New Syntax
time:Time|error timeVal = time:parse("2016-03-01T09:46:22.444", yyyy-MM-dd'T'HH:mm:ss.SSS");
-
Introduction of the
checkpanic
unary expressioncheckpanic
is a unary expression that is used to handle errors. Thecheckpanic
expression checks the result of the sub-expression and panics if the result iserror
.- The only difference between the
checkpanic
expression and thecheck
expression is that, if the result of the sub-expression is of typeerror
, thecheckpanic
expression results in a panic while thecheck
expression returns theerror
value.
-
Error values can now be destructured using binding patterns and typed binding patterns as follows,
// Usage of error typed binding pattern.
var error (reasonString, detailMap) = getErrorValue();
// Usage of error binding pattern.
string reasonString;
map<anydata|error> detailMap;
error (reasonString, detailMap) = getErrorValue();
-
Value equality checks (
==
,!=
) are now allowed witherror
values. -
The return signature of the initializer of an object can now be
error?
(sub types oferror
allowed) or()
.
type Person object {
string name;
function __init(string name) returns error? {
self.name = check fnWithPotentialErrorReturn(name);
};
}
// Usage
Person|error person = new("John Doe");
- Tuple type is now iterable via the
foreach
statement. - Patterns in the static value match statement now support const values.
- String can concatenate into XML values and the string part is automatically converted to an XML character sequence, resulting in XML concatenation. This supports both '+' and '+=' operators.
xml xValue = xml `<name>John</name>`;
xml yValue = xValue + "suf";
yValue += "fix";
io:println(yValue);
- Introduced NATS connector.
- Introduced Artemis connector.
- Introduced RabbitMQ connector.
- Introduced OAuth2 password grant type and client credentials grant type along with the direct token mode for outbound authentication.
- Added support for password hashing techniques for basic auth authentication.
- Introduced filepath module with a set of utility functions to manipulate the file path in a way that is compatible with the target operating system.
- Introduced an "encoding" API to perform byte[] to string conversions using different encoding mechanisms.
- Introduced RSA and AES encryption/decryption capabilities to the crypto API.
- Introduced RSA signing operations to the crypto API.
- Improved h2/mysql/jdbc database clients to share a single, global connection pool for interacting with the same database with same connection properties. The option to use an unshared or a locally shared custom pool is provided.
- Introduced a shared global connection pool for HTTP client connectors. Per-client pools are also possible with
http:PoolConfiguration
. - Improved the HTTP/2 client connection pool to distribute the request load among I/O threads properly.
- The Language Server Extension API to contribute custom completions.
- Improvements to the Go-To definition, Find all references and Rename features.
- Diagram view function collapsing capability. This feature allows you to expand functions in a sequence diagram to view its internal logic.
- Improved performance, stability, and reduced plugin size with “Lsp4IntelliJ” language client support.
- Ballerina language server-based code formatting.
- Minor bug fixes and improvements.
- Support for generating OpenShift artifacts.
See Ballerina performance test results, which is available in the repository.
See Github milestone issues to view bug fixes.
You can download the Ballerina distributions, try samples, and read the documentation at https://ballerina.io. You can also visit Quick Tour to get started.
We encourage you to report issues, improvements, and suggestions at the Ballerina Github Repository.