ted@tedneward.com | Blog: http://blogs.tedneward.com | Twitter: tedneward | Github: tedneward | LinkedIn: tedneward
explore a few languages
discuss why they're "next-generation"
do some speculation and futurism
Crystal: statically-typed Ruby-esque general-purpose
Julia: dynamically-typed high-performance general-purpose
Io: message-passing homoiconic
Flix: functional imperative logic
Pony: type-safe, memory-safe, exception-safe, concurrent
Haxe: object(ish) strictly-typed cross-platform
Ballerina: service-oriented
Wing: cloud-oriented
Mint: web-oriented
Wasp: full-stack web app
This is a "survey talk"
we want to cover 10 languages
in 45 mins
hello, here it is, goodbye
very happy to discuss any of these afterwards
The point here is "to know what you don't know"
... and give you some signposts for exploring
... and maybe give a talk at a future conference!
https://crystal-lang.org/
web playground: https://play.crystal-lang.org/#/cr
native compilation (via LLVM)
heavily Ruby-inspired syntax
statically type-checked, type-inferenced
non-nillable types (compile-time nil checks)
macro metaprogramming system
An HTTP server
require "http/server" server = HTTP::Server.new do |context| context.response.content_type = "text/plain" context.response.print "Hello world! The time is #{Time.local}" end address = server.bind_tcp 8080 puts "Listening on http://#{address}" server.listen
https://crystal-lang.org/install/
Online playground: https://play.crystal-lang.org/#/cr
Download: https://crystal-lang.org/install/from_targz
Package managers:
Homebrew/Linuxbrew: brew install crystal-lang
Ubuntu: curl -fsSL https://crystal-lang.org/install.sh | sudo bash
From sources: https://crystal-lang.org/install/from_sources/
self-hosting, so you need Crystal to build Crystal
Create a project
crystal init app hello
Hello, world: src/hello.cr
# TODO: Write documentation for `Hello` module Hello VERSION = "0.1.0" # TODO: Put your code here puts "Hello, world!" end
Run
crystal run src/hello.cr
Compile
crystal build src/hello.cr; ./hello
flexibility of Ruby syntax
performance of native (LLVM)
interoperability across other LLVM-based platforms (GraalVM, etc)
https://julialang.org/
compiled (via LLVM)
complex and rational numbers
object-oriented and functional via multiple dispatch
dynamically-typed
parallel, async, multithreaded processing
implicit distribution capabilities
metaprogramming (code is data is code)
Julia distributed invocations
$ julia -p 2 julia> r = remotecall(rand, 2, 2, 2) Future(2, 1, 4, nothing) julia> s = @spawnat 2 1 .+ fetch(r) Future(2, 1, 5, nothing) julia> fetch(s) 2×2 Array{Float64,2}: 1.18526 1.50912 1.16296 1.60607
With some interesting metaprogramming support
julia> ex1 = Meta.parse("1 + 1") :(1 + 1) julia> dump(ex1) Expr head: Symbol call args: Array{Any}((3,)) 1: Symbol + 2: Int64 1 3: Int64 1 julia> ex2 = Expr(:call, :+, 1, 1) :(1 + 1) julia> ex1 == ex2 true julia>
Hosting Julia in native code
#include <julia.h> JULIA_DEFINE_FAST_TLS int main(int argc, char *argv[]) { jl_init(); /* run Julia commands */ jl_eval_string("print(sqrt(2.0))"); jl_atexit_hook(0); return 0; }
$ gcc -o test -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/lib -Wl,-rpath,$JULIA_DIR/lib test.c -ljulia
Homebrew (macOS, Linux): brew install julia
Chocolatey (Windows): choco install julia
Downloads: https://julialang.org/downloads/
Build from source: https://github.com/JuliaLang/julia
Hello, world
println("Hello, world!")
Run
julia hello.jl
Or run interactively
$ julia _ _ _ _(_)_ | Documentation: https://docs.julialang.org (_) | (_) (_) | _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 1.9.1 (2023-06-07) _/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release |__/ | julia> print("Hello world") Hello world julia>
--project=
dir: Set dir as the home project/environment
-p
/--procs
: Launches N additional local worker processes
--machine-file
file: Run processes on hosts listed in file
type-inferencing helps keep syntax clean
metaprogramming (code as data)
strong math/science features/ecosystem
performance of native (LLVM)
interoperability across other LLVM-based platforms (GraalVM, etc)
clear embedding API--viable scripting engine
https://iolanguage.org/
a homoiconic language
all values are objects
prototype-based object model
everything is a message, even assignment
no keywords, no globals
dynamic
concurrent
embeddable
inspired by Self, Lua, Smalltalk, NewtonScript, Act1, LISP
A Card system (pt 1 of 2)
Random setSeed(Date clone now asNumber) List shuffle := method( for(i, 1, size - 1, swapIndices(i, Random value(0, size) floor) ) ) Deck := Object clone do( init := method( self cards := List clone list("h", "d", "c", "s") foreach(suit, for(value, 2, 14, cards append(value asString .. suit)) ) ) init shuffle := method(cards shuffle) dealCard := method(cards pop) show := method(cards foreach(i, card, write(card, " ")); "\n" print) )
A Card system (pt 2 of 2)
Deck show Deck shuffle Deck show Deck dealCard println Deck dealCard println Deck dealCard println
Embedding Io
#include "IoState.h" int main(int argc, const char *argv[]) { int exitResult; IoState *self; self = IoState_new(); IoState_init(self); IoState_argc_argv_(self, argc, argv); IoState_doCString_(self, "\"hello world\" println"); //IoState_runCLI(self); exitResult = IoState_exitResult(self); IoState_free(self); return exitResult; }
Homebrew: brew install io
Download distro from website (https://iolanguage.org/binaries.html)
Build from source (https://github.com/stevedekorte/io):
make vm; sudo make install
Other builds:
CLR: https://github.com/stangelandcl/io-clr
GraalVM: https://github.com/guillermomolina/graal-io
Iota (JS): https://github.com/dariusf/iota
PyPy: https://pypi.org/project/mio-lang/
Hello world
"Hello world" println
Running Io
io hello.io
Run the REPL
$ io Io 20151111 Io> "Hello World" println Hello World ==> Hello World Io>
homoiconicity is a powerful thing
everything-is-an-expression
everything-is-a-message
whole language "hangs together" interestingly
easy hosting makes for scripting capabilities
https://flix.dev/
functional-first imperative logic language
JVM-based
Algebraic Data Types and Pattern Matching
enum Shape { case Circle(Int32), case Square(Int32), case Rectangle(Int32, Int32) } def area(s: Shape): Int32 = match s { case Circle(r) => 3 * (r * r) case Square(w) => w * w case Rectangle(h, w) => h * w }
Pure and Impure
/// A pure function is annotated with `\ {}`. def inc1(x: Int32): Int32 \ {} = x + 1 /// An impure function is annotated with `\ IO`. def inc2(x: Int32): Int32 \ IO = println("x = ${x}"); x + 1 def f(): Int32 \ IO = // f is impure let r1 = inc1(123); // pure let r2 = inc2(456); // impure r1 + r2 // pure
Region-based local mutation
/// We can implement a *pure* `sort` function which /// internally converts an immutable list to an array, /// sorts the array in-place, and then converts it /// back to an immutable list. def sort(l: List[a]): List[a] with Order[a] = region r { toArray(l, r) !> Array.sort! |> Array.toList } /// We can also write a *pure* `toString` function which /// internally uses a mutable StringBuilder. def toString(l: List[a]): String with ToString[a] = region r { let sb = new StringBuilder(r); for (x <- List.iterator(r, l)) { StringBuilder.appendString!("${x} :: ", sb), l) }; StringBuilder.appendString!("Nil", sb); StringBuilder.toString(sb) }
First-class Datalog constraints
def reachable(g: List[(String, Int32, String)], minSpeed: Int32): List[(String, String)] = let facts = inject g into Road; let rules = #{ Path(x, y) :- Road(x, maxSpeed, y), if maxSpeed >= minSpeed. Path(x, z) :- Path(x, y), Road(y, maxSpeed, z), if maxSpeed >= minSpeed. }; query facts, rules select (src, dst) from Path(src, dst) |> Foldable.toList
Online playground: https://play.flix.dev/
Requires Java 11+
Download: https://github.com/flix/flix/releases/latest
flix.jar
contains the compiler and project tool
Visual Studio extension:
Create a .flix
file
Search Marketplace for the extension (in response to the popup)
Homebrew/Linuxbrew: brew install flix
flix
is alias for java -jar flix.jar
Initialize the project
java -jar flix.jar init
Hello world: src/Main.flix
def main(): Unit \ IO = println("Hello world")
Run the project
java -jar flix.jar run
https://doc.flix.dev/
Reference: https://api.flix.dev/
Blogs: https://flix.dev/blog/
JVM interoperability: https://doc.flix.dev/interoperability/
another player in the functional-first JVM world
JVM underpining makes for easy integration
dataflow programming is an interesting concept
https://www.ponylang.io/
statically-typed, object-oriented
actor-model
capabilities-secure
type-safe
memeory-safe
exception-safe
data-race free
deadlock-free
high-performance
Pony Philosophy: "Get Stuff Done"
No loadable code; everything is known to the compiler
type system guarantees
If your program compiles, it won’t crash.
There will never be an unhandled exception.
There’s no such thing as null.
There will never be a data race.
Your program will never deadlock.
Your code will always be capabilities-secure.
All message passing is causal. (Not casual!)
a classic concurrency problem
Producer: generate data (at max speed)
Consumer: consume data (at max speed)
producer cannot outstrip consumer (lost data)
consumer cannot outstrip producer (duped data)
Main
actor Main """ Producer-Consumer concurrency problem. Pony has no blocking operations. The Pony standard library is structured in this way to use notifier objects, callbacks and promises to make programming in this style easier. """ new create(env: Env) => let buffer = Buffer(20, env.out) let producer = Producer(2, buffer, env.out) let consumer = Consumer(3, buffer, env.out) consumer.start_consuming() producer.start_producing() env.out.print("**Main** Finished.")
Producer
use "collections" actor Producer var _quantity_to_produce: U32 let _buffer: Buffer var _num: U32 = 0 let _out: OutStream new create(quantity_to_produce: U32, buffer: Buffer, out: OutStream) => _quantity_to_produce = quantity_to_produce _buffer = buffer _out = out be start_producing(count: U32 = 0) => _buffer.permission_to_produce(this) if count < _quantity_to_produce then start_producing(count + 1) end be produce() => _out.print("**Producer** Producing product " + _num.string()) let prod: Product = Product(_num, "Description of product " + _num.string()) _buffer.store_product(prod) _num = _num + 1
Consumer
use "collections" actor Consumer var _quantity_to_consume: U32 let _buffer: Buffer let _out: OutStream new create(quantity_to_consume: U32, buffer: Buffer, out: OutStream) => _quantity_to_consume = quantity_to_consume _buffer = buffer _out = out be start_consuming(count: U32 = 0) => _buffer.permission_to_consume(this) if count < _quantity_to_consume then start_consuming(count + 1) end be consuming(product: Product) => _out.print("**Consumer** Consuming product " + product.id.string()) _quantity_to_consume = _quantity_to_consume -1
Buffer
actor Buffer let capacity: USize var _products: Array[Product] var _future_products: USize = 0 var _producers_waiting: Array[Producer] = Array[Producer] var _consumers_waiting: Array[Consumer] = Array[Consumer] let _out: OutStream new create(capacity': USize, out: OutStream) => capacity = capacity' _products = Array[Product](capacity) _out = out
Buffer
be permission_to_consume(cons: Consumer) => let debug_string = "**Buffer** Permission_to_consume" _out.print(debug_string) try _out.print(debug_string + ": Calling consumer to consume") cons.consuming(_products.delete(0)?) // Fails if products is empty. try _out.print(debug_string + ": Calling producer to produce") _producers_waiting.delete(0)?.produce() end // If there are no producers in waiting, do nothing. else _out.print(debug_string + ": Storing consumer in waiting") _consumers_waiting.push(cons) end be permission_to_produce(prod: Producer) => let debug_string = "**Buffer** Permission_to_produce" _out.print(debug_string) if (_products.size() + _future_products) < capacity then _future_products = _future_products + 1 _out.print(debug_string + ": Calling producer to produce") prod.produce() else _producers_waiting.push(prod) _out.print(debug_string + ": Storing producer in waiting") end
Buffer
be store_product(product: Product) => let debug_string = "**Buffer** Store_product" _out.print(debug_string) _future_products = _future_products - 1 try _out.print(debug_string + ": Calling consumer to consume") _consumers_waiting.delete(0)?.consuming(product) else _out.print(debug_string + ": Storing product") _products.push(product) end
https://github.com/ponylang/ponyc/blob/main/INSTALL.md
requires a C/C++ compiler ($CC
and $CXX
env vars on *nix)
Homebrew/Linuxbrew: brew install ponyc
Build from source: https://github.com/ponylang/ponyc/blob/main/BUILD.md
Hello World: helloworld/main.pony
actor Main new create(env: Env) => env.out.print("Hello, world!")
Compile the code
cd helloworld; ponyc
Directory name is the name of the program
./helloworld
all the safety, everywhere we can get it
actors as first-class language constructs
general-purpose
concurrent
strongly-typed
with both textual and graphical syntaxes
heavily "service"-oriented
optimized for integration
open-source (https://github.com/ballerinalang
)
An Albums HTTP API (1 of 2)
configurable int port = 8080; type Album readonly & record {| string id; string title; string artist; decimal price; |}; table<Album> key(id) albums = table [ {id: "1", title: "Blue Train", artist: "John Coltrane", price: 56.99}, {id: "2", title: "Jeru", artist: "Gerry Mulligan", price: 17.99}, {id: "3", title: "Sarah Vaughan and Clifford Brown", artist: "Sarah Vaughan", price: 39.99} ];
An Albums HTTP API (2 of 2)
service / on new http:Listener(port) { resource function get albums() returns Album[] { return albums.toArray(); } resource function get albums/[string id]() returns Album|http:NotFound { Album? album = albums[id]; if album is () { return http:NOT_FOUND; } else { return album; } } resource function post albums(@http:Payload Album album) returns Album { albums.add(album); return album; } }
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
Download: https://ballerina.io/downloads/
(currently) requires Java11
extract into directory of choice
add BALLERINA_HOME/bin
to your PATH
Homebrew/Linuxbrew: brew install ballerina
Ballerina installers (Windows msi, macOS pkg, Linux deb, rpm)
bal
tool can self-update after installation
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!"); }
structurally typed
no implementation inheritance
heavy FP influence
"resource-oriented"
services as first-class constructs
concurrency analysis and verification
transactional support
runs on top of the Java Runtime (JRE)
mostly hidden behind the bal
tool
... but JAR artifacts easily obtained
Run
bal run greeter
Compile and run built JAR
bal build greeter
java -jar greeter/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
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
services as a first-class concept
JVM underpining makes for easy integration
built-in data types beyond typical primitives
structural typing makes more sense for services
Docker as the generated build artifact
https://www.winglang.io/
combines infrastructure and runtime code
cloud services as first-class citizens
local simulation (of cloud services)
deploy to any cloud
bring cloud; let q = new cloud.Queue(); let b = new cloud.Bucket() as "Bucket: Last Message"; q.addConsumer(inflight (m: str) => { b.put("latest.txt", m); }); new cloud.Function(inflight (s: str) => { log("Cloud Function was called with ${s}"); q.push(s); });
https://docs.winglang.io/getting-started/installation
Wing CLI
Requires Node v18+
NPM package: npm i -g winglang
Wing Console: download installer (macOS, Windows)
Hello... er, Cloud
bring cloud; let bucket = new cloud.Bucket(); let queue = new cloud.Queue(); queue.setConsumer(inflight (message: str) => { bucket.put("wing.txt", "Hello, ${message}"); });
Test it in the Wing Console
wing it hello.w
code and infrastructure, as code
local simulation
... and testing
https://haxe.org/
general-purpose, object-oriented, functional-friendly
statically-typed, type-inferenced
expression-centric
multi-platform-targeted
"Tier 1": JS, HashLink (VM), interpreted, JVM, PHP
"Tier 2": C++, Lua
"Tier 3": C#, Python, Java, Flash, Neko (VM)
(from https://haxe.org/documentation/introduction/language-features.html)
Anonymous structures
Generalized algebraic data types (parameterized enums)
Local functions and closures
Metadata
Partial function application
Parameterized types
Download: https://haxe.org/download/
Package managers:
Homebrew/Linuxbrew: brew install haxe
Source: https://github.com/HaxeFoundation/haxe
Hello world: Main.hx
class Main { static public function main():Void { // Single line comment trace("Hello World"); } }
Run it
haxe --main Main --interp
Cross-compile to JS
haxe --main Main --js Main.js
Cross-compile to Python
haxe --main Main --python Main.py
Cross-compile to Java
haxelib install hxjava
haxe --main Main --java MainJava
Cross-compile to C#
haxelib install hxcs
haxe --main Main --cs MainCS
cross-platform compilation/execution
interesting mix of static/dynamic (based on target platform)
and games?
https://mint-lang.com/
"programming language for writing single page applications"
incorporates HTML, CSS, JS into one unified language
written in Crystal
Hello world
component Main { fun render : Html { <button> "Click ME!" </button> } }
Counter component
component Counter { state counter = 0 fun increment { next { counter: counter + 1 } } fun decrement { next { counter: counter - 1 } } fun render { <div> <button onClick={decrement}>"Decrement"</button> <span><{ Number.toString(counter) }></span> <button onClick={increment}>"Increment"</button> </div> } }
https://mint-lang.com/install
Package managers:
Homebrew/Linuxbrew: brew install mint-lang
Download the (single) prebuilt binary
Build from source: git clone https://github.com/mint-lang/mint.git
Docker:
git clone https://github.com/mint-lang/mint-docker.git
cd mint-docker
docker-compose up
mint init hello-world
Main (source/Main.mint)
<</Users/tedneward/Projects/Presentations.git/Content/Mint/code/hello-world/Main.mint NOT FOUND>>
Info (source/Info.mint)
<</Users/tedneward/Projects/Presentations.git/Content/Mint/code/hello-world/Info.mint NOT FOUND>>
Link (source/Link.mint)
<</Users/tedneward/Projects/Presentations.git/Content/Mint/code/hello-world/Link.mint NOT FOUND>>
mint start
Browse to http://127.0.0.1:3000/
Edit source/Main.mint
(or any of the other files)
Browser page refreshes
https://ui.mint-lang.com/
loads of examples
"unified UI" front-end Web language
captures services as part of the language
JS interoperability makes it play well in the Web world
integrated testing as a component (not as HTML, CSS, JS, separately)
configuration/language for full-stack web apps
builds on top of React, Node, and Prisma
ReactJS: SPA framework for browser-based UIs
Node: server-side JS execution engine
Prisma: object-relational mapper
compiler (transpiler) unifies the three
Hello world
app todoApp { title: "ToDo App", // visible in the browser tab auth: { // full-stack auth out-of-the-box userEntity: User, methods: { google: {}, gitHub: {}, email: {...} } } } route RootRoute { path: "/", to: MainPage } page MainPage { authRequired: true, // Limit access to logged in users. component: import Main from "@client/Main.tsx" // Your React code. } query getTasks { fn: import { getTasks } from "@server/tasks.js", // Your Node.js code. entities: [Task] // Automatic cache invalidation. } entity Task {=psl ... psl=} // Your Prisma data model.
https://wasp-lang.dev/docs/quick-start
Curl/shell: curl -sSL https://get.wasp-lang.dev/installer.sh | sh
(No package manager support yet)
Create the project
wasp new TodoApp
Start the server
cd TodoApp; wasp start
Browse to http://localhost:3000
full-stack web application language
capture routes, types, "screens" all in one place
validation of application flow/constructs
easier reuse of constructs/components
There's a whole crop of interesting new languages out there
Many of these aren't ready for production use
but some are oh, so close...
All of them present some fascinating new ideas
... some of which you might want to steal (!)
If one of these doesn't get your motor running...
Odin: data-oriented systems programming
https://odin-lang.org/
Zig: statically-typed compiled metaprogrammaing
https://ziglang.org/
Fantom: static and dynamic typing actor concurrency
https://fantom.org/
Red: homoiconic high-level (CLI and GUI)
https://www.red-lang.org/
Wyvern: type-specific languages
http://wyvernlang.github.io/
Jolie: service-oriented programming
https://www.jolie-lang.org/
Idris: purely-functional type-driven development
https://www.idris-lang.org/
Nim: statically-typed compiled dependency-free
https://nim-lang.org/
Unison: statically-typed, content-addressed
https://www.unison-lang.org/
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)