From Python to Genie



Three days ago, I announced a side project to take one of my old text-based games and make a native port in C++ and/or Genie. It was meant more as an informal comparison, really. Meanwhile, as expected, my initial choice of game proved ill-advised. Luckily, there was a plan B: Glittering Light. Not the web-based game that's so popular, but the original text-based prototype I only showed off to a handful of friends. This has a number of advantages:

  • The code is 60% smaller than for Tomb of the Snake, making it much easier to tackle;
  • It's derived from a code clean-up of the same, resulting in more simplicity and clarity.

Once again, I tried doing this in both languages. Only this time it soon became obvious how C++ trips me up at every step while Genie, a language I only started learning ten days ago, performs better than expected, with only minor hiccups when I forget about the underlying C compiler.

I'm beginning to understand why many programmers prefer the latter to C++.

That's why this story is about Genie instead. And as it turns out, Genie is more than a glorified C preprocessor. If anything, it often ends up more helpful than Python, for all it's (inevitably) more low-level.

For one thing, Genie uses static typing. That makes it more verbose in places, as structs have to be declared for example. On the plus side it also gives you enumerations and constants, which make it easier to express intent.

Genie also has do-while and case-when statements, proof that indentation-based structure was never the obstacle. By the way, it expects tabs by default, with a way to state you're using four spaces instead or whatever. Sanity at last.

Oh, there are places where it's kinda fussy: make sure to initialize (local) variables, and declare them only at the start of a block to avoid a strange and unhelpful error message. It might be possible to compile the generated code with --std=c99... if you're feeling adventurous. Oh, and don't try to return from within a case-when statement.

Conversely, Genie has sane scoping rules (no more global declarations), and the self keyword, while still present, is implicit in most situations like it should be. Things like that can even make the code shorter than in Python!

The strong typing, meaning for example that enumerations are distinct types, now that's going to delight some people and annoy others.

Can't tell you much about the object system yet: should have waited more before writing this, arguably. It has interfaces and abstract methods; virtual methods have to be declared like in C++, and there is an Object class that all others normally inherit from, except it's not mandated. Let's call it a hybrid system.

(And yes, it's a single-inheritance system like Java's.)

Before concluding, there's one big issue related not to the language proper, but its standard libraries. Both Python and Genie wrap the curses API in an object-oriented interface, making windows into proper objects and so on. But where Genie's bindings wisely keep function names separated by use, Python collapses them into just a few that each take a variety of arguments, and then some that aren't there at all in C. I shudder just trying to imagine the maze-like if statements that handle the various combinations.

No wonder games made with Python and curses feel so sluggish. Python itself is definitely not that slow. Mystery solved!

In conclusion: if you also know some C, and crave working in a truly simple language for a change (Python may seem so, but it's a beast nowadays), Genie might be just the thing. It's pragmatic, fast yet high-level, and trusts / respects the programmer. That's a feature, you know.

P.S. A few details I forgot to mention:

  • Like in D, classes have reference semantics while structs have value semantics. But you can (un)box value types as needed.
  • Apparently errors aren't classes, but more like a kind of enumeration types?
  • You can choose to manually manage memory.


Tags: programming