Skip navigation

Tag Archives: c++

Those of you who’ve been checking out my projects might have noticed that I wrote my latest one in C++. The two previous projects I had written in Haskell. So why the switch? I’ll write down a small summary of the pros and cons of the both languages that influenced my decision.

I’ll start with the things that spoke for Haskell.

  • Haskell, in general, allows a lot more abstract, safer, higher level way of programming. Of course, you already knew this, but it’s still worth mentioning.
  • Hackage has tons of useful packages which makes using libraries and all the associated bureaucracy really simple. (Hackage is basically a repository consisting of almost all open sourced Haskell programs and libraries.) Combine this with cabal, which downloads, compiles and installs the dependencies for you automatically.
  • C++ compile times, especially with Boost, are abysmal.

And now for the cons, or, put in a more positive light, pros for C++.

  • It’s much easier to reason about performance in C++ than in Haskell. This is given, I guess, and the simple solution is to become a Haskell champion who can spot a space leak a mile away, but it bothers me nevertheless. There was a nice post and thread at Haskell cafe a while back about this.
  • Writing portable code in Haskell is not as easy as with C++. With portable I mean 1) code that runs on x86 across operating systems (Windows, Linux and Mac), and 2) code that runs across architectures (x86, ARM, MIPS, etc.). While portability is not as trendy anymore as it once was, I still have the twisted opinion that high quality code in a higher level language absolutely must be portable, otherwise it’s not high quality, and the Haskell ecosystem currently has limited support for writing portable code. Portable across operating systems is relatively simple with Haskell using GHC (although there are exceptions), but portable across architectures is a pain. GHC, the defacto standard Haskell compiler, actively supports only x86 and doesn’t cross compile. Some of the other Haskell compilers do compile across architectures, but they don’t support all the GHC extensions (which are used by a lot of Hackage packages) and often have a huge performance gap with GHC, which leaves me with zero Haskell compilers I’m 100% happy with. Don’t get me wrong, I still appreciate GHC and think it’s magical, but there’s room for improvement.
  • The Haskell libraries are in a constant flux. I’ve been writing Haskell code for a couple of years now, and each time a new GHC version came out, the old code broke. Usually the libraries included with GHC are updated and the interface was changed. Or GHC behaves a bit differently regarding some minor points and the code breaks. Or cabal, which has its main releases together with GHC, has some new features and the code breaks. There are plans for fixing the libraries once and for all (I can’t find the link now), which I think is a great idea, but when they do (and until they do), there’ll be breakage again.
  • Cabal, while great in general, has its problems, namely what cdsmith felicitously dubbed Haskell’s own DLL hell.

As can be seen from the list, the negative issues I see concerning Haskell are mostly not about the language itself but the infrastructure. That makes sense, I guess; Haskell, although it has a great community, is a less used language, especially in the industry, which makes it more difficult to establish an infrastructure that can compete with the one of, say, C++. The problems I have with C++, on the other hand, concern the language itself, which, although useful, is not really what one might consider the crown jewel of language design.

The infrastructure is at least something that can be fixed.

I noticed I still haven’t blogged about a project I worked on some time ago, so here goes.

A long time ago I wrote a small library for wrapping OGRE in Haskell. I wrote it manually, i.e. first writing some C functions that call C++ and have a C interface, and then wrote some Haskell functions to call the C functions. That’s the principle when wrapping C++ libraries in most higher level languages, mainly because most language implementations support calling C, but not C++.

Now, by writing the whole wrapper manually you have the complete power of the resulting interface, so you can try to bend the C interface so that the resulting interface has the natural feel of the higher level language you’re writing the binding for. The negative side to this is, of course, that it’s lots of work, and more or less tedious at that. There are therefore a lot of programs that automate some or part of the process of writing bindings to C libraries. So when wrapping a C library for Haskell, you can use a tool like hsc2hs, bindings-DSL or c2hs.

But it gets more problematic when you want to wrap C++ code. In the end you somehow have to wrap the C++ code to C – either manually or automatically. Some C++ libraries maintain their own C wrappers, like bullet and LLVM. For others, the wrapper writers must either write or generate their own C wrappers. When it comes to Haskell bindings for C++ libraries, the C wrappers were written manually at least for Irrlicht. I also wrote the C wrapper manually for the first versions of Hogre. As for the libraries that generate the C wrapper using a tool, there’s at least qtHaskell.

Now, at some point it got tiresome to manually write the Haskell bindings to Hogre, so I wrote a tool to automate it. Actually, there are two tools: cgen is a program that parses C++ header files and creates a C wrapper around the C++ library, and cgen-hs is a tool that parses the generated C header files and creates a Haskell wrapper around the C library. Using these two tools I created the newest version of Hogre, which is a lot more complete than the previous, manually written binding.

I also wrote a small example on how cgen works that I’ll demonstrate here. The input is Animals, a C++ library that allows access to a programmatic use of a wide range of animals. It’s a header-only library because I wanted to keep it simple, but that doesn’t really make a difference here. It’s split across three header files, listed here:

namespace Animals {
class Animal {
    public:
        Animal() : age(0) { }
        ~Animal() { }
        virtual void make_sound() = 0;
        int get_age() const
        {
            return age;
        }
        void increment_age()
        {
           age++;
        }
    private:
        int age;
};
class Dog : public Animal {
    public:
        Dog() { }
        void make_sound()
        {
            std::cout << "Growl!\n";
        }
};

class Sheep : public Animal {
    public:
        Sheep(int wooliness_level_ = 0)
            : wooliness_level(wooliness_level_)
        { }
        void make_sound()
        {
             std::cout << "Baa!\n";
        }
        void shear()
        { /* something */ }
    private:
        int wooliness_level;
};
}

So, given this piece of code one can feed it to cgen, which generates a C interface for it. The result looks something like this (simplified):

/* Sheep.h */
void Animals_Sheep_delete(Sheep* this_ptr);
Sheep* Animals_Sheep_new(int wooliness_level_);
void Animals_Sheep_make_sound(Sheep* this_ptr);
void Animals_Sheep_shear(Sheep* this_ptr);
/* Sheep.cpp */
void Animals_Sheep_delete(Sheep* this_ptr)
{
    delete this_ptr;
}

Sheep* Animals_Sheep_new(int wooliness_level_)
{
    return new Sheep(wooliness_level_);
}

void Animals_Sheep_make_sound(Sheep* this_ptr)
{
    this_ptr->make_sound();
}

void Animals_Sheep_shear(Sheep* this_ptr)
{
    this_ptr->shear();
}

So there we have a C wrapper for a C++ library ready for compilation.

For writing the Haskell binding, the next step is to run the next tool, cgen-hs. It takes the generated headers of the C wrapper as input, and as output creates a Haskell library that wraps the C library. The output looks something like this:

{-# LANGUAGE ForeignFunctionInterface #-}
module Sheep(
sheep_with, 
sheep_delete, 
sheep_new, 
sheep_make_sound, 
sheep_shear
)

where

import Types
import Control.Monad

import Foreign
import Foreign.C.String
import Foreign.C.Types

sheep_with :: Int -> (Sheep -> IO a) -> IO a
sheep_with p1 f = do
    obj <- sheep_new p1
    res <- f obj
    sheep_delete obj
    return res

foreign import ccall "Sheep.h Animals_Sheep_delete" c_sheep_delete :: Sheep -> IO ()
sheep_delete :: Sheep -> IO ()
sheep_delete p1 =   c_sheep_delete p1

foreign import ccall "Sheep.h Animals_Sheep_new" c_sheep_new :: CInt -> IO Sheep
sheep_new :: Int -> IO Sheep
sheep_new p1 =   c_sheep_new (fromIntegral p1)

foreign import ccall "Sheep.h Animals_Sheep_make_sound" c_sheep_make_sound :: Sheep -> IO ()
sheep_make_sound :: Sheep -> IO ()
sheep_make_sound p1 =   c_sheep_make_sound p1

foreign import ccall "Sheep.h Animals_Sheep_shear" c_sheep_shear :: Sheep -> IO ()
sheep_shear :: Sheep -> IO ()
sheep_shear p1 =   c_sheep_shear p1

Then one can write a Haskell program using this new Haskell library, and run it for the output:

$ cat Main.hs
module Main
where

import Control.Monad (replicateM_)

import Types
import Animal
import Dog
import Sheep

main = do
  dog_with $ \d -> 
    sheep_with 1 $ \s -> do
      dog_make_sound d
      sheep_make_sound s
      sheep_shear s
      replicateM_ 5 $ animal_increment_age (toAnimal s)
      animal_get_age (toAnimal s) >>= \a -> putStrLn $ "The sheep is now " ++ show a ++ " years old!"
$ ./Main
Growl!
Baa!
The sheep is now 5 years old!

So, everything seems to work well, and the newest Hogre version can be found at Hackage, as well as cgen.

Cgen is, however, in a very early stage of development and has, therefore, some weaknesses. First of all, it’s not a complete C++ parser, not even close, so it fails to parse many C++ header files. After configuring it for OGRE, it does manage to parse about two thirds of the OGRE headers, which is a good start, I guess. The C++ parser was the first real parser I wrote using Parsec, so a rewrite is probably the way to go.

Second of all, as I’ve only seriously used cgen for OGRE, it makes some assumptions about the C++ headers that may not hold for other libraries. The most critical one is probably that cgen-hs expects that all the classes and functions to wrap are in some namespace, which leads to problems when wrapping libraries that reside in the global namespace.

The third weakness is that it the generated Haskell functions are simply all in the IO monad, which suits well for OGRE (which doesn’t really have that many pure functions), but may be far from ideal for another library. Finally, cgen currently doesn’t support any class templates, neither wrapping them or using them as parameters or return values, so wrapping interfaces that rely heavily e.g. on STL will be troublesome. For Hogre this is not really a killer, although it does prevent the Hogre user from using some features that are available in OGRE.

All in all, however, cgen is working well for Hogre, and if you’re planning on writing a binding for a C++ library, you can give it a try. For more information, see the cgen homepage, a simple example, and the Hogre homepage.

Time for a small update again. The last time I wrote I mostly reviewed the work done last year, wrote about the tools used and spent some time comparing Haskell with C++ as I had been busy rewriting the Freekick server in C++. So what’s been going on in the past month? Well, some of the points mentioned in “things to do next” part of the last post have been worked on, while others aren’t. Also, as I have now been using C++ for a few months there have been some signs of the need to wander off to another – hopefully better and shinier – programming language again, just like one would expect. This time I’m not thinking of Haskell though, but Python.

I’ll first let you know what’s new with Freekick core development. There’s been a lot of small improvements – I’ve added some server functionality such as allowing human players to play along or goal detection, but the most important update is that the OGRE client now has the ability to control a player and kick the ball around. This actually makes Freekick a soccer game that can be played. This doesn’t mean, however, that it would actually be fun to play the game – the relatively silly AI makes sure we’re not quite there yet. Another thing that makes the game less fun is that the clubs aren’t really there; the players have no differences in skills or personality, there are no kits or club names or tournaments.

The next thing for me to do is try and eliminate these two problems: first, the AI needs to be made better. At the moment it’s not really that bad – they pass the ball and try to score – but they only have a few actions which makes the match seem repetitive, and the goalkeepers are horrible. Second, the soccer match needs to have a menu around it, including creating and viewing tournaments, lineups, league tables – the whole deal. Actually I’ve already started work on that, which brings me to Python.

You see, working with C++ the whole time with Freekick core was not bad, but after you’ve seen something like Haskell in action, sooner or later you start to wonder if everything really needs to be so complicated. I’m talking about the sheer amount of time spent typing the code in, the loops, the iterators, the classes and headers and declarations, the curly brackets…

As Freekick was designed with modularity in mind and was split to multiple processes from the beginning on, the question of using Python for the game menu arose. After poking around with PyQt for a while the first drafts of the game menu were already finished. I had had my doubts about dynamic languages and duck typing before, but now, after having written a few small applications with Python I’m slowly starting to see the advantages such a dynamic high-level language can bring. I was amazed how fast you could actually write a simple-looking Python script that does the same thing as an application you could spend weeks writing in C++.

Encouraged by my Python adventures, I played around with the idea of solving the other problem – AI – with Python. Since I don’t really fancy writing all the Freekick client side logic in Python, I thought about using Boost.Python to export the C++ classes into Python. Doing the experiment was interesting, but the unfortunate truth is that exporting the classes still seems like too much work, even with the excellent library, especially with the page-long error messages and the fact that the STL containers would apparently also be have to exported manually. The other way would be embedding Python in C++, but I’d still have to export the data structures to Python and back, which makes me think it’s probably faster just to stick with C++ after all.

The GUI part is still far from ready – the only event that starts a match at the moment is a friendly match, and the GUI-match interface is non-existent at the moment – but the base is there and will be expanded when the time is ready. At the moment I think improving the soccer match itself is more important, since there is really no good reason to start a match if playing it isn’t fun, which brings me back to C++ and the AI. I’ve been reading the book “Programming Game AI by Example” by Mat Buckland again, which really is quite an inspiring work, but I think it will still take a while for me before the AI code is in a state where it both seems halfway smart and is easily extensible.

Luckily there are still a couple of mini projects for me to do in case writing AI gets boring. First of all there’s the GUI with all the tournament and schedule creation to do, but I think the time is also slowly getting ready for another Freekick client, this time with ncurses as the “graphics” library. I’ve been wanting to get my hands dirty with ncurses for a while now, and I’m all for minimalistic software, so hey, why not. Other fun things include creating a TV style soccer camera in OGRE and taking player skills into account on the server side. I’ll keep you posted.

New year, new tricks. In this post I’ll explain what Freekick has been doing for the last two months. The main events include rewriting Freekick in C++ so that it finally matches the Haskell version feature-wise, as well as gaining a bit of experience in using the associated tools and libraries. Before I get to that, let me first write down a brief summary of the last year, and of the blog thus far.

In April I wrote the first post announcing the beginning of the project, wondering which language and graphics library to use. The decision was in the end to go for C++ and Ogre. I was also preparing CEGUI as the GUI library. The build system was make, the version control system used was Subversion (if any).

In May I got to physics libraries and decided to look at ODE instead of Bullet. Soon after that I’d let the physics and graphics digest for a while and learn Haskell instead as a tool for AI programming.  Back then, there was no real code written for the project yet.

In June I had learnt the basics of Haskell and was using it to program some of the first things in Freekick.

In July the very basic design of Freekick was slowly getting clear. The plan was (and is) to split the game to different processes and use a server-client model. I went on programming the server and the AI in Haskell and played with the thought of writing the client in Python. I also started getting VCS conscious and mentioned darcs for the first time.

By August I had gotten as far as programming some multithreaded networking in Haskell, as well as doing some nice experiments and tests with neural networks. While the networking part was directly a part of Freekick at the time, I haven’t integrated the concept of neural networks with the project yet.

In September the very basic structure of Freekick, including the server, AI and a client, was finished in Haskell and the version 0.0.1 was released. The client was written using SDL, the primitive physics for the server was done without external libraries and the AI was a simple decision tree.

In October the negative sides of Haskell were starting to become clear, mainly being problems with the performance and problematic use of C++ libraries. The decision was to write a new client in C++ that uses Ogre for graphics. Implementing the data structures (classes) in C++ for the client also makes writing the server in C++ not such a big step.

In November the new client was finished. As it became clear that the performance problems had more to do with the Haskell server than with the client, the decision was to rewrite the server in C++.

In December I didn’t have the time to write about it, but I was busy rewriting the server in C++. This included updating the protocol between the server and the client as well as learning object oriented design.

And now, in January, it’s time for a post again. The C++ server is running, and the preliminary AI is finished too. As there were some updates to the Freekick protocol that broke the backwards compatibility; the old Haskell programs (server, SDL client, AI client) would have to be updated to match the new protocol in order to be able to work with the newer software (maybe I’ll get to it on some rainy day).

As there are some difficulties finding a public code hosting site for darcs repositories (and darcs seems to have some other problems too), I went for another RCS, namely git. I too am one of those who don’t want to go back to centralized SCM after seeing the other side, and git seems to fit my needs perfectly. The Freekick code can be found at GitHub by the way, at http://github.com/anttisalonen/freekick/tree/master. If you want to compile and run it though, there are some external dependencies (notably Bullet and Ogre) and the build script probably isn’t portable yet. If you run into problems, drop me a note.

As a side note, I also wondered which build tool to use for the C++ version of Freekick (for Haskell, Cabal is the excellent build tool, while C++ has a lot more options). The two strongest candidates were CMake and SCons, and in the end I went for the latter. The build tool for Freekick has the seemingly complicated task of compiling and managing a few libraries and applications, preferably comfortably configured in one configuration file. By now, my SCons build script (SConstruct) has become about 150 lines, but it does everything I want it to and how I want it to. The level of documentation for SCons is also excellent.

Now, a few words about implementing Freekick. First of all, even though C++ is more comfortable than I previously thought, it’s still far away from Haskell. My impression is that, thanks to the Boost libraries, you can use most of the nice things that Haskell has (e.g. tuples, lambdas), and everything will run slightly more efficiently than in Haskell, but there’s a lot more code to write and the code is a lot less elegant and a lot more verbose than in Haskell. I guess the better control of CPU cycles and bytes of RAM is worth it.

An interesting thing to note is that it took for both Haskell and C++ about three months to implement the basic functionality of Freekick. The comparison is unfair; I had just learnt Haskell when I started programming Freekick with it, while I’ve had previous (albeit now rather obsolete) experience with C++. Also, when I programmed Freekick the first time, the basic structure and design was only barely clear to me. With Haskell I had to program my own primitive physics engine, with C++ I used Bullet (which was about just as troublesome). The Haskell graphical client was easily done in SDL, while the Ogre client was a bit more work (though using Ogre is actually quite fast, easy and fun – signs of an excellent library). However, in the end the difference in development times wasn’t drastic, which shows to me that C++ really seems to do the job of evolving to a higher level language with time pretty well.

This was also the first time that I’ve actually done some object oriented design. It’s actually quite fun. The constant shuffling around with the header and cpp-files and the verbosity of it all is something I wouldn’t miss with Haskell, and the generic programming and code reuse that OOP offers is still light years away from the level you can find in a functional programming language. Still, C++ is on any account usable and I really need those cycles and bytes. Hopefully in a few years I can use a language that is as elegant as Haskell, while still maintaining the perceived efficiency of C++.

The next things to do with Freekick include relatively small improvements to the server (better compliance with the rules of the game), to the AI (it’s really quite primitive at the moment) as well as to the client (controlling a player and some small graphical enchancements). After that the next task is to go and implement the bigger plan, i.e. the game around the match – organizing the matches into cups and leagues.

A few weeks ago I wrote I’d try and write a new Freekick client using OGRE3D and C++. The reasons for this seemingly dramatic language switch from Haskell were manifold; the top one being the jittery feeling in the old SDL client, apparently resulting from some timing issues regarding my thread management in Haskell I wasn’t able to sort out. Another thing that greatly influenced the decision was that I had split the whole project in multiple processes already during the design; since the processes communicate with each other via sockets, reimplementing one part (even in a different programming language) is relatively easy.

The first version of the OGRE client is now finished, and it has about the same functionality as the very first version of the SDL client: the user is doomed to be a spectator as there is no way to control a player, the only controls available are merely for moving the camera around. I personally found it very interesting to see the functionality of both the server and the AI through a different client; of course the rest of the functionality has stayed the same and the AI is as stupid as usual, but now it’s robots instead of red and blue squares kicking the ball.

Oh, here are some screenshots of the new client. Obviously, there a lot to be done (more than the pictures can describe), but it’s a start.

OGRE client
Top-down look

Another thing I find rather exciting is how easy it is to produce software these days that has features I could only dream about five years ago. Back then, programming multi-threaded networking or 3D scenes with custom meshes and lighting (including shadows) was a nightmare (for me at least), but nowadays (especially with the aid of such terrific libraries as Boost or OGRE) I can spend more time programming the essential things.

A few words on the design of the new OGRE client. I wanted it to have three distinct parts which communicate with each other via simple interfaces (true to Rule of Modularity) – networking, graphics, and match state. The basic idea is that the networking part receives information about the match state from the server and writes it in the state part. The graphics part renders the scene and reads the information for this from the state part, so the state acts as a kind of broker between networking and graphics. As only one part writes and the other one reads the mutable, shared data there shouldn’t be big problems arising with multi-threading, either (I hope).

The question is, then, is the jittery feel from the SDL client gone with the OGRE client? The answer is (to my surprise) no. Last time I wrote about the timing problems in the networking code between the server and the client; specifically, even though the server was set to send the player positions every 20 milliseconds and the client should draw them every 20 milliseconds, the jitter was clearly noticeable. My conclusion at the time was that the client wasn’t updating the graphics fast enough and that I’d need to write a new client in C++ as a remedy.

Now, as the new client is functional enough to show the jitter, I investigated the problem more and, using the Date_time library from Boost I measured the frequency with which the server actually updates the client. It turned out that instead of sending an update every 20 milliseconds, the client receives a scene update only every 250 milliseconds, which obviously is much too slow.

I actually measured the interval between updates before I started writing the new client and came up with the said 20 milliseconds. The difference is, back then I measured the interval on the server side, not on the client side – which means that some obscure bug in either the thread management code or in the network code kept the data on the server before it was actually sent.

I also tried implementing a very primitive client side prediction on the OGRE client as a test, but the interval of 250 milliseconds is still too much for a smooth scene. I also came across some very interesting resources by Valve regarding multiplayer network programming, and while I’m not so sure I’m willing to implement entity interpolation like they did or if doing that would even work so well in a soccer game, the article still gave me some hints what could be done better on the server side.

The last time I wrote I’d consider rewriting the server again using Bullet as the physics engine, and now that I’ve discovered the problems regarding the network code on the server side as well my next task seems pretty clear. I could try to fix the issues in the Haskell server code, but it seems a bit too much at the moment, and I’m already looking forward to getting my hands dirty on Bullet. That means (to the disappointment of the fellow Haskellers) that soon the only part written in Haskell (not counting the older, yet very usable client) will be the AI, which also needs to be improved a lot in the future. I still think Haskell is a great language though and I’ve learnt unbelievably much from it (as Simon Peyton Jones says, “Even if you’re going to go back to C++, you’ll write better C++ if you become familiar with functional programming”), but I’m afraid it’s not the best tool for this job.

For those of you who are interested, I haven’t yet uploaded the code for the new client in any repository. It wouldn’t be suitable having the code on haskell.org, and I don’t know of any other public source code repositories for darcs, which makes me look for other revision control systems. After my experiences with darcs I’m determined to stick with a distributed RCS, and git seems like a good option, but before making the final decision I’ll check out the other options (e.g. Mercurial). Once I have the URL I’ll let you know.

Following the 0.0.1 release of Freekick and an update to 0.0.2, I started noticing some problems in the implementation that showed a need for code refactoring. There were certain issues that implied I should find out about the internal workings of Haskell, as in, trying to figure out how the language and the implementation I use (Glasgow Haskell Compiler) works in general, especially with regards to threading, scheduling and performance.

The first issue I ran into was about my physics engine. I had defined a maximum velocity for my players of 8 m/s, but after some measurements I found out they were instead quite a bit slower. (A tip for the future: implement a debug panel for having such information when you need it. Measuring something like that shouldn’t be necessary.) This implies that the physics engine has serious flaws. I improved the engine slightly and it works slightly better now (but still not as well as it should), but the improvements lead not only to faster players, but also to strange twitching, a flicker-kind of effect on my SDL client.

To figure out what causes the flicker, I needed to check the code for networking. The way my networking code works at the moment is that the server (physics engine) only sends the positions of the players to the clients but no velocity or acceleration, and my SDL client doesn’t calculate the velocity of the player but only places the player where the server tells the client to. This is the simple method used in Quake that lead to problems back in 1996 when 56k baud modems were fast: with a lag of 200 milliseconds and occasional packet loss the client would spend most of the time not knowing where the moving objects (a.k.a. targets) were exactly located. The remedy that id came up with (a technique that was also used in Duke Nukem 3D) was brought to life in QuakeWorld, where the client would “assume” where the players would be located in based on their current/last known position and velocity. This made Quake playable (and a huge online success) even with slower connections (at the time I had a mere 14.4k modem). The technique is called client side prediction and there’s a small section written about it in Wikipedia.

Now, since I don’t expect a crowd of modem using people starting to play Freekick over the Internet, I didn’t implement client side prediction. Since I have the Freekick server and client running on the same computer lag shouldn’t be the cause for twitching anyways. But to make sure the client was receiving updates about the match state fast enough, I raised the server refresh rate, that is, the frequency with which the physics engine sends the match data to the client(s). The delay between refreshes was 40 milliseconds (using threadDelay), which should actually be enough, but I dropped it to 20 milliseconds for testing. Now, with the lightweight threads that Haskell offers (using forkIO) the refresh rate went up indeed, but the flicker stayed. I tried compiling with the “-threaded” parameter, which made the situation only worse, as the minimum thread delay time using “threadDelay” went up to 40 milliseconds on my computer. In the end I stayed with the lightweight threads, which doesn’t really affect my single core anyways, but this points out a problem when optimising the engine for multiple cores.

However, the problem persisted. Since my CPU was still nowhere near 100%, I figured the problem has something to do with how Haskell handles high precision timing. I’ve tried Frag (a 3D shooter written in Haskell) on my computer, and while I was overall impressed by the game, it was hard not to notice how Frag was twitching with regular intervals as well. As I don’t know if there exists a remedy for the problem, nor if the cause indeed is something Haskell specific or just some obscure bug in SDL or in my client, I wanted to go for a completely different approach.

That’s where C++ comes into play. I’ve actually had quite negative opinions about object oriented programming as well as C/C++ in the past, but on the other hand there are some rather impressive and useful libraries available where bindings to Haskell don’t exist and can only be implemented with a lot of work. The library that I thought of first was OGRE, the massively powerful 3D graphics library written in C++. There are actually a couple of articles about calling C++ functions from Haskell (see here and here), but binding a library like OGRE to Haskell using the described methods is not really something I’d like to spend my free time with.

I know that using OGRE for the client side would

a) make the client run faster and with no flicker, and

b) maybe even look a bit nicer

than the current client implementation using SDL, Haskell and 2D pixel-by-pixel drawing methods. The middle way would be to use the apparently very well written Haskell bindings to OpenGL, but I didn’t really enjoy OpenGL very much the last time I used it five years ago and after seeing OGRE in action and realising using OGRE is actually easier than using OpenGL I don’t really have the motivation. Of course, the biggest reason to use OpenGL would be that I could keep on writing the client in Haskell, but in the end it’s probably easier and more effective using C++ and OGRE.

That being decided, the next thing to do was to freshen up my C++ knowledge. I actually never had much of formal education to C++, instead I was using it much like “C with classes”. Even though that was the primary objective of C++ in the beginning, modern C++ is a completely different subject that I somehow had failed to miss until now. So I went and got me the book The C++ Programming Language by Bjarne Stroustrup and studied it through. I can imagine that a lot of people who have no or very little experience with C or object oriented programming find the book confusing, but for me as someone with good knowledge in C and some idea what C++ is about the book was perfect: it explained all the ways C++ can be used to make programming more efficient and less error prone.

I think it’s time for a small analysis about programming languages. After using C and assembly language I’ve gotten a pretty good picture about what the lower-level job of compilers is: shuffling around with the registers, allocating and keeping track of memory, testing for bits and so forth. Languages like C build on top of this, making the whole resource and control flow management easier to write and read.

On the other hand, Haskell approaches the problem from the other side. Haskell is designed from a mathematical point of view while trying to improve the efficiency of the programmer without clinging to the requirements and constraints of the machine, making Haskell code elegant and robust. To me, writing code in Haskell is almost like using a perfect programming language. Between C and Haskell, there’s C++. My impression about C++ was originally (unsurprisingly) that it is not far away from C, but after seeing how C++ improves on C and adds language features that allow the use of completely new programming paradigms (to C), C++ seems more and more Haskell-like to me.

With Haskell I learned to love the fundamental functional programming features that first seemed a little strange to me (like currying, higher order functions, lambdas etc.). I thought with C++ I’d be giving them away in exchange for pointer arithmetic, buffer overflows and unsafe typing, but fortunately I couldn’t have been more wrong. Nearly all of the C features that don’t seem to fit to modern software development are completely unnecessary in C++, and a lot of functional concepts and other features I’d miss from Haskell are brought in either as built-in C++ features (e.g. safer typing, better mutability control), the standard library (lists, currying, higher order functions) and Boost libraries (smart pointers for memory management, lambdas, serialization).

If you check out the Programming Language Shootout, you’ll see that C++ is (as expected) usually faster than Haskell (but the difference is not tremendous). As is also very well known, there exist about ten thousand times more libraries for C++ than for Haskell. In my opinion, those are pretty much all the aspects where C++ is “better” than Haskell. On the other hand, Haskell code is easier to reason about, significantly shorter and therefore easier to read (in my opinion, at the very least) and the concept of type classes is something C++ and the templates still have a lot to learn from, making generic programming far easier and simpler in Haskell than in C++. However, when writing a client for Freekick, performance as well as external libraries do play an important role in the end, and therefore I’ll go for C++. I’m glad I’ve seen Haskell as the finest example on how elegant code can be written, and I’m also glad it’s easy to use the same concepts in C++.

The next thing I’m going to do is read some more about object oriented design (I’ve got Design Patterns waiting for me) and then go and implement a simple Freekick client using OGRE. For that I need to reimplement the Freekick library in C++ as well, which is a nice exercise for OO design (you should plan to throw the first one away anyway, right?). Having the library in C++ would in theory also make it possible to rewrite the server part in C++, in which case I could use a top notch physics library like Bullet as well. But first we’ll see how the client turns out…

Follow

Get every new post delivered to your Inbox.