I’ve been working with Elm a bit now, and I’ve begun to have a feeling for how it works, as well as starting to hit a few problems. It’s perhaps time to consider if I’m going the right way.
It has been a lot better than I expected to be honest. As an imperative programmer by profession, I expected that the functional nature of the language would cause problems. Instead I have been pleasantly surprised by the language.
In particular, I think it naturally structures programs well. The underlying architectural separation of Model / Update / View encourages clear thought about what exactly we want to store, and fits well into the model I need for a simulation game, pushing me clearly to a simple architecture where the data is everything. Fundamentally that’s really what an idle game is; a model that is updated repeatedly that can be prodded at the edges to manipulate it. I also liked the view part of it, although I’ve not really got too far with it.
I also really liked it’s error messages and development environment. It was nice to see something that was helpful and it really helped me get off the ground.
I have a feeling that this might be a very good language for the web, in all honesty. It does seem like the message / update architecture would work nicely if I was trying to write something that prodded APIs or kept state while actions were happening in the background. For a simpler simulation model, this would be nice and easy.
Not so good things
So clearly there’s something that I’m not happy about, and I think I can sum it up in two words: random and pointers.
The random is a real headache. Most games have a reasonable amount of randomness, and the need to drop out of your update routine in order to acquire new random numbers either requires a horrifyingly complex update route, or requires complex forethought to get the numbers you might need before you use them. In this case, where many random numbers are consumed potentially with no interaction other than the timer, this is a massive complexity.
A lack of pointers is an issue that I’ve not really talked about. I feel like I’m having to jump through hoops a lot, since in order to update any part of the model I have to update the whole model. For example, lets say I’m updating the list of actors. This should be nice and easy – I loop through the list of actions and process them – this is a simple map application as I’m doing the same things to each action. Except that each update of the actions will change the rest of the model. In an imperative world I’d pass a pointer to the resources data into the mapped update. Instead I’m doing three passes of the list; one to update the actions, another to update the resources based on the results of the first update, and a third to reset the actions. Now, in retrospect I could do this with an aggregate function that processes the list and accumulates a tuple with the list of updated actions and the updated model, but suddenly I’ve turned a simple list update into a complex operation.
Another relatively small problem that cropped up was lack of dictionary support. Because the model encouraged types that were customised, but those could not be indexes to a dictionary, it made it difficult to add new things such as resources, or buildings – I had to search a lot of lists rather than use the natural typing to create a map.
But this is not a simple application, in that while the interactions are very simple, the underlying simulation is not, and the interest in the game is in that simulation being complex. I’m fighting an unfamiliar language to do something that I really don’t think it’s very good at doing.
There is something I will take away from this however that I think is the right approach to the game: A clear understanding that the update function updates the model, and the model is just data. When I’ve done similar things to this before, I’ve been too object orientated, and not willing enough to consider that not every part of a structure should update itself. In this case, with a complex model, it should be reasonable for me to structure the data so I can modularise it. More on that in another post, though.
If not Elm, what else? Essentially the features I need are:
- Simple setup and development environment
- A language that will support a data model that I can update rather than replace
- Random numbers that are generated immediately
I have a few more that I can look at from my original list, so I’ll have a look there. You never know, though, I may be back to Elm if that’s the best I have available!