A First Look at the Manda Language


It’s still not public yet, but here’s a little bit about my current project.

If you’ve read any of my “What’s New” posts, you’ll recall hearing about me working on the “Manda” language for the past two months. This isn’t true – I actually started in early 2018.

class Tobe {  fn complain -> print("I need money!")}

The Name

Manda, the great snake.

It’s a little embarrassing, yes, but for some reason, I thought “Manda” was the name of some snake of ancient legend. In reality, I had remembered it wrong, and it was really just a big purple snake from Naruto.

It worked out, though. The original stated goal was “a gradually-typed language to replace Python.” Though that goal has since changed, the name and icon (🐍) stuck.

One Last Rewrite

That being said, I’ve nuked the project and completely restarted it multiple times. The current iteration is all C++, with a flex lexer, handwritten parser, and libjit-based JIT environment, as well as a REPL. I plan one more rewrite this week, which I am sure will finally lead to the completion of the project. C++ is great for writing fast, efficient programs. However, it’s simply horrible for writing compilers, especially for functional languages. You know what’s fantastic for writing compiler frontends (but not necessarily JIT runtimes)? OCaml. This next iteration will have its frontend implemented in OCaml, which will then produce a shared IR (intermediate representation). This shared IR will be picked up by the C++ runtime, which will handle garbage collection, concurrency, JIT, and other nitty-gritty functionality. The C++ backend will actually be a static library, which exposes a minimal C API. The shared IR will be passed by means of Protobuf, so we can really have the best of both worlds.

This rewrite will mean I can very quickly implement the previously-undone features of the language, and also lets me separate my concerns. Hooray!

Execution Model

Manda’s virtual machine (VM) is multi-threaded, and operates in terms of workers. Workers are, in simplest terms, the smallest units of code that Manda will execute. Each worker contains a pointer to a function, its entry point, as well as any arguments passed to it. Each worker also has its own stack, and contains a pointer to a worker that may be blocked in waiting for its result. Manda runs as many threads as you have cores, each of which gets a worker from a VM-wide queue. That worker’s code is then executed, until it returns a value, terminates due to an unhandled exception, OR voluntary yields control to the next worker. Yielding puts a worker in a WAITING state. This is how async+await are implemented in Manda. One worker performs a system call to enqueue another worker, and yields to the next worker. Eventually, the other worker will end, at which point the first worker will be resumed, with the results placed on its stack.

Manda, like most other languages with VM’s, uses automatic garbage collection to manage memory. This is useful, because things like String.concat can actually just return a class that holds references to its inputs, instead of having to manually copy them.

It’s (Actually) Functional

Though Manda’s syntax resembles C-derived languages like Java, in reality, it’s a functional language. Every “statement” is really just an expression in disguise. Manda’s type system is a kind of Hindley-Milner type system – basically, it uses a well-known algorithm to infer the types of virtually any expression, given the set of primitive types and operations. Because of type inference, you almost never have to write type annotations, so Manda writes and reads like simpler, dynamic languages, while still having all the type information it needs to produce efficient code.

At this time, though, partial function application is not yet planned. Though it’s very nice, I fear that it will hurt long-term readability.

Overall, I feel like Manda is a very clean, readable language, while being fully typed, which I think makes it attractive.

Primitives

I initially considered going the route that Dart took, and providing primitive types like int and bool as classes. However, I ultimately preferred having primitive types as plain value types, and so there are builtin types like u8, i64, and f32. Languages like C# and Java have such primitives, and nobody’s ever complained. One difference, though, is that I don’t plan to have any sort of boxed types for primitives. Because there will be both ad-hoc polymorphism for number types (like most other C-like languages), and generics, you can expect to see something like this:

class Int {  fn toString(n) {    if n < 0 then      "-" + toString(n * -1)    else if n < 10      "0123456789"[n]    else      var digit = toString(n / 10)      var rest = n % 10      if rest == 0 then        digit      else        digit + toString(rest)  }}

I don’t expect any problems in regards to primitives. Plus, this means that number-heavy code can be compiled to very efficient code once the JIT touches it.

Challenges

Though a language-specific VM can provide better performance and ease of development, it’s simply incompatible with existing code, other than use with a C FFI. At the same time, without good library support, nobody will use the language. One big thing I know people will be looking for is database support, so it’ll be important to have a plan for this from day one.

Other Plans

I realize that launching a programming language is a tremendous amount of work; writing the compiler+runtime is just the first step. So expect the following to exist from the very day it goes public:

  • Good docs (probably a GitBook site)
  • scales, a package manager
  • A good standard library (think Dart, C#, or Java, with expansive libraries)
  • IDE tools (code formatting CLI tool + language server protocol)
  • Good unit testing support, because nobody likes bugs in production
  • A running Web service or other product of considerable scale running on Manda. Without a real-world example, how can I prove it’s scalable, reliable, etc.?
  • A donation link (GitHub sponsors), or otherwise some clear indication of how the project is funded
  • A clear roadmap and plan for new features and changes

Conclusion

Overall, I’m excited about the potential this project has. I’m aware that it will be a lot of work, but it’s been a passion project from the very beginning. I truly believe that, when all is said and done, it’ll be a very fast runtime environment, while also being very easy to maintain in the long term. I look forward to Manda finding a niche in serverless functions and very high-throughput Web servers.