Slang: Review of 2012

Already the first quarter of 2013 is behind us, but I wanted to take a look whether I accomplished the goals I set for Slang development in 2012. I’m not going to reiterate the goals here, but almost none of them were completed.

I wanted to bring the language into a usable form, but so far there is still a lot of work to do. I wanted to make the compiler open source, but I’m still not sure at which point I would like to do that. I think I will postpone that quite a bit, because I don’t have the time to run an open source project at the moment (and parts of the compiler are still full of horrible hacks). Actually, lack of development time was one of the things that prevented me from fulfilling the goals. I worked on Slang mostly during vacations and when I found a drive to start work during other times I would continue for a couple of weeks and then take a break for a few months.

I am suspecting that development will continue at a similar pace. I have made some progress, though, sporadically during 2012 and more continuously during the last few weeks.

New Parser

I think I spent most of my Slang development time last year on the new parser, using the mixfix parser combinators I blogged about (sorry, I kind of forgot to post the third part of that). I have improved the parser framework a lot since then, but it does have a downside of being quite slow for large programs, even with Packrat parsers. So I have some further work to do here, like maybe replacing the whole parser again, but I will probably leave that to some unknown future date.

Custom Operator Precedence Rules

The new mixfix parser theoretically enabled a modular grammar: the default grammar can be relatively small, but programs could define their own prefix, postfix, infix and closed operators and their precedence rules. And recently, I made that actually work. You still can’t quite define a grammar per Slang source file, but you can add operator graph (.ops) files to the list of compiled files and together with the standard rules, they will define the grammar for that compiler run. Some examples.

New Compiler Infrastructure

I just finished the initial work on this, a step towards separate compilation: instead of including library code into the source file being compiled, now the new Slang compiler driver can compile multiple source files at the same time, but still requires that the library sources are available. The end result is linked together with the LLVM IR linker.

Slang IDE

I started work on an Eclipse-based Slang IDE. Currently it includes syntax highlighting, error reporting, a few quick fixes, and quick-assist for rewriting expressions to use different aliases of methods. E.g. if you write x.times(y) you can then click Ctrl+1 and select “Use alias: *”. Then the expression will be rewritten to x * y. This is much more useful if you have Unicode operators that can’t be easily typed. Another example: you write array(1), Ctrl+1 suggests “Use alias: subscript” and selecting it turns the expression into array₁

The IDE also shows warnings and errors with squiggly lines, and I added a few more useful warnings to the compiler and improved the messages.

Debugging

This is still in progress, but for some programs, Slang compiler can now emit DWARF debug info, and the programs can be debugged using the GNU Debugger. I was quite pleased to get that working, and together with the IDE, and new compiler driver, it has made Slang much more usable for myself.

Next Steps

This time, I don’t want to give any deadlines, but the next steps are to make the tooling more usable, improve error messages, add some of the language features I didn’t get to add in 2012, etc. I think I might even release a build in the form of the Slang IDE with the compiler embedded, even if it will not be open source.

I have various language features in mind that I want to explore, such as proper generic types, some form of dependent types, Strings, IO, better interoperability with C, JVM back-end. Strings and IO are pretty much given, and generics as well. Not sure how soon I’ll get to the other things.

I think I will pretty much be doing pain-driven development: what is currently giving me most pain will get fixed first. I think actually generics might be the thing, because adding collection methods for only a specific type of arrays is no fun.

Advertisements

Syntax Matters in Slang

This post was inspired by Ola Bini’s notes on syntax. I agree with most of Ola’s thoughts. I’m not convinced that repetition aids reading or improves syntax, and think that optimising syntax for writing is mostly irrelevant. I might agree less about the familiarity of syntax. I would love it if people, including me, were more open to trying languages with unfamiliar syntax, but the familiarity is important to many on some level.

Some of these thoughts form the basis for Slang’s syntax. I’m not quite ready to define The Zen of Slang, but I can give a shot to stating some of the underlying principles behind its syntax:

  • Reading code is an order of magnitude more important than writing code
  • You should still be able to type a lot of code quickly in any text editor
  • Concise is good, repetition is bad
  • There can be multiple ways to write the same thing, but one way should be canonical
  • Familiarity is good, in this case with:
    • Scala
    • to a lesser extent, other curly brace languages
    • mathematical notation

How these goals actually effect the syntax deserves more explanation

Reading > Writing

We read code more than we write it, and reading is more important. I hope this is accepted by everyone nowadays and I’m not going into why. But how to optimise for readability is another question, and probably highly subjective. In Slang, I am experimenting with syntax that I think is readable, but that might not be always easy to write.

Slang makes very few restrictions on what Unicode characters are allowed in identifiers — I believe that well-known mathematical operators in code that deals with maths are more readable than English words. The ability to write close to mathematical notation in many cases is enhanced by limited mix-fix operator support, but this is really less about syntax and more about libraries. Slang’s standard libraries will prefer well-known mathematical operator symbols instead of word-based method names.

A thing I really love about Scala’s syntax is the ability to define one-line methods without using curly braces.

def +(v: Vector2) = Vector2(x + v.x, y + v.y)

I’d find it incredibly distracting for readability if there were curly braces around this or if the method body was on a separate line due to code conventions. For me, such one-liners and even multi-line single-expression methods are important.

def sum(xs: [Int]) =
  loop(i := 0, acc := 0) while i < #xs do
    (i + 1, acc + xsᵢ)
  yield acc

Many methods that are based on loops can conveniently be implemented as a single loop expression because Slang doesn’t have mutable local variables (at least not yet) that would be defined in a code block, but instead prefers “anonymous recursion” for computing varying values. while is syntax sugar for making that construct more concise. There is just one loop construct, where other languages would have for loops, tail recursion, while loops, or do while loops. It’s likely that I’ll add a ‘for each’ construct, though.

There are other things to consider when thinking about code readability, but that could be a whole post or series of posts on its own.

Writing cannot suck!

Typing Unicode symbols is not easy. The solution I use regularly is to have often-used symbols in a text file, and copy them from there when needed, or to search in a Character Map application (there’s a good one in Ubuntu). This slows down writing, which often doesn’t matter if you spend more time thinking than writing anyway.

But sometimes you still want to type fast, and for that, Slang’s library will have ASCII aliases for every non-ASCII identifier. You can write ASCII names instead of Unicode symbols and replace them later when a code snippet is complete and tested. In the future, an IDE should know what the canonical forms are and do the replacement automatically.

This means there will effectively be two ways of writing many programs. Some language designers would consider multiple ways of doing things bad, but in Slang I allow it with no regrets — this comes from the desire to achieve a balance between the goals “Reading > Writing” and “Writing cannot suck!”.

Repetition is bad and multiple ways of writing things

Ok, I mentioned that non-ASCII symbols always have ASCII aliases (in fact it is mostly vice versa). Consider the following:

class Boolean {
  def xor(that: Boolean) = // intrinsic operation
  def ⊻(that: Boolean) = xor(that)

  // Methods ending with … are prefix operators
  def not…() = true ⊻ this
  def ¬…() = true ⊻ this
}

In the above code, we create aliases by either duplicating definitions (not, ¬) or defining similar methods where the aliases call the “canonical” method (xor, ). There is repetition in both cases and potential performance issues in the latter case if methods are not in-lined. It is how most widely used languages allow aliasing, because they are not too concerned with providing multiple ways of doing things. But Slang is concerned with that, because it helps deal with the above-mentioned tension between reading and writing. So Slang makes aliases explicit:

class Boolean {
  def xor(that: Boolean) = // intrinsic operation
  def not…() = true ⊻ this

  alias ⊻ = xor
  alias ¬… = not…
}

The repetition is gone — to define an alias, we only define its name and the name of the aliasee. Right now only simple identifiers may be aliased, but I might allow more complex cases later.

If you don’t like the aliases Slang provides for the standard types, you could define your own:

extending Boolean {
  alias `no way!` = not… // I hope nobody will actually do this :)
}

Now you can write: if collection.isEmpty.`no way!` then ...

As you can see, even spaces are allowed in identifiers, as long as the identifier is surrounded by back-ticks (same as in Scala). We can’t use the `no way!` alias as a prefix operator, though, because Slang currently allows only certain operator symbols to be prefix instead of infix. I might add user-defined precedence/fixity rules later, but not totally sure about that.

Now, I hear alarm bells sounding in some readers’ heads already. How come I’m willing to give potential Slang programmers so many tools to shoot themselves in the foot? Because I want to believe that most programmers are not stupid and the usefulness of this in the hands of smart people outweighs the negative sides.

Similarly to term aliases, there are type aliases:

type SDL_Rect = (x: Short, y: Short, w: Short, h: Short)

Familiar is good

I don’t have a whole lot to say about this, as things are not yet set in stone. I really like most of Scala’s syntax and I want to stick to something similar for the most part. Significant whitespace would be an interesting experiment, but I’m not sure if it’s a clear improvement over curly braces, which are familiar to the vast majority of programmers. Mathematical notation is complex, and varies between different fields of mathematics, blackboard and paper, and so on. But there is a part of it that is commonly understood and I would like to make some subset of that usable in Slang, although slight differences in syntax might be necessary.

Some examples:

∃! xs , x -> x == 3 // there exists only one x in xs where x == 3
2 ∈ xs // 2 is an element of xs
5 + ∏ xs // 5 + the product of xs
∛(27) + |-3| // cube root of 27 + absolute value of -3

// definition of for all on an array of integers
extending [Int] {
  def ∀…,…(ƒ: (Int) → Boolean) =
    loop(i ≔ 0, z ≔ true) while z ∧ i < #this do
      (i + 1, z ∧ ƒ(thisᵢ))
    yield z
}

You may have noticed

  • quantifiers (for all, exists etc.). For this purpose I allowed comma to be used in a few special identifiers: ∀…,… ∃…,… ∄…,… ∃!…,…
  • subscripts can be used to index into arrays and other indexed collections
  • Unicode aliases like ∧, ≔ and →
  • ∏… as a prefix operator
  • |…| as a closed operator

These all actually translate to method calls such as

xs.∃!…,…((x: Int) -> x == 3)
2.∈(xs)
5.+(xs.∏…())
∛(27).+(3.-…().|…|())
this.#…()
this.subscript(i)

Conclusion

Syntax is quite important in Slang. I’m not designing it syntax-first, but syntax weighs into most considerations. I think the syntax as a whole will be somewhat familiar to many, being similar to Scala and a couple of other recent JVM languages.

The language is optimised for reading, mostly by allowing concise method definitions, a large range of Unicode characters in identifiers, but also by having some support for mix-fix operators. Aliases to Unicode symbols allow fast writing as well, and the alias definitions are made explicit in code. Lots of aliases allow one to write the same program in multiple ways, but in the future, there might be IDE support for “normalising” the syntax.

There are some new things here as well, or at least things that the vast majority of languages don’t have. One is the translation of subscript and superscript characters to their normal equivalents. Another is the loop construct, which is basically anonymous recursion similar to some functional language constructs. It turned out more flexible than I thought, and I’d like to write another post about that, soon.

Slang language goals for 2012

I’m setting myself some goals for the Slang language (I’m renaming Klang to Slang) for the coming year. By the end of 2012 I should have

  • a usable and useful language
    • programs must not crash, unless you purposefully make them crash
    • compiler must always provide nice error messages (and not crash)
    • must be able to do IO
    • must be able to do OpenGL
    • must have a small standard library
      • IO, Unicode strings, basic collections
      • parser combinators (maybe)
  • programs that are mostly pure by default, except when they’re not (doing IO etc.)
  • allocation in pools or a garbage collected heap
  • performance mostly on par with C
  • open source compiler written in Scala
  • a comprehensive test suite
    • all language features must have tests
    • all library functions must have tests
    • all compiler errors and warnings must have tests
    • some use case tests, maybe a Project Euler based test suite
  • all the things mentioned in the post where I outlined the first language (most of those exist already)

There are a few additional things that would be nice to have, but are not my explicit goals for the year. The first is a self-hosting compiler. The current compiler spews out .ll files, which then get parsed and compiled by LLVM tools such as llc, but it would be nice to work with LLVM directly. Another thing is separate compilation, which I’m probably not going to implement in the current compiler. Same goes for JIT. And lastly: support for debugging; syntax highlighters; maybe a bare-bones Eclipse IDE.

I should be able to pull off the things listed here, some sooner and some later. I still have a lot to learn about language design, type systems and compilers and am not sure at which point I’m going to open source it, but I’m aiming for June 2012 or so.

Klang: How To Solve Overloading?

I haven’t had much time to work on Klang since my vacation ended, but I’ve been thinking about how to solve overloading. Note that this post contains pseudo-code that bears resemblance to, but is not actual Klang code — these are just thoughts so far.

Given types Double and Vector2(x: Double, y: Double), there are mathematical operations that take both types as operands in different combinations, but have the same name. For example, multiplication:

a: Double * b: Double = // intrinsic operation a * b
a: Double * v: Vector2 = Vector2(a * v.x, a * v.y)
v: Vector2 * a: Double = Vector2(a * v.x, a * v.y)

Solution 1: Allow overloading of class methods

package klang
class Double {
  def *(that: Double) = // intrinsic this * that
}

package vecmath
extending Double {
  def *(v: Vector2) = Vector2(this * v.x, this * v.y)
}

Solution 1a: Allow overloading of package level functions

package klang
def *(a: Double, b: Double) = // intrinsic a * b

package klang.vecmath
def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)

Solution 2: Allow for Haskell-style type classes

package klang
typeclass Multiplication[A, B, C] {
  def *(a: A, b: B): C
}
instance Multiplication[Double, Double, Double] {
  def *(a: Double, b: Double) = // intrinsic a * b
}

package klang.vecmath
instance Multiplication[Double, Vector2, Vector2] {
  def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)
}

Pros and Cons

The first solution of allowing method/function overloading as in Java or Scala will certainly complicate things, especially when I introduce some form of inheritance (currently there is none). However, I’m not sure the second method, which is more like the Haskell way of handling overloading, is any better. Especially the third type class argument (return type) will be confusing: am I then allowed to also provide an

instance Multiplication[Double, Vector2, String]

which differs only in the last argument. Obviously it shouldn’t be so: if selecting a type class instance based on method return type was allowed, that wouldn’t work with Klang’s Scala style type inference. Maybe the type class could have an abstract type member instead:

typeclass Multiplication[A, B] {
  type Result
  def *(a: A, b: B): Result
}
instance Multiplication[Double, Vector2] {
  type Result = Vector2
  def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)
}

But I haven’t really decided whether to even have type classes or type members. There seems to be a lot more ceremony required with type classes compared to simply allowing overloading methods or module-level functions. And I’m not sure if that provides any real advantage…

I could say that defining a function *(a: Double, b: Vector2) creates an implicit type class *[A, B] and an implicit instance of it *[Double, Vector2]. It would be equivalent to the manually defined type classes, wouldn’t it? Except in the manual case you could put division into the same type class with multiplication, but that would still require more ceremony than simple overloading.

And what of functions like max(a: Double, b: Double) and max(a: Collection[Double])? It would be nice to be able to do have the 2-argument version for performance reasons. Type classes wouldn’t necessarily solve that unless one could abstract over method argument arity.

I should probably read more literature to make better informed decisions about these things, just haven’t gotten around to those parts yet :)

What do you think? Do you have an opinion about which way to go or any pointers to reading material?

Klang: Classes and Math Notation

Just got started with adding classes to Klang. At the moment, only immutable classes can be created and there is no inheritance.

The fields and methods are more separated than usual — the data is defined in the beginning of the class body as a single tuple type. On the other hand, there is a uniform access principle and both field accesses and method calls are represented the same way internally and in syntax. Actually the field access is implemented similarly to an intrinsic method call. Intrinsics in Klang usually translate to a single LLVM instruction and I’m going to expose some of them to users as well.

Here’s a sample program with a class:

class Vector2 {
  data (x: Double, y: Double)

  // other methods skipped

  def +(v: Vector2) = Vector2(x + v.x, y + v.y)
  def length() = √(x² + y²)

  alias |…| = length
}

def computeVectorLength(): Double = {
  val v1 := Vector2(1, 1)
  val v2 := Vector2(2, 3)
  | v1 + v2 |
}

def main() = computeVectorLength().toInt

Vector2 is a class whose data is represented as (x: Double, y: Double). Reusing tuples again :) The compiler also generates a no-op function named Vector2 that takes the same tuple type and returns an instance of the class. It’s a no-op because the instances of classes are still held in LLVM registers (LLVM has an infinite number of registers) simply as the data they represent.

Mathematical syntax

There is also some nice syntax resembling mathematical notation in the example. I want to allow as much mathematical syntax as can be represented in plain Unicode text, but also provide aliases for those who prefer plain English words. I took some ideas from Fortress, but I don’t want to go into that double-syntax stuff where the written syntax is weird, but can be rendered into readable mathematical notation.

I defined some specific characters as left/right braces that when surrounding an expression get turned into a specially named method call on that expression:
| v1 + v2 | is turned into (v1 + v2).|…| (the ellipsis is a single character, not three dots).

Unfortunately, I think using | as a left/right brace makes it hard to use | in the or meaning or allowing it as a regular identifier. Maybe it’s possible, but I’m not yet good enough with grammars to know for sure. Anyway, I think actual words and and or might be better than & and |. Certainly ^ as xor doesn’t make much sense. Of course, since I want to enable mathematical syntax, , and are aliases for and, or and xor as well.

The above code example doesn’t actually parse yet — until I improve the parser and the lexer, there is some additional spacing and parentheses needed. For example √((x ²) + y ²) would compile.

If you know any programming languages which are good at mathematical notation in plain text, let me know in the comments.

Klang: Program Structure

I thought I’d keep my posts about Klang, the language I’m designing, shorter (at least I’ll try). So in this post I’ll describe the overall program structure and just a few constructs, focusing more on current status rather than goals.

Version 1 of the Klang compiler is going to be pretty basic. I’m not even sure if it’ll have separate compilation (well, it kind of does have that via externs). As I started moving some stuff from the compiler into a library, I just made it prepend the library source code to the source being compiled. So at least right now, the compiler takes just one source file (or string) and turns it into a single LLVM assembly module (.ll file), which can in turn be compiled to machine code using the LLVM toolchain.

Functions

A Klang module is currently made of function definitions and function declarations (externs). Classes will come later. A function named main is the entry point, as usual. A Hello World program in Klang might look like this:

// puts is defined in the C library
extern puts(string: Byte *): Int
def main() = puts("Hello, World!")

Byte * is a pointer to a Byte, but I added pointer types only as a quick hack to interface with native libraries. I might keep them for that reason, but limit their use to extern declarations — extern declares a function defined in another module.
You probably noticed that functions are defined similarly to Scala.

'def', name, argument list, '=', body expression

Expressions

In Klang, like in Scala, most things are expressions i.e. evaluate to a value. Here’s what the mandatory naive Fibonacci example looks like:

def fib(n: Int): Int =
  if n == 0 then
    0
  else if n == 1 then
    1
  else
    fib(n - 2) + fib(n - 1)

Specifying the return type is necessary here because the function is recursive, and the type inferencer can’t handle that. if is an expression, so both the then and else branches must be of the same type. An if without an else would evaluate to (), the empty tuple value, also known as Unit. It is similar to void, except void is the lack of a value.

def addOneThenSquare(n: Int) = {
  val nPlus1 := n + 1;
  nPlus1 * nPlus1
}

A block is a list of statements surrounded by { and }. Statements are usually separated by semicolons because the current parser is a quick hack implemented with parser combinators and can’t do the semicolon inference well. The statements can be definitions as well as expressions, but the last statement is what is returned and needs to be an expression.

val starts a local value definition. Local values cannot be reassigned after they are defined. I want to avoid mutable local variables for as long as I can, though in the end I will probably have to add them. := is perhaps an unusual choice for assignment and I might revert to using = for that instead.

Loops

I haven’t even implemented Arrays yet, but loops are still useful, especially as there are no tail calls yet and the Fibonacci function above would probably exit with a segmentation fault for a large value when the stack grows too big. But how do you do loops without mutable variables? I’m talking about primitive loops that must be the basis for other constructs such as comprehensions. I thought about it for a couple of days and came up with something like this (there are probably similar constructs in other languages):

def helloHello(n: Int) =
  // loop takes a tuple of parameters similar to a function argument list
  // but it must always specify default (starting) values
  loop(i := 0)
    // and also an expression that ends with continue(...) or break()
    if (i < n) then {
      puts("Hello?");
      // continue "calls" the loop again with the new values
      continue(i + 1)
    } else {
      // break returns from the loop
      break()
    }
  // yield can see the *last* values of the loop parameters
  yield i

def main() = helloHello(3)

This program will print “Hello?” three times and return 3. But this kind of loop seems very verbose and actually what it does is similar to tail recursion, using LLVM’s Phi nodes. I might rethink what kind of loops to have in the future, but for now I’ll stick with this. It can be simplified a bit:

def helloHello(n: Int) =
  loop(i := 0) while (i < n) {
    puts("Hello?");
    i + 1
  } yield i

There are some potential programming errors that can easily arise from this kind of loop, but I’ll talk about that later (or maybe you can guess).

while can only come directly after loop(...) and is defined in terms of if, break and continue:

while (condition) expression = if (condition) continue(expression) else break()

This translation is done immediately after parsing, to simplify the compiler phases.

With these constructs, and passing functions around, one could already write a program that does something a little bit useful. I think my next focus is on adding Strings and Arrays into the mix, but my next post will probably go more into functions and tuples.

My Language Experiment

Last time I posted about how it came to be that I started designing a new programming language and writing a compiler for it. I think I should continue by explaining a bit about how I started the project, how I’m implementing the compiler, and describe the project’s goals and the language I want to create.

About the same time I started having ideas of a more high-level object-functional language allowing a data-oriented programming style and more close-to-machine runtime than the JVM, Geoff Reedy‘s Scala on LLVM appeared. I think that’s a really interesting project and I hope it turns into something awesome. But I think that is not quite what I was looking for, because it still needs the Java libraries and must carry some of the baggage that comes from the Scala/Java interoperability (such as null).

But LLVM caught my attention as I had been hearing more and more about it. I went through the Kaleidoscope tutorial and shortly had my mind set that LLVM would be the library/toolset I would use as the back-end of my compiler to output machine code. By the way, I suggest that anyone who is new to implementing compilers like me should try that tutorial — it takes about a day to get through and in the end you have a simple toy language with a basic REPL and JIT.

I tried to continue adding stuff to Kaleidoscope, but realized yet again that I really don’t like C++ (which is what the tutorial used). I found no Java bindings for LLVM, so I thought to learn a language that has bindings: Haskell. I Learned me a Haskell, or part of it. It is another awesome language, but the syntax and purity scares me a bit and I just couldn’t imagine being as comfortable writing Haskell as I am when writing Scala. So, back to Scala. I initially thought to output LLVM Bitcode from Scala, but after reading some docs, it seemed easier to generate LLVM assembly text files (.ll), similarly to the Scala LLVM project (I even reused some bits of code from there). And indeed, it was much easier getting something running that way, and that’s how I’ll implement the first compiler.

But lets talk about the language and the project goals as well. Actually, I want to split this project into separate phases.

  • The first phase is to create a relatively simple language that has a nice Scala-like syntax.
  • The second phase is trying out various designs and implementations based on that small base language.
  • The third phase, if I get that far, is at the moment an Unknown, trying to take what I’ve learned in the previous phases and try to apply that to actually implement the language I want.

At some point, I will try to bootstrap a compiler in the language itself. The project might end up creating yet another esoteric language, but I hope it will turn out to have some usefulness.

The separation into phases is necessary because I still have a lot to learn and don’t want to rush into creating a full-blown general programming language. And also because I don’t want to think too far ahead at the moment. I started reading some books on programming languages and compilers: Programming Language Pragmatics for the introduction, next will be the Dragon Book and Types and Programming Languages (thanks to Daniel Spiewak for the suggestions). I have a lot of theory to go through and progress may be slow.

The language from the first phase is codenamed

Klang

The name comes from Kaleidoscope + language (no relation to Viktor Klang :)), because Kaleidoscope was what I started with, although I altered the syntax to be more like Scala. What features will make it into Klang is not yet set in stone, but I’ll list some of them and describe the language in more detail in the next post, because this one is already pretty long. Anyway, some of the intended features

  • A Scala-like (but not always identical) syntax
  • Type safety
    • Type inference (somewhat similar to Scala’s)
  • Functions
    • Named and default arguments
    • Passing functions as arguments to other functions
    • Implicit conversions (but they can’t be used for pimping)
    • Anonymous functions
    • Extern function declarations (for linking to native C libraries)
  • Primitive types: Byte, Short, Int, Long, Float, Double, Boolean
    • Considering having Byte be unsigned, but not sure
  • Tuple types with optionally named elements
    • function argument lists are tuples
      • can call a function with any expression that returns a tuple (if the argument list matches)
    • multiple named return values from functions
  • Arrays and UTF-8 Strings
  • Blocks and local values (no mutable local variables)
  • Control structures
    • If expressions
    • Some kind of for-loop like structure, specifics not decided yet
    • && and ||
  • Packages or namespaces
  • A tiny standard library
  • … maybe a few more things

A feature that will probably not make it is polymorphism. There will likely not be an Any or Object type that all other objects inherit from. And you will not be able to ask for the type of a value at runtime.

At least the above is roughly what I think will be in the first version of Klang. Once that version is done, I might make it available on Github under some liberal license. More in the next post.