Creating a programming language, part 2: The Idea

Starting out

Way before I even had a functioning parser, I already had some idea for some of the features I wanted to have in the language. Most of these were ripped from languages I liked to use. Some were just things I found interesting. There were some concrete things I knew I wanted, though.

Systems programming

First of all, I wanted to make a language I would be able to use for my own future projects. This meant it would be a hard requirement that it would be usable for systems programming, e.g. it would definitely need to compile to native code. It also would need to be fast, and it would need to play nice with other languages.

Mathematical programming

The language also needed to have good semantics for mathematical programming. Which meant I wanted to be able to include user-defined operators and operator overloading. This is probably one of the bigger jumps away from the usual systems programming schtick. But the ability to easily deal with matrices, vectors and tensors would absolutely be something I wanted to allow.

int matrix_1[][] = { {1.0, 0.0, 0.0},
                     {0.0, 1.0, 0.0},
                     {0.0, 0.0, 1.0}};

// ...

int* result_matrix;

result_matrix = malloc(expected_size);

multiply_matrices(matrix_1, matrix_2, result_matrix);

This was something I absolutely wanted to avoid. C++ makes it saner, but even there, it’s not all sunshine and roses. This is partly because the usual libraries aren’t exactly shining examples of good API design. e.g. Matrix sizes are not checked compile-time, etc…

Higher use of functional ideas

There were some concepts I found in languages like Haskell, Rust and even some C++ libraries that I enjoyed. Use of monads, especially in error handling. More expression-centric semantics, first-class functions, and typeclasses. I was pretty much set on creating a functional language at this point, to the point that I started calling it a “functional low-level language”. That is still visible as all my source files have “.flow”- end.

“Zero-cost Abstractions”, RAII, versioning

I wanted to take what was good in C++ and keep it, and I had watched a lot of seminars about C++ language and its development, followed plenty of people in different channels to understand why it does things the way it does and what are other people’s ideas of improvement.

Not going to lie, Herb Sutter has been a big inspiration to the language. And if C++ came with language-level variants, pattern matching and metaclasses, Flower would not exist.

So, following the path of C++ and Rust, Flower needed to have both RAII and some emphasis on “zero-cost abstractions”. I’ve heard plenty of times that there are no real zero-cost abstractions, but well, we’ll do what we can.

Another thing I really wanted was a reasonable way to be able to change the implementations if they were insufficient. So I knew I wanted to have versioned language from the beginning. Rust has its epochs, and I find it necessary to have such a mechanism. A deep bow to Vittorio Romeo, whose paper tried to include such a mechanism in C++ as well. If that had gone through, there’s a good chance I would be working with C++ compilers instead of my own “toy” language.

A reasonably strong type system

One thing I really like about C++ is its type system. I know that might not be exactly the majority opinion. What I do not like in it are some implicit conversions between types, especially narrowing ones. Rust’s was closer to what I wanted, so I was pretty much set on using that as a starting point.

But on the other hand, one thing I really like about Haskell is its type system. Typeclasses and sum classes, thank you. In addition to those, C++ concepts were something I wanted. I wasn’t sold on Rust traits. I also wanted metaclasses real bad, since I figured quite fast how much I could do with just those.

When I write this part, I understand why there were multiple rewrites of the early type system and why it still keeps changing. I had multiple ideas that played together with various amounts of success and sanity. It is quite obvious that this would need plenty of refinement, and it is where most of my time has gone.

C interoperability

I knew I wanted this, and I knew that I wouldn’t want to do it the way C++ did it. I quite honestly think that it has become one of the greatest weaknesses of the language.

But Zig showed me the sane way to do this. Since importing C functionality was much more important to me than exporting it, I decided I could just ape what Zig did and add “cimport” to bring in definitions for C functions and the LLVM backend would handle calling them just fine.

I really thought it would be this easy.

Generics

I’m not even going to go into this. I’ve used generics, and I don’t want to go back to the land of type erasure with pointer magic. If you’ve used generics, you know you want this.

Keeping it simple(r)

And finally, it needed to be a lot less complex than either Rust or C++. I often say that the purpose of a programming language is to reduce cognitive load. A term that is too rarely spoken about, even though it’s improving.

So, I wanted a language as simple as it could go with the features I wanted. Time will probably tell if I succeed. And what monstrosity I have created. I took a mental note that Zig was probably as complex as I wanted to go.

Conclusions and continuations

So, that was pretty much where I started from. Note that some things are completely absent from the feature set I started with. The most notable one probably being the syntax. In fact, I still do not have a fixed syntax.

This is the oldest piece of syntax I could still find, and it’s pretty much from the time I figured these things out. This syntax actually comes from a toy language I was writing before I started with Flower. The example here is from March 2019, long before I even decided to go forward with writing the Flower compiler.

import std;

extern "C" func puts: address -> void

func main: string[] -> int32
{
    puts("hello world");
}

Next in this series, I’ll be discussing how these things changed with time.

Read the whole Flower Lang blog here: https://flower-lang.org