Sylan

Fork me on GitHub

Sylan is an experimental programming language project to investigate what a spiritual successor to Java and C# might look like.

Example

#!/usr/bin/env sylan

// If no package is specified, "main" is assumed.
package main

import sylan.io.{println, print}
import sylan.datetime.ZonedDateTime

// Package items like functions and classes are private to the package if
// prefixed with an underscore.
//
// This also works with fields in classes and methods in classes and interfaces.
void _demoIteration() {
    List(1, 2, 3).forEach(n ->
        println(`{n}`)
    )

    var highlight = s -> `>> {s} <<`

    1.to(5)
        .map(double # ::toString # highlight)
        .forEach(println)

    var quadruple = n -> n.double().double()

    123456789
        |> quadruple
        |> ::toString
        |> highlight
        |> println

    var map = HashMap(
        "abc": 123,
        "def": 321,
        "ghi": 987,
    )
    map.forEach((key, value) ->
        println(`{key}: {value}`)
    )

    var fact = for var n = 20, var result = 1 ->
        if n <= 0 ->
            result
        else ->
            continue(n - 1, n * result)

    println(`factorial: {fact}`)
}

int factorial(int n) ->
    switch n {
        0, 1 -> 1

        default ->
            if n < 0 ->
                throw Exception("n cannot be less than 0")
            else ->
                factorial(n * (n - 1))
    }

void twice<N>(N n, N f(N)) if N: Number ->
    f(n) + f(n)

String double<N>(N n) if N: Add & ToString ->
    (n + n).toString()

Optional<int> demoContexts() ->
    do {
        var a <- Some(5)
        doSomething()
        var b <- Empty()
        willNotBeRun()
    }

package counter {

    enum Message {
        Increment,
        Reset(int),
        Get,
    }

    void start(Task sender, int n = 0) ->
        select Message {
            .Increment ->
                start(sender, n + 1)
            .Reset(n) ->
                start(sender, n)
            .Get {
                sender.send(n)
                start(sender, n)
            }
            timeout 10.seconds ->
                throw Exception("timed out!")
        }
}

interface Concatenate<T, Result = T> {
    Result concatenate(T y)
}

class Account: ToString, Concatenate<Account> {
    String firstName
    String lastName
    int ageInYears

    ZonedDateTime _expiry = ZonedDateTime.now() + 1.year

    Account(String firstName, String lastName) {
        println("instantiating an Account...")
        super(.firstName, .lastName, ageInYears = 35)
    }

    override String toString() ->
        `{firstName} {lastName} is {ageInYears} years old`

    override Account concatenate(Account a) {
        var firstName = firstName.concat(a.firstName)
        var lastName = lastName.concat(a.lastName)

        Account(
            .firstName,
            .lastName,
            ageInYears = ageInYears + a.ageInYears,
        )
    }

    String get name ->
        `{firstName} {lastName}`

    boolean get locked ->
        expiry < ZonedDateTime.now()
}

extends class Account: Concatenate<Account, Result = String> {

    override String concatenate(This that) ->
        `{firstName} {that.firstName}`
}

class Person = Account
interface Showable = ToString

int maxBound = 5

void closureDemo() {
    var x = 5

    var account1 = Account(
        firstName = "Tom",
        lastName = "Smith",
        ageInYears = 15,
    )

    var firstName = "Tom"
    var lastName = "Smith"
    var age = 25
    var account2 = Account(.firstName, .lastName, ageInYears = age)

    var f = a ->
        println(a.toString())

    f(account1)
    f(account2(firstName = "Emma"))

    var g = a -> {
        println("returning an account")
        a
    }

    var z = g(account1)

    var n = twice(3, x -> x * 2)
    println(`n == {n}`)
}

void demoNumericLiterals() {
    int a = 5
    uint b = 5
    decimal c = 10.0

    byte d = 5u8
    uint16 e = 11u16
    uint32 f = 12u32
    uint64 g = 13u64
    int8 h = 15s8
    short i = 13s16
    int32 j = 7s32
    long k = 7s64
    float l = 12f16
    double m = 8f32
}

// Top-level code is allowed, but only in the main package. Code in other packages must be in
// functions or methods.

Optional<String> optionalString = Some("test string")
if var Some(s) = optionalString ->
    println(s)

var c = Task(-> counter.start(currentTask))
5.times(-> c.send(counter.Message.Increment()))

c.send(counter.Message.Get())
c.send(counter.Message.Increment())
c.send(counter.Message.Get())

// Should print 5 and then 6.
2.times(->
    select int n ->
        println(`{n}`)
)

print("""
Multiline
strings
""")

var x = {
    println("Returning 5 to be bound as x...")
    5
}
print(`{x}`)

/*
  A multiline comment.

  /*
    A nested multiline comment.
  */
*/

Synopsis

Java and C# moved C++ application programmers away from direct memory management onto managed abstract machines with concurrency, networking, serialisation, and portability built-in.

What about the next language and runtime after Java and .NET? Better distributed and concurrent programming support would be a good starting point. Null-free types, ubiquitous immutability, a lack of concrete inheritance, built-in supervisor trees, and transparently asynchronous IO would acknowledge this era of computing.

Hardware is no longer speeding up exponentially year-on-year and is becoming increasingly parallel. Performance cannot be discarded out of hand like the rise of dynamic languages throughout the previous decade.

Large semantic changes will likely be rejected by developers if not presented in a syntax similar to existing languages; like Java took C++'s syntax, the next language should take Java's.

A gap exists between scripting languages and application languages; would enough type inference and support for features like top-level executable code and shebangs help bridge the gap?

A runtime will be needed for preemptive concurrency and light weight tasks. Go shows that compromises regarding the tasks' preemptiveness must be made in the case of native compilation.

TODO

Goals

Details

Accessibility Levels

Types

Methods and Functions

Pattern Matching

Matching in Switch and Select

Invocations

Language Versioning

Compile-time Metaprogramming

Runtime Structure Information

The Runtime

The Build System

Interoperability

Standard Library

To Consider