Sunday, October 3, 2021

A look back

It's obviously been a while since I updated this, and I've gotten one or two questions about it — enough to get me to write a brief update.

In short, this project is (surprise!) now officially abandonware. I'm not planning on developing Effes any more. That said, I consider the project a success!

Going back to the start, the crux of Effes was to explore what happens when I let programmers define variables whose type is a sum type of declared types: "A or B". That is, I wanted to move one aspect of composition from the API designer's realm to the API user's realm. For example, in Java, an Optional<T> is defined as being one of two things: either an "absent" or a "present of T". This sum type (absent or present) is defined by the Java API. I wanted to see what happens if we let the API define just the "absent" and "present of T" types, and let the user of the API declare when they want a variable that is exactly one of those — or when they want something else, like an "absent or present-of-T or list-of-T", or even a "present-of-T or list-of-S".

To get there, I started with a project called Effes to create a parser and type-checker for such a language. With that done, I moved to Effes2, which would be re-written as a self-bootstrapping language: Effes2 would be written in Effes2.

Since I didn't want to deal with Effes2-to-JVM compatibility, I couldn't rely on any external libraries; the Effes2 compiler had to be written from scratch. One of the first steps was writing the parser, and this was actually a perfect test of the language! Parser rules are sum types (a statement is an assignment, or a function call, or a return, or a...), so they would fit perfectly with the central feature of my language.

But the result was... not great. You can see the result in Parser.ef, which basically looks like gobbledygook. If my idea was really that powerful, the code behind this parser would be intuitive, approaching (if not equaling) a BNF definition. A quick glance at _parseSimpleExpression(tokens) shows that it isn't.

Well, a negative result is still a result — and that's where we stand today. The project started out to explore "what happens if we let users create sum types?" and the answer was, "not enough to warrant designing a language around it."

There are some caveats around the negative result, to be sure: I never finished Effes2, and it could be that using the parser rules in a compiler would be more intuitive than using them in a parser. I also never explored an earlier idea had, was to explore how intersection types ("A and B") could replace inheritance (imagine a List type whose instantiation was something like List & AbstractList & ArrayBasedListFunctionality).

Interestingly enough, I've since learned that TypeScript has this feature, which it calls union types. I have a couple ideas for future projects bouncing around in my head, and if I get around to pursuing those, I look forward to using TypeScript for them and seeing what role union types have in the context of a fully-formed language. But for now, Effes has served its purpose, and I'm content to close the book on it.