Busy Developer's Guide to Next-Generation Languages

ted@tedneward.com | Blog: http://blogs.tedneward.com | Twitter: tedneward | Github: tedneward | LinkedIn: tedneward

Objectives

In this presentation, we're going to

Objectives

Our list

Objectives

Our list

Objectives

NOTE

The Crystal Programming Language

... in a nutshell

The Crystal Programming Language

What is this?

The Crystal Programming Language

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

Getting Started with Crystal

From 0 to HelloWorld

Getting Started with Crystal

Installation

Getting Started with 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

Analysis

Why Crystal?

The Julia Programming Language

... in a nutshell

The Julia Programming Language

What is it?

The Julia Programming Language

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

The Julia Programming Language

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> 

The Julia Programming Language

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

Getting Started with Julia

From 0 to Hello World

Getting Started with Julia

Installation

Getting Started with 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> 

Getting Started with Julia

Some interesting CLI switches

Analysis

Why Julia?

The Io Programming Language

... in a nutshell

The Io Programming Language

What is this?

The Io Programming Language

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)
)

The Io Programming Language

A Card system (pt 2 of 2)

Deck show
Deck shuffle
Deck show
    
Deck dealCard println
Deck dealCard println
Deck dealCard println

The Io Programming Language

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;
}

Getting Started with Io

From zero to Hello World

Getting Started with Io

Installation

Getting Started with Io

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> 

Analysis

Why Io?

The Flix Programming Language

... in a nutshell

The Flix Programming Language

What is this?

The Flix Programming Language

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
}

The Flix Programming Language

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

The Flix Programming Language

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)
    }

The Flix Programming Language

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

Getting Started with Flix

From 0 to HelloWorld

Getting Started with Flix

Installation

Getting Started with Flix

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

Getting Started with Flix

Docs

Analysis

Why Flix?

The Pony Programming Language

... in a nutshell

The Pony Programming Language

What is this thing?

The Pony Programming Language

Other notes

The Pony Programming Language

Producer-Consumer

The Pony Programming Language

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.")

The Pony Programming Language

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

The Pony Programming Language

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

The Pony Programming Language

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

The Pony Programming Language

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

The Pony Programming Language

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

Getting Started with Pony

From 0 to HelloWorld

Getting Started with Pony

Installation

Getting Started with Pony

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

Analysis

Why Pony?

The Ballerina Programming Language

... in a nutshell

The Ballerina Programming Language

What is this thing?

The Ballerina Programming Language

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}
    ];

The Ballerina Programming Language

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;
    }
}

Getting Started with Ballerina

From zero to hello world

Getting Started with Ballerina

Try Ballerina

Getting Started with Ballerina

Installation

Getting Started with Ballerina

Learning Ballerina

Getting Started with Ballerina

Generating a new package

$ bal new greeter

Getting Started with Ballerina

Ballerina Syntax

Getting Started with Ballerina

Hello, Ballerina

import ballerina/io;

public function main() {
    io:println("Hello, World!");
}

Getting Started with Ballerina

Ballerina Semantics

Getting Started with Ballerina

Running Ballerina

Getting Started with Ballerina

Run

bal run greeter

Compile and run built JAR

bal build greeter
java -jar greeter/target/bin/greeter.jar

Getting RESTful

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; 
    }
}

Getting RESTful

Running

$ bal run

Client access

$ curl localhost:8080/greeting
Hello, World!
$ curl localhost:8080/greeting/Ballerina
Hello Ballerina

Getting Cloudy

Build a Docker

Getting Cloudy

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

Getting Cloudy

Run the Docker container

$ docker run -d -p 8080:8080 tedneward/restgreeter:v0.1.0

Analysis

Why Ballerina?

The Wing Programming Language

... in a nutshell

The Wing Programming Language

What is it?

The Wing Programming Language

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);
});

Getting Started with Wing

From 0 to HelloWorld

Getting Started with Wing

Installation

Getting Started with Wing

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

Analysis

Why Wing?

The Haxe Programming Language

... in a nutshell

The Haxe Programming Language

What is this?

The Haxe Programming Language

Feature list

Getting Started with Haxe

From 0 to HelloWorld

Getting Started with Haxe

Installation

Getting Started with Haxe

Hello world: Main.hx

class Main {
    static public function main():Void {
        // Single line comment
        trace("Hello World");
    }
}

Getting Started with Haxe

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

Analysis

Why Haxe?

The Mint Programming Language

... in a nutshell

The Mint Programming Language

What is it?

The Mint Programming Language

Hello world

component Main {
  fun render : Html {
    <button>
      "Click ME!"
    </button>
  }
}

The Mint Programming Language

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>
  }
}

Getting Started with Mint

From 0 to HelloWorld

Getting Started with Mint

Installation

Getting Started with Mint

Generate a new project

Getting Started with Mint

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>>

Getting Started with Mint

Run the dev server

Getting Started with Mint

Hot reload

Getting Started with Mint

Mint UI Library

Analysis

Why Mint?

The Wasp Programming Language

... in a nutshell

The Wasp Programming Language

What is this thing?

The Wasp Programming Language

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.

Getting Started with Wasp

Getting Started with Wasp

Installation

Getting Started with Wasp

Create the project

wasp new TodoApp

Start the server

cd TodoApp; wasp start

Browse to http://localhost:3000

Analysis

Why Wasp?

Summary

What have we learned?

Summary

By the way... there's more!

Summary

By the way... there's more!

Credentials

Who is this guy?