Well actually I don’t really present it, as it doesn’t exist. Lapsang is a name I came up with as a bit of a joke for a replacement language to Java nearly four years ago. Since then I have used it as an imaginary target language for various software engineering and craftsmanship thought experiments. During those four years (plus a few extra, but let’s not let mere details interfere with the story), I’ve watched my safe, simple world of waterfall-driven OO designs of heavily inherited classes, thousands of lines long, slowly crumble to dust. These days, we have whole new ways of doing software development: small, single-responsibility classes; design patterns; test-driven-development; design to interfaces; composition over inheritance; avoidance of mutability; functional programming and the like. The development world really has changed beyond all recognition, no?
So this has set me thinking: if I were to design a brand new language that truly embraced ideas like TDD, dependency injection, design to interfaces etc, what would it look like? The first problem I ran into is syntax. The moment I started writing example code that modelled these ideas, I had to express that code with a consistent syntax. Yet a syntax can make or kill a language instantly in the minds of many. So I tried to express them as a form of pseudocode, but that didn’t really work either. So in the end I threw out the consistent syntax idea and decided I would express each idea with a different syntax. No doubt some will see this as a mistake too, but I can’t hope to keep everyone happy all of the time, so I won’t lose any sleep over it if you don’t like the idea.
So back to Lapsang: what sort of language is it? Well it has the following features:
- For a unit of Lapsang code to compile, it must be tested. This is probably the most controversial feature, so I mention it first. If you don’t believe in the need to write unit tests, I’d suggest you stop reading now, as this language’s ideals are not for you. What this means in practice is that unit tests have to be a fundamental feature of the language, rather than a framework library that the code compiles against. The compiler runs the tests and profiles the code. Failed tests, or code not covered by those tests, are then both compiler errors.
- Lapsang mandates design to interfaces. To give an example of how thoroughly it mandates this pattern, code (outside of tests) cannot create an instance of another class, it must create an instance of an interface. Dependency injection is used to provide the desired class, that implements that interface, to that code at compile time/runtime.
- Lapsang supports classes, but doesn’t allow inheritance. I can’t decide yet whether it should allow inheritance within interfaces, but class inheritance is definitely out. Instead, composition is king. Any object (which includes interface references, functions and primitives) can have components added to it, even at runtime. Again, this pattern is baked into the language: Inversion of control/entity frameworks are not required to set up composed objects, at least at a basic level.
- Lapsang supports structured typing. This means that classes (and primitives and functions) do not need to pre-declare that they implement interfaces. Instead they implicitly implement an interface if they satisfy that interface’s contract.
- Lapsang encourages the use of immutable data types and functions/methods without side effects. Mutability is allowed, in recognition of the fact that its an essential feature at times, but such code has to be explicitly annotated as unsafe.
So that’s the plan. All I need do now is explain how such features might be achieved without making the language impenetrable to beginners. Watch this space…