ted@tedneward.com | Blog: http://blogs.tedneward.com | Twitter: tedneward | Github: tedneward | LinkedIn: tedneward
What if you were to build a language....
... specifically to consume HTTP APIs/"Web 2.0"?
... specifically to make it easy to produce said APIs?
... to parallelize well?
... but without trying to do too much?
Ballerina Programming Language
general-purpose
concurrent
strongly-typed
with both textual and graphical syntaxes
heavily "service"-oriented
optimized for integration
open-source (https://github.com/ballerinalang
)
Built around a few key concepts
services are our principal distributed design choice
so make them first-class citizens
concurrency within a service should be easy/default
obervability should be plumbing
just like code resolution or memory management
functions and explicit state are sufficient
supports objects but not a full-featured O-O language
prefer structural typing over nominative
Core entities
service
a collection of network-accessible entrypoints
must be bound to a network protocol for it to become exposed
resource
a single network-accessible entrypoint within a service
isolation and transactions
for managing (and checking) race conditions
strands
logical coroutines bound to a native thread
no two strands of the same thread will execute concurrently
Try Ballerina
Ballerina Playground
https://play.ballerina.io/
Ballerina Docker image
https://hub.docker.com/r/ballerina/ballerina
docker run -v .:/home/ballerina -it ballerina/ballerina:1.0.2 bal run demo.bal
Ballerina source
https://github.com/ballerina-platform/
or install it locally
Installing Ballerina
brew install ballerina
Ballerina installers (Windows msi, macOS pkg, Linux deb, rpm)
or download the Ballerina tools zip
(currently) requires Java11
https://ballerina.io/downloads/
extract into directory of choice
add BALLERINA_HOME/bin
to your PATH
(bal
tool can self-update after installation)
Learning Ballerina
Read: Ballerina-by-Example (BBE)
https://ballerina.io/learn/by-example/
Language spec
https://ballerina.io/learn/platform-specifications/
Generating a new package
$ bal new greeter
Ballerina Syntax
similar (not identical) to most C-family languages
curly braces for blocks of code
// comments inside functions
semicolon statement terminators
files end in .bal
suffix
no filename/packaging restrictions
Hello, Ballerina
import ballerina/io; public function main() { io:println("Hello, World!"); }
Ballerina Semantics
structurally typed
no implementation inheritance
heavy FP influence
"resource-oriented"
services as first-class constructs
concurrency analysis and verification
transactional support
Running Ballerina
currently runs on top of the Java Runtime (JRE)
plans to move to native (LLVM?)
mostly hidden behind the bal
tool
... but JAR artifacts easily obtained
Running
$ bal run
Build-and-run
$ bal build; bal run target/bin/greeter.jar
REST API for Greetings
import ballerina/http; listener http:Listener httpListener = new (8080); service / on httpListener { resource function get greeting() returns string { return "Hello, World!"; } resource function get greeting/[string name]() returns string { return "Hello " + name; } }
Running
$ bal run
Client access
$ curl localhost:8080/greeting Hello, World! $ curl localhost:8080/greeting/Ballerina Hello Ballerina
Build a Docker
Add [build-options] cloud = "docker"
to Ballerina.toml
Add a Cloud.toml file to provide Docker settings
set buildImage=true
to generate image
set buildImage=false
to generate Dockerfile/arrange dependencies
bal build
generates the executable and the Docker image
Cloud.toml
[container.image] repository="tedneward" # ex - Docker hub name name="greeter" # container name tag="v0.1.0" [settings] buildImage=true # set this false to just gen the Dockerfile
Run the Docker container
$ docker run -d -p 8080:8080 tedneward/restgreeter:v0.1.0
https://github.com/tedneward/TicTacToeREST
intended as a "full example" of API + database + some business rules
"contract-first" (from OpenAPI YAML)
bal openapi -i ttt.yaml --mode service -o server
HTTP endpoints -> "business layer" -> "persistence layer" -> database
H2 embedded database
Ballerina is...
... probably not going to replace your current language/platform of choice
... but something to keep an eye on
... most certainly a hopeful influence for future languages/platforms
Values are of four kinds of types:
simple values: not constructed from other values
structured values: contain other values
sequence values: zero or more constituent items
behavioral values: not just data; code
"storage identity": reference vs value storage
"plain data": simple, sequence, or structured value with all-plain-data members
Variable declarations and usage
declared "C-style"
"Typename VariableName" with optional assignment
globals
declared at "file scope"
visible across entire module
visible everywhere if declared public
names can be any non-keyword identifier
or "escaped" using single backtick
multiple variables can be declared simultaneously
used to "destructure" tuples
var
used to declare type-inferenced variables
Simple values
nil
: ()
boolean
: true
, false
int
: 64-bit signed integers
float
: 64-bit floating-point
decimal
: decimal floating-point
Casting and conversions
cast using angle-bracket syntax
no implicit conversions; language library functions help with this
Structured values
array: ordered list of values of a single type
tuple: ordered list of values of multiple types
map
: mapping of string keys to values of (one) type
record
: mapping from strings to heterogeneous types
table
: ordered collection of uniquely-identified mappings
array: numeric-indexed vectors of types
indicated by square brackets ([ ]
) after type
initializer uses comma-delimited [ a, b, c ]
empty array initializer is [ ]
arrays know their own length (.length()
)
use ballerina/lang.arrays
package for utility methods
accessed for read/write by []
tuple: collection of unnamed fields
comma-delimited list within square brackets
structurally-typed
accessed via indexed integers or...
... destructured using assignment syntax
mapping: map
: a collection of named fields
value type defined using angle-bracketed syntax
use -string-indexed access for get/set
use ballerina/lang.maps
package for utility methods
mapping: record
: a collection of named fields
named fields of types
structurally typed
record types can compose as part of definition
fields can have defaulted values
Composing record types
type Date record { int year; int month; int day; }; type TimeOfDay record { int hour; int minute; decimal seconds; }; type Time record { *Date; *TimeOfDay; };
Closed and open records
"closed": records can only contain named fields
denoted by {|
|}
pairs instead of usual {}
"open": records can contain additional named fields
data just "comes along for the ride" in that instance
records are open by default
Sequence values
string
: sequence of Unicode values (string:Char
instances)
package ballerina/lang.string
contains usual string functions
iterate characters via iterator()
xml
: sequence of XML nodes (elements, processing instructions, etc)
package ballerina/lang.xml
for XML-related functions
iterate nodes via iterator()
xml
: object representations of hierarchy
hierarchy of types xmlelement, xmldocument, etc
sequence of zero or more XML {element, text, comment, or PI} instances
xml literal strings allowed with backtick-quoted strings
supports namespaces: (namspace-uri)element-name
format
package xmldata
converts between XML and JSON/Ballerina records
package xslt
does XML transformations
Behavioral values
function
: function w/0+ specified parameter types and a return type
object
: combination of named fields and named methods
typedesc
: type descriptor
error
: representation of an error
future
: a value to be returned by a function execution
stream
: sequence of values that can be generated lazily
handle
: reference to externally managed storage
error
: multi-valued fault condition type
package ballerina/lang.error
for utility methods
cause
: the cause of the error
detail
: deeper details about the error
message
: error message describing the error
stackTrace
: stack trace of the error
object
: collection of named fields and functions
two forms of construction:
"new-expression" using class
-defined template
"object-expression" using object literal syntax
object type inclusion: compose object declarations
not the same as implementation inheritance
Ballerina does not provide implementation inheritance
Object construction
type Hashable object { function hash() returns int; }; function h() returns Hashable { var obj = object { function hash() returns int { return 42; } }; return obj; }
Object type inclusion
type Cloneable object { function clone() returns Cloneable; }; type Shape object { *Cloneable; function draw(); }; class Circle { *Shape; function clone() returns Circle { return new; } function draw() { } }
distinct object types: significantly-named types
provides nominal typing capabilities
use distinct
modifier
Distinct types
type Person distinct object { public string name; }; distinct class Employee { *Person; function init(string name) { self.name = name; } } distinct class Manager { *Person; function init(string name) { self.name = name; } }
Union "types"
Vertical pipe |
indicates type can be one of two+ types
meaning either type satisfies the type restriction
string|error
indicates string OR error
nullable types (string?
) are essentially a union type
error?
== error|()
json
type is essentially a large union type
string|int|array|map
Immutability, Isolation, and Concurrency
services need to be highly concurrent
Ballerina wants to elevate this to compile-time validation
So Ballerina will try to compile-time enforce concurrency
Isolation
isolated
functions/methods ideal for concurrency
they do not use anything outside of parameters passed in
compiler-enforced!
immutable values enforced via readonly
modifier
applicable to function parameters
immutable copies of mutable values can be generated via cloneReadonly()
method
while
foreach
if/else
match
while
boolean {
... }
terminated by:
boolean condition changing to false
break
return
early loop cessation via continue
parentheses optional around boolean expression
old-school range-based uses range operator
foreach int x in 0 ..< 10
or over any collection
foreach Student s in studentArray
if
boolean {
... }
if
boolean {
... } else {
... }
if
boolean {
... } else if
...
parentheses optional around boolean expression
constant pattern
compared against compile-time value
binding pattern var x
binds value into local-variable x
wildcard pattern _
"default" case
list pattern [1, 2, 3]
matches against values in source sequence
list values can actually be any of these patterns
rest match pattern ... var r
binds the remainder of the values into r
mapping pattern {command: "add", amount: var x}
matches against key/values in source map (or json)
value of key/values can be any of these patterns
error pattern error (...)
]
binds to particular error types/values
error types instead of exception handling
in conjunction with check
keyword
asynchronous function invocation and futures
start
, wait
, future types
Basic syntax
function
name(
type name (, ...) ) returns
type {
... }
or function
name(...) =>
expression
single-return value (no value/void is ()
)
name is optional
assignable to variables (first-class value)
arguments can be passed either positionally or "by name"
Default parameter values
declared parameters can have default values
defaulted parameters must come after non-defaulted
Record parameters
reference parameters by name instead of position
name =
value syntax
must come after all positional arguments
Rest parameters
supports variable-number parameters
behaves as an array of the declared type
final parameter in parameter list
(behaves very similarly to JS rest/spread syntax)
Asynchronous invocation
use start
before call to make it async
each asynchronous call runs on a separate strand
results are now future
s
future values can be obtained via wait
keyword
ballerina/jballerina.java
module
external
keyword
handle
basic type
Annotations to match to name-based metadata
Connecting to JVM field
// Returns the `out` field in the `java.lang.System` class. // `java.lang.System#out` is of the `java.io.PrintStream` type. public function getStdOut() returns handle = @java:FieldGet { name: "out", 'class: "java/lang/System" } external;
Connecting to JVM method
// Invoke the `println` method on `java.lang.System#out`, // which accepts a `java.lang.String` parameter. public function printInternal(handle receiver, handle strValue) = @java:Method { name: "println", 'class: "java/io/PrintStream", paramTypes: ["java.lang.String"] } external;
Using both
public function main() { handle stdOut = getStdOut(); handle str = java:fromString("Hello World"); printInternal(stdOut, str); }
Who is this guy?
Architect, Engineering Manager/Leader, "force multiplier"
Principal -- Neward & Associates
http://www.newardassociates.com
Educative (http://educative.io) Author
Performance Management for Engineering Managers
Author
Professional F# 2.0 (w/Erickson, et al; Wrox, 2010)
Effective Enterprise Java (Addison-Wesley, 2004)
SSCLI Essentials (w/Stutz, et al; OReilly, 2003)
Server-Based Java Programming (Manning, 2000)