gluonscript

A dynamically typed language with the bare minimum features to be enjoyable and simple to use.

Features

  • Minimalist but ergonomic and consistent syntax
  • Lists (immutable Python-like lists)
  • Records (immutable Javascript-like objects)
  • First-class functions
  • Lambdas
  • Closures
  • Function pipe operator
  • Easy collection iteration
  • Functions that might fail return { “error”: Bool, “value”: Value }
  • One single way to do things
  • Rich built-in std library
  • Balanced imperative/functional style
  • Ideal for new and experienced programmers
  • Implemented in Rust taking advantage of its ownership model (no GC)

Examples

Example 1

io = import("io")

fn generic_operation(a, b, operation) {
    operation(a, b)
}

sum = fn(x , y) { x + y }
sub = fn(x , y) { x - y }
mul = fn(x , y) { x * y }
div = fn(x , y) { x / y }

operations = [sum, sub, mul, div]

for operation in operations {
    result = generic_operation(4, 2, operation)
    io.println(result)
}
Output:
6
2
8
2

Example 2

io = import("io")

fn even_odd(numbers) {
    even = []
    odd = []
    all = []

    i = 0
    while i < len(numbers) {
        if numbers[i] % 2 == 0 {
            even = append(even, numbers[i])
        } else {
            odd = append(odd, numbers[i])
        }

        i += 1
    }

    all = append(all, even)
    all = append(all, odd)

    return all
}

numbers = [1, 2, 3, 4, 5, 6]

io.println(even_odd(numbers))
Output:
[[2, 4, 6], [1, 3, 5]]

Example 3

conv = import("conv")
io = import("io")

# Define a function that "updates" a user (records are immutable).
fn birthday(user) {
    return {
        name: user.name,
        age: user.age + 1
    }
}

# Create a record.
user = {
    name: "Vasco",
    age: 44
}

io.println("User:")
io.println("Name: " + user.name)
io.println("Age: " + conv.string(user.age))

# Create a new updated record.
updated = birthday(user)

io.println()
io.println("After birthday:")
io.println("Name: " + updated.name)
io.println("Age: " + conv.string(updated.age))
User:
Name: Vasco
Age: 44

After birthday:
Name: Vasco
Age: 45

Example 4

env = import("env")
http = import("http")
io = import("io")
strings = import("strings")

fn get_weather(location) {
    # Get may fail so it returns { "error": Bool, "value": Value }.
    # The last expression is returned even without the return keyword.
    # A function returns an expression that evaluates to a value and is returned.
    http.get("https://wttr.in/" + location + "?format=3")
}

fn main() {
    args = env.args()

    if len(args) < 3 {
        io.println("Usage: weather.gs <location>")
        return 1
    }

    # The function pipe |> operator makes data manipulation easy to reason.
    location =
        args # List of all arguments passed to the program.
        |> slice(2, len(args)) # Slice the list to exclude unwanted elements.
        |> strings.join(" ") # Join elements of args to form a location string.

    result = get_weather(location)

    # By convention functions that might fail return { "error": Bool, "value": Value }.
    # Checking this record for an error is a common pattern in gluonscript.
    # If error is true, value shows its message as a string.
    # Otherwise if error is false, value shows whatever value the function returns.
    # This is similar in spirit to what languages like Go or Rust do.
    if result.error {
        io.println("Could not fetch weather: " + result.value)
    } else {
        io.print(result.value)
    }
}

main()
Output:
lisbon: 🌦   +14°C

This site uses Just the Docs, a documentation theme for Jekyll.