Siko Programming Language

Posts

Traits and instances

This post will explain how the trait system and instance resolution works in Siko. Siko uses traits for describing interfaces, they can be used to constrain generic types in generic functions. Here is a sample trait:

trait Foo[T] {
  fn foo(self) -> ()
}

This trait expresses that whatever type has an instance for this trait, that type will have a foo method that returns an empty tuple. To be able to use the trait in practice you need to add instances for types.

Implicits and effect handlers

Siko now supports implicits and effect handlers. Because it may not be obvious what these features do and more importantly how they are implemented, we will look into them using a simple teletype example. Without much further ado, let’s dive into the code. Here is the full example and we will explore it in detail afterwards.

module TeleType {

pub effect TeleType {
  fn readLine() -> String
  fn println(input: &String)
}

pub fn run() {
  while True {
    let input = readLine();
    if input == "exit" {
      break;
    }
    println("You said: " + input);
  }
}

}

module Main {

import TeleType as T

implicit mut state: Int

fn mockReadLine() -> String {
  if state < 3 {
    state += 1;
    "mocked: ${state}"
  } else {
    "exit".toString()
  }
}

fn mockPrintln(input: &String) {
  let expectedString = "You said: mocked: ${state}";
  assert(expectedString == input);
}

fn testTeleType() {
  let mut state = 0;
  with T.println = mockPrintln,
     T.readLine = mockReadLine,
     state = state {
    T.run();
  }
}

fn realTeleType() {
  println("Starting teletype");
  with T.println = println,
       T.readLine = readLine {
    T.run();
  }
}

fn main() {
  testTeleType();
  realTeleType();
}

}

The example program defines a single TeleType effect that allows for reading and writing to the console in a controlled manner. The effect definition looks similar to a trait definition because it acts as an interface but in contrast to instances (the trait implementations), effects are not handled globally, their actual implementation is context dependent. The execution context of a code block determines how the effect is handled. In other words, the effect acts as a hole in the program, allowing the caller to control what happens when an effect is called. Because Siko is a low level programming language, it does not have a language specific runtime, it does not do stack juggling in a way that you would expect if you heard about algebraic effects previously.

Siko language redesign

For those who encountered Siko before and for some reason still remember it, you may have noticed that the language has undergone some significant changes. The goal of this redesign is to improve usability, performance, and overall developer experience. Both visually and semantically, the language is now an imperative language.

module Main {

fn main() {
  println("Hello, Siko!");
}

}
GitHubDiscord