Thursday, 25 May 2017

Programming language rant

Brian Bucklew, the developer of Caves of Qud (highest rated turn-based tactics game on Steam) and Sproggiwood (a casual roguelike very good both for beginners and for experts), has recently been involved in an external C++ project, and has tweeted a long series of rants about his hate of C++ from the point of view of a C# developer. Since Twitter is not a good medium for discussion, I am posting my thoughts on the subject here.

I will start with mentioning that I have no experience with C#. I have experience with Java. I consider C# to be an evolution to Java. Since I was not satisfied with Java, I am not interested in trying C#, since I believe it to be based on the same general rules. One reason why I did not like Java was too much focus on object oriented programming. The widely held belief is that it is good to learn as many programming paradigms as possible, as then you are able to use the good things about these paradigms in whatever programming language you end up working with. I consider OOP to be one such concept: something that generally every programmer should learn (ideally on a fully OOP language such as Smalltalk) but not something that everything has to be written in. I consider OOP to be a very useful representation of polymorphism. For example, in Hydra Slayer, there are multiple kinds of objects: hydras, consumables, and weapons. I can list all the objects in sight of the player, and then e.g. list their names. It is useful to call a name() method that will work correctly for all kinds of objects despite their different inner representations. But not everything has to be an object. This was the only use of OOP in Hydra Slayer (not including NotEye which does use OOP quite significantly), and HyperRogue did not use polymorphism at all until recently.

Oh my fucking god I have to make two fucking separate files for every fucking object. How can anyone like this language. C++, two pluses because you have twice as many files as the precise same thing architected in any other language. I really think C++ programmers are blind to how many incredibly annoying things you waste your time doing in C++. Ugh. It's so damn wordy.

This actually looks very similar to the issue I had with Java. Having to create a file for every single object; not only that, also a tree structure is forced. Furthermore, because of the lack of conditional compilation, I could not create a single version of the HyperRogue Android source that would compile as one of three packages depending on the compiler options chosen, and I had to create three copies of this source (this was done with a script, but still); maybe an experienced Java programmer would do it in some better way. I do not know to what extent C# fixes this. It does have conditional compilation, at least.

I hate having two separate files (.c and .h) too. But contrary to Java, the language does not force you to actually do this. In my biggest project (HyperRogue) the main file hyper.cpp includes init.cpp, which includes all the other cpp files in turn, from the most fundamental ones. When I want to call some function which was not yet compiled, I simply copy the declaration to hyper.h which is included first. But this comes up very rarely and it is far from a problem that Brian makes it to be.

It takes 10 seconds to recompile HyperRogue. Not ideal, but not bad either. If header files are necessary, generating them automatically does not seem to be a difficult task.

Like C++ guys think they have the ultimate concise low level language, but you basically have to write everything in two representations.

I consider the Google Code Jam statistics to be a good benchmark of conciseness. Contestants have to implement solution to algorithmic problems as fast as possible. It has to run fast, which hurts Python, but not languages such as C# or Java. Most contestants decide to use C++. From contestants who have passed to Round 2 (thus, no newbies), ones using C++ are also more likely to advance to Round 3 than ones using Java or C#.

Want to setup a map<> for something? Make sure you keep track of everything and/or iterate it when erasing so you can delete everything.

I do not understand what Brian is referring to here. Deleting every pointer in a map is simply for(auto& p: m) delete p.second;. In most cases, you do not even need that! I usually do maps of ints, pairs, strings, vectors, non-polymorphic types, etc. which do not require anything; and contrary to garbage collection, RAII will take care of cases which are more general than simply clearing the memory. If polymorphism is required, smart pointers will handle deletion.

bahahaha I forgot you can do multiple inheritance in C++ . . . . what a bad idea

Maybe nobody uses it, maybe people use it to implement something like Java interfaces (which were designed later), maybe it is used in the implementation of C++ itself. I do not care. I never use this and I have no problems with this feature existing. I consider the diamond problem to be an inherent to (class-based) OOP, especially in roguelike programming, when the hierarchical subclass distinctions are often very blurry (attack monsters with a cockatrice corpse? uh, it was first a monster, then it was food, and now it is a weapon?).

omg I forgot C++ can't compile circular references; so a child can't simply refer to it's parent without some sort of hackery like void* (I've written several million lines production of C++ in my life, for those concerned I have no clue what's going on with C++)

Simply use forward declarations, I do not get how Brian did not remember this.

Wow, c++ got a little unhinged with copy/move semantics since I last visited it, hu? I'm trying to imagine people with like less than 20 years of C++ experience writing correct C++ programs nowadays..."

Yeah, the copy/move semantics sounds crazy. But... what happens when you compile an older program with C++11? It compiles and works faster, because move semantics work behind the scenes. One only needs to understand it and care about it when writing extremely efficient programs.

...also not having introspection/reflection sucks a fucking A+ hairy nutsack.

For introspection (as in, checking what is the exact type of a polymorphic object) dynamic_cast is fine. As for reflection -- this seems to cure a problem that I do not have because I rarely use OOP. There is OOP in NotEye, and debug/save/load functions are case-by-case listings of all fields -- this is a place where reflection could be used, but I do not believe it would help that much because (a) this was trivial to write, (b) it appears easier to handle special cases, such as when new fields are added / class hierarchy is redesigned and the load function has to be adapted without breaking older saves. (Anyway, I have managed to implement a method executing a given lambda function with parameters (auto field, string name) for all fields of a polymorphic object in seven lines of C++ plus two lines per class, and creating objects by class ID in about ten extra lines; despite having to write a list of fields and subclasses for each class, I like my solution for efficiency and type safety.)

Coming back to C++ after such a long layoff it's amusingly clear just how much Stockholm Syndrome you develop with its language design.

There were several tweets like this. I know some legitimate criticisms of C++, but all Brian's criticisms appear to be caused by some kind of bias -- problems already solved appear easy, new problems appear difficult, or maybe self-confirmation, or working on some very poorly designed external project. It is hard to see what could be achieved by using templates, macros, RAII, and smart pointers when being used to OOP and reflection. Rather than accusing people of "Stockholm Syndrome", I suppose that some people think in this way, and other people think in that way, and everyone chooses the language which is better aligned with their way of thinking.

Friday, 24 March 2017

HyperRogue 9.4 is now available freely!

HyperRogue version 9.4c is released freely! You can download the Windows executable with source that compiles on Linux, the OSX package, the source, the Android version, or play the online version.

Compared to the previous free release of HyperRogue (8.3j) it includes the following new features:
  • Adaptative animations, 3D display, sound effects, and other user interface improvements.
  • Ten new lands, including Reptiles where the floor is made of reptiles, Burial Grounds where you have to use the curvature to gather treasures, and the Halloween mini-game where you have to use the limited resources in spherical geometry! See all lands in the HyperRogue gallery.
  • Geometry nerds can now experiment with spherical, elliptic, or quotient hyperbolic geometry, access new 3D models of the hyperbolic world, try cellular automata, or use HyperRogue as a visualization engine.
  • And tons of other minor improvements, such as turn-based multiplayer or changes to Orb frequency -- see the full changelog here.

As you can see, this is the latest version available at the moment; thus, the paid extras are only the social features (achievements, leaderboards) and automatic updates. We are tending towards changing the "previous major version is available for free" system a bit, as it has some disadvantages.
  • Bugfixes and interface improvements should be immediately available in the free version, as bugs or bad interface could drive the players away.
  • Having up-to-date source in the public repo would make it much more convenient to fork HyperRogue, as the improvements could be easily incorporated into the offical version. This would increase the probability of people contributing (so far there were only technical contributions, or ideas without code).
  • HyperRogue is a fun and challenging game, but it is also more than that. We believe it is one of the best ways to learn about hyperbolic geometry, and as possibly the richest hyperbolic geometry system currently in existence, it has other applications (such as data visualization). For such applications, it is beneficial if the free version is up-to-date.
Possibly the free version will be updated more frequently, possibly some more features will be added as paid extras. Please comment if you have any thoughts about this!

We would also like to note that although HyperRogue is currently one of the highest rated turn-based tactics games on Steam, it has almost no reviews on sites such as Metacritic. Please add reviews there!

Most importantly, have fun!

Sunday, 5 March 2017

HyperRogue 9.4: bulls everywhere

HyperRogue 9.4 is released on Steam and! (Android, iOS, and the online version will come later.)

You can find safety in some places in the Prairie, but if you want treasures, they can be found only on the other side of a giant herd of bulls.

Butterflies of Bull Dash don't pursue you -- unless you get next to them, they just spin around the obstacles. They cannot be killed conventionally, but you get treasure when a Raging Bull crashes into a Butterfly.

Crossroads V is yet another layout of Crossroads.

Some other changes:
  • Additional 3D options have been added to HyperRogue. The ball model and hyperboloid model can explain the 3D hyperbolic space used by HyperRogue. The new camera options could be used to obtain FPP or TPP view, although the models used by HyperRogue are not adapted to this.
  • A slight change in the generation of orbs, so that it is no longer optimal to avoid collecting more treasures after the 10 or 25 threshold. Orb spawn rate in the Crossroads is just 70% (relative to the spawn rate before the change) if you have 10 treasures, and rises to 100% when you have 25. Prize Orbs appear if you have 25 treasures, but their spawn rate is 60% if you have exactly 25, 100% if you have 50 (the spawn rate gets higher and higher as you collect more treasures, but the benefits are diminishing).
  • Two new geometries have been added (in the euclidean/elliptic menu). The Zebra pattern is a periodic pattern of 40 cells, in the Zebra quotient geometry, the space is warped so that repetitions which become exactly the same cell -- thus, you play on a torus with two holes. The field quotient geometry is similar, but it is based on the pattern which is used by the Prairie; this pattern has 132440 cells (39732 heptagons).
  • In the mobile versions, a compass has been added in the bottom left corner. It can be used for movement, so that your hand no longer obscures the view.

Prairie is based on wonderfullizardofoz's Amazon River idea, but rethemed to make it stand our more from Whirlpool. Crossroads V is an old idea of Fulgur14. Many people have had idea of a land inspired by the Boulder Dash mechanics (Z, CtrlAltDestroy, simon_clarkstone); Bull Dash has risen from these ideas, although the relationship is quite remote. The field pattern is inspired by the method used by David Madore in his hyperbolic maze.

More improvements and are reported in the changelog, and on the Steam forums. Have fun!

Thursday, 5 January 2017

HyperRogue 9.3: three new lands and an online demo

HyperRogue 9.3 is released on Steam and! (Android and iOS versions will come later.) This update introduces three new lands, and several other minor features and bugfixes.

Additionally, an online demo of HyperRogue has been created! This allows new players to try out HyperRogue's gameplay without downloading it.

These reptiles are quite strange creatures. They spend most of their lives sleeping, as floors that other creatures can walk on. Sometimes they wake up to hunt their prey, but they will happily go back to sleep if they happen to move into a hole on their way. Your attacks do not kill the Reptiles, but you can push and stun them.

Take the gravity mechanics from the Ivory Tower, but reverse it: you are going deep into the Dungeons now! This is combined with ideas from the Palace: use floor switches to open or close passages, and the Skeletons have to be pushed into holes, so that they won't be able to return. But be careful, and don't fall yourself!

Gravitational anomalies in the Jungle create mountains overgrown with ivies and bushes. Will you dare to climb the ivies to get the amethysts hidden above?

The Reptiles land is based on an old idea of tricosahedron, inspired by a print by M.C. Escher. Dungeon and Lost Mountain are based on ideas by wonderfullizardofoz. If you have more ideas for new lands, please share!

HyperRogue 9.3 also has several more improvements. Columns appear on the coasts of R'Lyeh so let you know that you are near. Slow monsters, Ivies, and Worms now use a specialized pathfinding algorithm, so they won't try to catch you through trapdoors or against gravity. Orbs of Yendor no longer block the player movement. See the Steam forums for more details.

Have fun, and a happy New Year!