Monthly Archive for December, 2008

Let-In

ML family languages provide the let-in construct:

let a = 1 + 2 in a * a;;

This construct evaluates a value, then binds it to a name that is available within the expression that follows. Aside from a little type system requirement (let-in binding is required in order to achieve universal polymorphism safely) this construct can be completely simulated using an anonymous function:

(fun a -> a * a) (1 + 2);;

In some cases, reverting to the original definition can have advantages. One such advantage is the ability to control the lifetime of the binding: a let-in construct defines a name that is evaluated right before the expression is evaluated, but nothing happens, or can be set up to happen automatically, after the expression has been evaluated. For instance, if the program opens a file, an explicit closing operation must be present:

let out = open_out "foo.txt" in output_string out "hello" ; close_out out

When using a function, the caller can be another function which takes care of the removal. For instance:

let on_file filename f =
  let out = open_out filename in
  f out ;
  close_out out 

on_file "foo.txt" (fun out -> output_string out "hello")

Also, when designing a meta-language (that is, a library which helps construct a program in another language) it’s impossible to achieve the level of reflection required to notice that two expressions in the program are identical just by looking at the meta-program:

let result = Lang.call func arg in Lang.multiply result result

This code cannot notice that “result” is being used twice. By contrast, one can use an approach such as:

Lang.let_in (Lang.call func arg) (fun var -> Lang.multiply var var)

Here, the let_in function can create an expression which pushes the expression on a stack or otherwise binds it to a variable, and then generate a pop instruction or read-variable instruction on which the user-provided function is called.  For instance:

let let_in a b =
  let uid = get_uid () in
  LetIn(uid, a, b (GetValue uid))

The Missing Link

In paleontology, a missing link is a transitional fossil that fills the evolutionary gap between two recognized species, both in time and in phenotype.

Quite frequently in the course of software development, certain parts of a program are deemed global at some point in time: there never ought to be a need for more than one instance, nor the need for polymorphic handling of a similar yet distinct part. And sometimes, but not always, this initial impression is proven wrong, and the need for more than one instance arises. The consequences of such an error are usually quite extreme: a one-of global entity tends to be referenced by name, requiring a refactoring effort to convert it to a parameter everywhere this is needed. And so, developers are given the choice between going with the initial impression (with the risk of having to convert it) or ignore the initial impression (and spend time on something they might never need).

I propose here a missing link, a third alternative which implements a one-instance form with minimal effort, yet can be easily refactored into a several-instance if the need arises.

Of course, this applies only in situations where a doubt exists. If it is obvious right away that a given entity will be a several-instance entity, then it should be written as such from the beginning. Only in situations where the current state of the design (especially in Agile methodologies) only requires a single instance should this missing link be considered.

But first, a few background information about this.

Procedural and Objective

A while ago, I wrote a short article that discussed how procedural programming approached the issue of global state. The basic conclusions were that by grouping global state into modules, the number of possible interactions decreased, and those that occurred were made obvious by the structure of the code. As such, a procedural program is a set of stateful entities that interact with each other along a dependency graph.

So is an object-oriented program: stateful objects reference each other and communicate through message-passing. At runtime, there is therefore no major difference in this respect between an object-oriented program and a non-objective procedural program. The main difference is elsewhere. Objects, unlike modules, are rarely defined in the code: they are usually created dynamically at runtime. So, while the two dependency graphs may look the same, the object-oriented runtime dependency graph is a purely dynamic construct that can be altered at will, whereas the procedural runtime dependency graph is a static construct that is tightly mapped to the structure of the code.

Keep It Simple, BridgeThe extensibility of object-oriented programming comes from the dynamic aspects of its dependency graph: if objects can be created, replaced and removed at will, even by the program itself, then the program will have a flexibility and adaptability that exceeds the static module skeleton of a traditional procedural program. On the other hand, the static module skeleton is easier to design and implement than a fully flexible object architecture where elements can be hotplugged—even with language support for object-oriented programming.

When you have to build a bridge, you don’t build a fully automated moving bridge just for the fun of it: if the simplest thing that could possibly work is a plain old suspended bridge with no moving parts, then this is what you do.

Remember that we’re considering here the case of a one-instance object being converted to a multiple-instance object even though there is no apparent need for it yet. Why is that more difficult than using the one instance directly?

  • Polymorphism requires abstraction, and abstraction usually comes from having several instances—then you can identify what’s general and what’s specific. Trying to abstract a concept from a single instance will miss some general aspects that could have been useful, and keep some specific aspects that will limit extensibility.
  • It’s easier to program something which makes sense. If having multiple instances does not make sense yet, then the programmer cannot rely on his instinct or his intuition to determine whether what he’s writing works or not, and the single-instance assumption might fight its way stealthily into the program anyway. Testing a multi-instance system when you only have one instance is quite difficult, too.
  • When using multiple instances, one has to consider what scope they should exist in, and how they are propagated down. Of course, there’s the code required to have the multiple instances trickle down to where they are used. But the real difficulty is deciding what the correct scope is—and since there isn’t a reason yet to consider multiple non-global instances, it’s quite probable that such a decision will turn out to be wrong in the end anyway.
  • Handling a flexible design is harder, mentally, than handling a fixed design. In a static module skeleton, the dependencies are clear and, when they are not, can be extracted from the code very easily. In a dynamic dependency graph, one has to think about how that graph will be constructed at runtime before they know whether a certain piece of code can affect a certain concept (especially if that concept is still a one-instance global).

As such, delaying the setup of a flexible and dynamic dependency graph as long as possible reduces the amount and difficulty of development efforts. The downside, of course, is the refactoring effort required if the initial assumption is proven wrong. A solution to this conundrum would keep the conceptual simplicity of a single-instance static skeleton, while having a code layout that can be easily changed to a multi-instance dynamic graph as soon as the reasons for such a change are discovered.

Singletons?

While often used to implement single-instance cases, the Singleton design pattern does not solve this issue: it is a pattern for representing the single instance, and the problem here is related to how the rest of the program refers to the instance. If all your code uses a certain instance by name, it does not matter whether that instance is a global variable or the instance of a singleton class: that code cannot use a second instance until it uses that instance by reference, and that reference is a parameter of some kind.

So, the choice of a singleton (or any other approach) to represent the instance is completely independent of any solution that could be found to this problem.

Bottom-Up Construction

An approach which can be used in many cases and leads to avoidance of single instances is bottom-up development. Since the system is being built bottom-up, most of the time when a module would need to access a single instance, that single instance has not yet been written or even designed yet. In that situation, the correct approach is to create an interface representing what the module expects, and have a parameter somewhere to receive an instance implementing that interface. Then, when the single instance is finally designed, it can be made to implement that interface (or adapt to it) and then passed as an argument to the relevant elements.

Bottom-up construction eliminates many of the problems related to handling single instances. That is, by refusing to assume anything about the object being used beyond its interface (including, of course, how many instances exist that implement that interface) development automatically deviates from the single-instance approach and can handle multiple instances automatically.

This does not solve everything, however. Bottom-up construction is notoriously ill adapted to fast development cycles, because the actual functionality of the program appears only when the top-level objects have been developed, which is at the end of the cycle. By contrast, with a top-down approach, the top-level object can be developed first and filled with mocks, and the mocks replaced with the actual functionality on the fly. Besides, bottom-up construction is also subject to violating YAGNI, because objects are created before their users exist (and may end up not existing at all).

The Missing Link

The key of the problem here is that directly converting a single-instance approach to a multiple-instance approach requires a lot of argument-passing: since the instances are manipulated through references, and those references are parameters, a lot of parameters are required to pass the instance from its point of creation (quite probably somewhere near the entry point) down to every part of the program that uses it. A possible solution would be do to as much of that work as possible (replacing as many of the global accesses as possible with references) without having to heavily increase the number of parameters.

Aside from global symbols, one other kind of value is available in functions without being passed as a parameter: member variables.

The Screen Design Pattern

The problem: methods of a class needs to access a global variable directly. Making that variable non-global is unnecessary right now, but might be necessary in the future.

The solution: have the class keep a screen member reference to the global variable. That reference is initialized in the constructor and used everywhere else. Member functions other than the constructor are never allowed to reference global variables.

What would be an example of refactoring using this pattern? Consider the original C# code:

public class GlobalUser
{
  public GlobalUser() {}
  public void MethodA() { Global.Instance.Use(); }
  public void MethodB() { Global.Instance.Use(); }
}

Methods in this code use a global instance. Let’s replace that with a member reference to the global instance:

public class GlobalUser
{
  private Global screen;
  public GlobalUser() { this.screen = Global.Instance; }
  public void MethodA() { this.screen.Use(); }
  public void MethodB() { this.screen.Use(); }
}

Using the pattern, the refactored code can be written straight away (instead of writing the original code and then refactoring it) without requiring mental effort, which means that using the pattern bears almost no cost (it only requires an additional member variable and an additional assignment in the constructor). And if the screened variable suddenly has to become non-global, only the constructor will be affected, saving precious time that would have been lost refactoring the methods as well.

Note that creating a property which returns the global variable (instead of a member variable assigned in the constructor) is equivalent in terms of writing the initial refactored code (the this.screen = Global.Instance is replaced with { get { return Global.Instance; } }), but does not have the same benefits when refactoring to remove the global instance because a connection will have to be made between the value returned by the property and the parameter received in the constructor, which requires more code. I therefore suggest using a member variable assigned in the constructor instead of a property.

Also note that the above can be seen as the preliminary step of a dependency injection and follows the same general idea as preparing your application for Spring.NET integration (for example). The difference is that the pattern does so at the class scale, and emphasizes development speed (using the pattern should be no slower than using the non-pattern approach) rather than external interoperability and flexibility.

Memory issues

Of course, storing a screen reference in every object might not be welcome. Some very small objects, such as vectors or polygons, cannot afford to store an additional reference because of the time and space overhead this would imply.

My suggestion in these situations is as follows: eliminate the global dependency altogether. Resist the temptation to have a certain small object frobnicate itself using a global instance, and instead have a larger object frobnicate the small objects. This makes the optimization more transparent (the small objects are now just bits of data without any kind of polymorphic behavior that are externally manipulated) and allows using the Screen design pattern on the larger object.

Game Development Tutorial

Creating video games is not easy, but few things are easy: cooking for ten, writing a book or running ten miles are quite difficult as well. The difference is that with games, people don’t know how to start. To cook for ten people, you know it’s going to involve shopping for ingredients, using a kitchen to boil, simmer, roast and prepare them, and serve them. Writing a book involves typing on your keyboard until you’ve written all the hundreds of pages you wanted to write. Running ten miles involves getting your shoes on and going outside.

But how does one start creating a video game? How does the initial idea of a video game translate to an actual program you can run? This step isn’t the hardest of all steps in game development (far from it) but it deters a lot of otherwise well-motivated wannabes.

As a former game developer (I was the lead programmer for Darklaga : Cannonball Symphony) I will try to answer a few of these questions on the technical side. To this end, I have written a short video game which you can find here, which happens to be a reimplementation of Pong (one of the earliest video games). In this article, I will discuss video game development using that game as an illustration.

How Game Development Works

So, how does a video game get created? It usually follows the same set of steps:

  • A team of designers has a basic idea for a game. it designs most of the high-level details of the game: the look and feel, the various elements and their behavior, win and loss conditions, player controls, and so on.
  • A team of artists creates the graphics and sounds for the game, using their favorite editors and tools and recording studios, according to the designer’s vision.
  • A team of programmers writes the program itself, describing how, where and when the graphics should appear and the sounds should be played, and how the player’s input affects this, according to the designer’s vision.
  • Testers play the game, provide input to the designers, who alter the design to please the testers. The cycle repeats until the testers are happy or money runs out.
  • A publisher takes the game, packages it, sends it to retail stores and advertises it.

Of course, all of this could be done by a single person (Pong), or it could be done by an independent team of five (Darklaga), or it could be done by a professional experienced studio backed by a strong publisher (Red Alert 3).

In an ideal world, you would be able to pitch in an idea, and people would take that idea, create a game from it, publish it and give you a share of the money. This rarely happens in the real world, because games take time to be developed, there’s limited manpower to go around, and so those few idea-pitcher positions are already taken by people with vast amounts of experience and connections in the business. Tom Sloper has a few quite interesting articles about getting your game done, which you can read here.

So, if you have a great game idea, but neither connections nor experience in the business, you’re basically stuck with either giving up or doing it yourself. This will involve either convincing a programmer to work for you, or doing the programming yourself. If you want to try programming, read on.

Programming Games

Video games are computer programs: contraptions designed and written by programmers to make the computer behave in a certain way. Since programmers tend not to be happy with available tools, they often invent new ways of programming computers, which means there are many ways of creating a video game. For instance, the Pong game I wrote for this article is written using a programming language called Javascript (or ECMAScript, depending on whom you ask). The part of the program responsible for making the ball bounce on the screen edges looks like this:

if (this.ball.y + ball.h > field.h)
  { this.ball.vy = - ball.s } 

if (this.ball.y - ball.h < - field.h)
  { this.ball.vy = ball.s }

Different programming languages look different. Sometimes, differences are small, so an equivalent program in the C++ programming language would look like:

if (this -> ball.y + ball::h > field::h)
  { this -> ball.vy = - ball::s } 

if (this -> ball.y - ball::h < - field::h)
  { this -> ball.vy = ball::s }

These two are fairly similar, because both C++ and Javascript belong to the same family of languages (called the C family) and therefore share a lot of features and constructs. By contrast, Objective Caml is a programming language of the ML family, and has a quite different take on things:

method verticalBounce =
  if y -. Const.ball_h < -. Const.field_h then
    {< vy = Const.ball_s >}
  else if y + Const.ball_h > Const.field_h then
    {< vy = -. Const.ball_s >}
  else
    self

Different languages have different capabilities. I chose Javascript because it allows running the game in a browser with no downloading or applets. One could choose the ActionScript language to run a video game in a Flash or Flex applet, or the Java language for running a video game in a Java applet, both within a browser. Developing for Windows or the XBox could involve using the C#, F# or VisualBasic.Net languages. Developing for the PC and most consoles can also happen in the C++ and C languages, as well as one of the many BASIC language variants and many others as well. Writing the central server program for multiplayer games could involve the ErLang or Stackless Python programming languages for performance reasons. Writing a video game for a pocket calculator would involve using the assembly language for that calculator. Every programmer know several languages, and chooses whichever best fits the problem he is solving.

Code is written for humans to read and only incidentally. for computers to execute.
- Donald Knuth

All languages have a thing in common: they’re human-readable text which the computer does not understand, and as such they necessitate a translation phase where the program, written in a programming language, is transformed into a sequence of machine instructions that the computer can execute. This translation sometimes happens before running the program (done by another program called a compiler), and sometimes it happens while running the program (done by another program called an interpreter). Some languages, such as C++, tend to be always compiled, while other languages, such as JavaScript, tend to be always interpreted, and many programs are half-compiled and half-interpreted.

Almost everyone has a Javascript interpreter on their computer: Internet Explorer, Firefox and Safari all bundle one, because web pages tend to use Javascript to make their content dynamic and interact with the user. Because of this, all you need to start programming is a text editor (such as Notepad) to edit javascript files and a web browser (such as Internet Explorer) to view the result. I prefer to use improved tools (the Crimson Editor, Firefox and the Firebug plug-in) because they help me write programs faster.

If I have seen further it is only by standing on the shoulders of Giants.
- Isaac Newton

A very important aspect of programming (and computer usage in general) is the use of existing tools for accomplishing common tasks. Programmers who regularly solve the same problems eventually write down code to solve these problems, once and for all, and then store that code in code libraries. Sometimes, a library is useful enough that it deserves to be published and used by many other programmers worldwide. For instance, my Pong game needs to move green things around on the screen, which is a fairly common task that is already done by the jQuery Javascript library. In general, when a programmer has a difficult task to solve, he usually searches for an existing solution on the web before rolling out his own.

A Programming Primer

This article is not going to teach you how to program. That would require more space and time than I have here. What it can do, however, is teach a few basic elements of programming in Javascript, which you may also find useful in other languages.

The simplest way of executing Javascript is to write it as part of a web page. For instance:

<html>
  <head>
    <title></title>
    <script type="text/javascript">
<![CDATA[
   { write your javascript code here }
]]>
    </script>
  </head>
  <body></body>
</html>

Save this text with the “html” file extension, and start writing Javascript. Open the file in a browser to test it (depending on your security settings, you might have to enable scripts for this to work). Again, I strongly advise you to use the CrimsonEditor/Firefox/Firebug triad for working with Javascript.

Statements, Variables, Values

Javascript is an imperative language: it describes sequences of operations to be performed by the computer. Individual operations are called statements. For instance, the sentence $(document).text(“Hello”) is an operation which replaces the content of the document with the text “Hello”. You can chain several statements together by separating them with semicolons: the statements are then executed in order, left-to-right and top-to-bottom. One very useful statement is the “alert” statement, which creates a message box containing some text:

alert("This is my message")

If you’re using Firebug, you have access to the superior “console.debug” option, which is not as nasty as a message box and allows you to output things more complex than text:

console.debug("This is my message")

Programs manipulate values: these can be numbers, lists of other values, pieces of text, parts of a web page, or even parts of a program. The most elementary operation to be performed with a value is to store it in a variable: this is useful so that values are kept around when you’re not using them. A variable is just a name which is associated with a value: you can retrieve that value at any time by writing the variable’s name, and you can change the value of a variably any time you wish.

Creating a variable uses the “var” keyword, which is reserved for that purpose:

var zero = 0

This statement creates a variable, called zero, and associates it with the number 0. You can use a variable anywhere you would use its value:

var message = "This is my message" ;
alert(message)

This displays “This is my message” in a message box. You can also change the value of a variable after you’ve created it. That operation is called an assignment:

var message = "This is my message" ;
alert(message) ;
message = "On second thought, it isn't" ;
alert(message)

This displays “This is my message” followed by “On second thought, it isn’t”. The first value assigned to the variable is lost, replaced by the second value assigned to the variable.

You can manipulate values in many fashions. For instance, you can have arithmetic operations (+a, -a, a + b, a – b, a / b are fairly obvious, a * b is multiplication, and a % b is the remainder of dividing a by b), comparisons (a == b for equality, a != b for inequality, a < b, a > b, a <= b and a >= b), and logical connectors (a && b : and, a || b: or, !a : not).

Blocks, Functions

I have mentioned earlier that you can manipulate parts of a program. The easiest way of doing so (although somewhat limited) is to use blocks and control structures. A block is zero, one or more statements between curly braces, for instance { a ; b }. A control structure is a special statement which is followed by a block, and executes that block under special circumstances. For example, a conditional statement only executes its associated block if a certain condition is true:

if (age < 13)
{ alert("You are not allowed to view this website")  }

Control statements give you control over which statements are executed in certain situations. They are invaluable for expressing complex behavior in your programs. A typical extension of the conditional statement is to also specify something to be done when the condition is not verified:

if (name == "John") { alert("Hello, John!") }
else                { alert("Who are you?") }

By now, you have probably noticed that I position my blocks and statements around randomly. This is indeed the case: Javascript doesn’t care about the position of your statements and blocks. Just like in English, you can write your sentences every way you wish as long as you don’t split or swap your words.

Another typical control statement is the loop. It executes its associated block repeatedly as long as its condition is true. So, displaying a countdown from 10 to 0 would look like this:

var i = 10 ;
while (i != 0)
{ alert(i) ; i = i - 1 }

The loop displays the number, then substracts one from it, until the number is no longer different from zero.

The improved version of a block is a function: a function is, for all purposes, a block that can be manipulated as a value. This means that you can assign it to variables, keep it around, and execute it when you want it to. You create a function from a block by using the “function()” keyword in front of that block. You then call functions (which executes the corresponding block) by appending two parentheses after the variable name:

var scare = function() { alert("Boo!") }; 

if (surprise)
{ scare() ; alert("Sorry for scaring you!") }
else
{ alert("I'm going to scare you!") ; scare() }

Functions serve several purposed in a program. Their primary purpose is to eliminate repeated code: if you have code which is repeated in several places, turn that code into a function and call the function wherever you need without having to rewrite the code. This even works if you have code that is not identical, but still similar enough:

var i = 1 ;
var total = 0 ;
while (i <= 10) { total = total + i }
alert(total) ; 

i = 1 ;
total = 0;
while (i <= 20) { total = total + i }
alert(total)

These two pieces of code compute the sum of numbers between 1 and 10, and between 1 and 20. The only difference here is the number 10 (or 20). It is then possible to make this number a parameter of a function: when a function has a parameter, a value for that parameter has to be provided when the function is called. The parameter then becomes a variable associated to that value. In this case:

var sum = function(max)
{ var i = 1 ;
  var total = 0 ;
  while (i <= max) { total = total + i }
  alert(total) }; 

sum(10) ;
sum(20)

A function may have several parameters. If that is the case, then the parameter values must be provided in the same order. Parameters enhance the ability of functions to eliminate repetitive code.

The secondary use of functions is to serve in special situations where one needs to represent a block. For instance, the setTimeout() operation registers a function to be executed after a specified duration. So, for instance:

alert("First message") ;
setTimeout(function(){ alert("Third message") }, 3000) ;
alert("Second message")

This displays “First message”. When that message box is closed, it registers “Third message” to be displayed after 3 seconds (3000 milliseconds) and immediately displays “Second message”. Another example is jQuery’s “when document is loaded” operation, $():

$(function(){ alert("Document has finished loading") });

Note that you can define functions and assign them to a new variable in a single action using an alternative simplified syntax:

function sum(max)
{ var i = 1 ;
  var total = 0 ;
  while (i <= max) { total = total + i }
  alert(total) }

Objects, Classes

One other feature of Javascript is the ability to combine several values into one. For example, it’s interesting to store together in a single variable the horizontal and vertical positions of the ball in a Pong game, yet still be able to access them independently. In Javascript, an object is an aggregation of several values: these values are members of the object, and they are given names which allows the program to access them:

var obj = { x : 10, y : 20 } ;
alert (obj.x) ;
alert (obj.y) ;
obj.x = 30 ;
alert (obj.x)

This code creates an object with members x (equals 10) and y (equals 20). It then displays the value of member x, then the value of member y. Then, it changes the value of member x, and displays it again. The result is 10, 20, 30.

When it becomes useful to create many objects along the same pattern, as well as define functions which can operate on these objects, Javascript allows you to define classes of objects. A class is a template which allows the creation of objects which have function members that operate on the object. A class is a template used for the creation of objects. For instance:

function number(x)
{ this.x = x } 

number.prototype.increase = function() { this.x = this.x + 1 } ; 

number.prototype.show = function() { alert(this.x) } ; 

var n = new number(10) ;
n.show() ;
n.increase() ;
n.show()

This example introduces several new concepts, which are all necessary to understand classes:

  • The ‘prototype’ keyword indicates that the ‘number’ function is in fact a class, and defines two functions, ‘increase’ and ‘show’, as being members of all objects of class ‘number’.
  • The ‘new’ keyword creates a new object of the ‘number’ class. That is, it creates an empty object, then adds every function inside the class prototype to that object. Then, it calls the function ‘number’ itself, with the provided parameter values.
  • The ‘this’ keyword acts as a variable. Whenever a member of an object is called,’this’ becomes equal to that object, so that any operations applied to ‘this’ will be applied to the object. When the ‘number’ function is called because of the ‘new’ keyword, ‘this’ becomes equal to the newly created object.

In detail, what the example above does is:

  • Define a function called ‘number’.
  • Decide that ‘number’ is in fact a class, and define member functions ‘increase’ and ‘show’.
  • Create a new instance of ‘number’ : this creates an object, adds the ‘increase’ and ‘show’ functions to it, sets ‘this’ to that object, and calls ‘number’.
  • When ‘number’ is called, it creates a new member ‘x’ and sets it to 10. So, the new object has a member ‘x’ equal to 10.
  • The program calls the ‘show’ function. This sets ‘this’ to the object, and the function reads the ‘x’ member of that object (which equals 10) and displays it.
  • The program calls the ‘increase’ function. This sets ‘this’ to the object, and the function adds one to the ‘x’ member of that object (so it now equals 11).
  • The program calls the ‘show’ function. This sets ‘this’ to the object, and the function reads the ‘x’ member of that object (which is now 11) and displays it.

Note that the value of ‘this’ is restored after a member function returns.

But I Can’t Remember All This!

Of course, you can’t. This kind of stuff takes time and patience to remember. So, take your time and read it a few times. If you don’t understand something, try it out to see for yourself what happens. If you really don’t get it, ask around. I’m willing to answer questions if you ask them in comments to this entry, and you can always ask questions around the good folks at gamedev.net anytime. After a few weeks of practice, you’ll be able to do most of this on your own.

Game Design

Before you jump right into coding (and drawing your assets, if applicable) you need to have a fairly complete and detailed description of the game you intend to develop. Otherwise, like a mason without a plan, the house you build is unlikely to ever be finished, and will crash to the ground in strong wind if it is.

The basic requirements for a pong game are as follows:

  • The Pong game contains a square ball and two rectangular paddles.
  • The ball moves at a certain speed along both horizontal and vertical axis.
  • When it hits the top or bottom of the screen, the vertical velocity is reversed.
  • When it hits the left or right edges of the screen, the horizontal velocity is reversed and the ball is moved to the center (horizontally). The player on the other side gains a point.
  • When it hits a paddle, the horizontal velocity is reversed.
  • Paddles are vertical, and there is one on each side of the screen.
  • They move up and down at a fixed speed.
  • When they hit the top or bottom edges of the screen, they stop moving.
  • They move slightly slower than the ball (so that “follow the ball” is not a winning strategy).
  • The player controls the left paddle, an AI controls the right paddle.

Writing the program

The game is a large piece of functionality. However, programming only allows us to express small bits of functionality. So, we will have to split up the program in smaller pieces before we can create it.

One common way of splitting things is the MVC architecture. MVC stands for Model/View/Controller, which can be explained like this:

  • The Model describes everything that happens behind the scenes. It doesn’t care about how the game will be displayed on the screen, or how the input from the player will be received. What it cares about is where the ball is, where the paddles are, how the ball should bounce when it hits something, and when scores should increase. This will be an entire object containing all the data required to describe the game, along with functions that compute the movement of the paddles and ball over time.
  • The View describes how the game should be displayed. It doesn’t really care why the ball and paddles move a certain way: all it cares about is where the ball and paddles are, and which way they are moving. It gets this information from the model, and displays it in one way or another.
  • The Controller is what makes the game interactive: it reads user input in one way or another, generates AI strategies, and enters all that data into the model. Once the model has computed the new positions and scores, it asks the view to draw it, then starts again.

Applying MVC splits the program in three parts that are much cleaner and, therefore, potentially easier to create. It’s usually considered a good first step when designing a program.

The Model

Since the view depends on the model, and the controller depends on both the view and the model, the first thing to be implemented is usually the model: it’s independent of anything else, and so it can be written on its own.

First, there is data to be stored that will change a lot over time:

  • The position of the ball, as the ball’s velocity.
  • The vertical position of each paddle, and its vertical velocity.
  • The score of each player.

Then, there’s also data that will not change:

  • The default horizontal and vertical speed of the ball.
  • The horizontal position and default vertical speed of the paddles.
  • The dimensions of the field, ball and paddles.

We can store these constants in objects that will never be changed:

var field    = { w: 320, h: 240 };
var paddle   = { x: 300, w:   2, h:  30, s: 76 };
var ball     = { w:   5, h:   5, s: 120 };

The changing data itself should be stored in a model object, which should store the different categories of model data in sub-objects:

function model()
{ var s = ball.s;
  this.left   = {  pos: 0,   vel: 0 };
  this.right  = {  pos: 0,   vel: 0 };
  this.ball   = {    x: 0,     y: 0,
                    vx: s,    vy: s };
  this.scores = { left: 0, right: 0 }
}

Before going on, let’s discuss a bit all these definitions. Obviously, this code creates a model class with data for left and right paddles, a ball, and scores. Constants are also defined to describe the dimensions of the field, paddles and ball, as well as the default speeds of the ball and paddles. This can be inferred fairly easily from the code if you know JavaScript. The unanswered question is, what do those numbers represent?

  • Since the play field is symmetric, I have chosen coordinates (0,0) to represent the center of the field. This way, the top and bottom edges are at -field.h and field.h respectively (which means the total height of the field is, in fact, 480 pixels and not 240 pixels), the left and right edges are at -field.w and field.w (total width of 640 pixels). In general, the width and height are actually half-widths and half-heights, and the position of an object is in fact the position of its center.
  • Speeds are expressed in pixels per second. This means that the ball traverses the field vertically in 2 seconds and horizontally in 2.6 seconds, and the paddles traverse the field vertically in a bit more than 3 seconds (all of this is computed without taking the dimensions of the elements into account).
  • The scores are points. You add one point to the winner’s score on each round.

Initially, everything is centered, and the ball moves to the bottom-right (and since it moves faster than the AI’s paddle, the AI always loses the first round, but that’s not really a problem because it lets the player get his bearings for nearly two seconds).

The most elementary thing that can happen to the model is be controlled: this makes the paddles move by changing their velocity. So, when a player presses a key, the velocity changes, and when the key is released the velocity resets to zero. The model doesn’t care about keys (that is the job of the controller), only about directions, so the movement functions have a direction parameter:

model.prototype.moveLeft = function(d)
{ this.left.vel  = d * paddle.s }; 

model.prototype.moveRight = function(d)
{ this.right.vel = d * paddle.s };

These functions are added to the model class and move the left and right paddle, at the appropriate speed, depending on the direction. Here, we assume that the direction parameter d will equal -1 for “up”, 0 for “don’t move” and 1 for “down”, and we’ll have to take care in the controller in order to guarantee that.

The other thing that the model does is make things move. In the computer world, movement is a quick succession of different images which give the illusion of movement (as with flipbooks). So, instead of working in a continuous motion, the model should skip ahead of time by a certain duration (known as the time step). Here, I’m going to choose a reasonable timestep: 10 milliseconds (that’s 100 steps per second):

var timestep = 0.01;

The update function is pretty heavy: it has to move the objects around (to match those 10 milliseconds) then determine if the ball should bounce, if the paddles should stop moving, and if the scores should increase. The entire function is:

model.prototype.update = function()
{
  var t = timestep; 

  this.left.pos  += t * this.left.vel;
  this.right.pos += t * this.right.vel;
  this.ball.x    += t * this.ball.vx;
  this.ball.y    += t * this.ball.vy; 

  var clip = function(pad)
  { var pos = pad.pos;
    pos = Math.min(pos,field.h - paddle.h);
    pos = Math.max(pos,paddle.h - field.h);
    if (pos != pad.pos) pad.vel = 0;
    pad.pos = pos;
  }; 

  clip(this.left);
  clip(this.right); 

  if (this.ball.y + ball.h > field.h)
  { this.ball.vy = - ball.s } 

  if (this.ball.y - ball.h < - field.h)
  { this.ball.vy = ball.s } 

  if (this.ball.x - ball.h < - paddle.x + paddle.w &&
      this.ball.x + ball.h > - paddle.x - paddle.w &&
      this.ball.y + ball.h > this.left.pos - paddle.h &&
      this.ball.y - ball.h < this.left.pos + paddle.h )
  { this.ball.vx = ball.s } 

  if (this.ball.x - ball.h < paddle.x + paddle.w &&
      this.ball.x + ball.h > paddle.x - paddle.w &&
      this.ball.y + ball.h > this.right.pos - paddle.h &&
      this.ball.y - ball.h < this.right.pos + paddle.h)
  { this.ball.vx = - ball.s }  

  if (this.ball.x - ball.h < -field.w)
  { this.scores.right++;
    this.ball.x = 0;
    this.ball.vx = ball.s } 

  if (this.ball.x + ball.h > field.w)
  { this.scores.left++;
    this.ball.x = 0;
    this.ball.vx = - ball.s } 

};

Let’s go through it step-by-step:

  • First, it moves objects around. This is done by adding (+=) the moved distance (t * speed) to the position of objects. This computes the final position of objects after that step. The next steps then handle collisions.
  • The first collision test is handled by the “clip” function, which prevents the paddles from leaving the screen (it’s a function because there are two paddles, so I created it once and used it for both paddles). The basic rule is: clip the paddle to the screen and, if it went outside, set its speed to zero. Since the position of the paddle is the position of its center, I have to take the height of the paddle into account in order to avoid leaving the field.
  • The next two collision tests happen between the ball and the top and bottom edges of the field: if the ball went beyond these, the vertical speed is set so that the ball moves back into the field.
  • The next two collision tests happen between the ball and the paddles. It tests whether the ball-rectangle hits the paddle-rectangle by checking whether any of them intersect (collision detection is a topic in itself) and if they do, sets the horizontal speed to move back into the field.
  • The last two collision tests check if the ball leaves the field on either side. When this happens, the score of the corresponding player is increased (++), the ball is moved to the center (x=0) and its speed is reversed.

So, if we call the “update” function, it computes the state of the game after 10 milliseconds. If we do it often enough, we can get the game state in real time. Now, we have to display it.

The View

The view is the part of the program responsible for displaying things to the player. It reads data from the model, and somehow maps it to whatever display techniques the program has.

In this example, I’m using the jQuery library. It allows the program to resize and move around DIV elements of a web page (by default, a DIV element is a rectangle with a set position). So, the first step I will take is create the HTML page which will be manipulated by the view:

<html>
  <head><title>Pong</title>
  <script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript" src="pong.js"></script>
  <style>
#playfield {
  color           : black;
  background-color: black;
  border          : 0px none black;
  margin          : 0px;
  padding         : 0px;
  position        : absolute;
  top             : 0px;
  left            : 0px }
div {
  font-size       : 1px;
  color           : white;
  background-color: #33FF33;
  margin          : 0px;
  padding         : 0px;
  position        : absolute;
  top             : 0px;
  left            : 0px }
div.score {
  color           : #33FF33;
  background-color: transparent;
  width           : 640px;
  font-size       : 20px;
  font-family     : courier new }
  </style>
  </head>
  <body>
    <input id="playfield"/>
    <div><div id="paddle_left"/></div>
    <div><div id="paddle_right"/></div>
    <div><div class="score" style="text-align:left" id="score_left">0</div></div>
    <div><div class="score" style="text-align:right" id="score_right">0</div></div>
    <div><div id="ball"/></div>
  </body>
</html>

This creates several rectangles, with identifiers, and also determines their color and margin. Note that the playfield is an “input” (because we need to receive input from the player, so we use this object as a trick). Also, all “div” elements are within “div” elements, to prevent their relative positions from influencing each other (because several elements with an absolute position are within the same body).

Most of the above should be fairly obvious to you (if it isn’t you can peek at a few online courses: html and css).

A point of interest here is the fact that the HTML file includes our script (pong.js) as well as the jQuery script (jquery.js). You can download jQuery here.

what is interesting about jQuery is that it allows selecting the objects quite easily, and then telling them to do things such as moving. An extremely important function in the view is this:

var move = function(avatar,pos,spd,size)
{ var x = pos.x - size.w + field.w;
  var y = pos.y - size.h + field.h;
  avatar.stop()
    .css({left:x,top:y})
    .animate({left:x+10*spd.vx, top:y+10*spd.vy},10000,"linear");
};

This function has four parameters: the ‘avatar’ is a jQuery object representing one of the “div” elements above (the ball, a paddle etc), the ‘pos’ is the position (with x and y coordinates) where that object should be, ‘spd’ is the velocity (with vx and vy coordinates) with which the object moves, and ‘size’ is the dimensions (with w and h coordinates) of that object. The dimensions are required because the position of a jQuery object (with ‘absolute’ positioning, as we are using here) is expressed as an offset between the top-left corner of the screen and the top-left container of the object itself, whereas the position in the model is the offset between the center of the playing field and the center of the object. So, variables ‘x’ and ‘y’ are computed to represent the object’s position on the HTML page.

This function stops the current movement of the avatar with ‘stop()’ then sets the left and top coordinates with ‘css()’, and finally asks the object to move with ‘animate()’ by specifying the destination (which we compute by adding the distance traversed in ten seconds to the current position), the duration (10 seconds = 10000 milliseconds) and the animation style (“linear”, which means there are no accelerations and no brakes).

In short, this function should be called whenever the movement of an object changes: jQuery then takes care of animating the object until its movement changes again. This way, we don’t have to change the movement of objects every ten milliseconds.

However, this requires the view to store the previous value of movement, in order to determine when movement changes by comparing the new value and the old value (if they’re the same, no changes happened). So, the view object would look like this:

function view()
{ this.ball   = {   vx: null,    vy: null };
  this.scores = { left:    0, right:    0 };
  this.paddle = { left: null, right: null };
  this.avatar = { ball: $('div#ball'),
                  sc_l: $('div#score_left'),
                  sc_r: $('div#score_right'),
                  pa_l: $('div#paddle_left'),
                  pa_r: $('div#paddle_right'),
                  play: $('input#playfield') }; 

  this.avatar.ball.width(1.9*ball.w)  .height(1.9*ball.h);
  this.avatar.pa_l.width(1.9*paddle.w).height(1.9*paddle.h);
  this.avatar.pa_r.width(1.9*paddle.w).height(1.9*paddle.h);
  this.avatar.play.width(2*field.w)   .height(2*field.h);
}

This class does the following things:

  • It defines members “ball”, and “paddle” which contain the velocities (but not positions) of paddles and the ball. So, when velocities change, the view notices and asks jQuery to change the trajectories. It also defines the currently displayed score (so that, when these change, they are updated).
  • It defines the avatars: this is done by using the jQuery selector: $(‘div#paddle_left’) selects the DIV element with the identifier ‘paddle_left’ that we defined in the HTML page earlier.
  • It resizes the avatars based on the constants, with the functions ‘width()’ and ‘height()’. Note that the width and height of the ball and paddles are smaller than they should be: this is a common trick for games, since players are bound to notice some close misses and interpret them as “this shouldn’t have missed”, making the image of the paddles and ball smaller reduces near misses and keeps the players happier.

Next, the view object uses a ‘render()’ function to display things. This function will use the ‘move()’ function we defined earlier:

view.prototype.render = function(model)
{ var move = function(avatar,pos,spd,size)
  { var x = pos.x - size.w + field.w;
    var y = pos.y - size.h + field.h;
    avatar.stop()
      .css({left:x,top:y})
      .animate({left:x+10*spd.vx, top:y+10*spd.vy},10000,"linear");
  }; 

  if (this.ball.vx != model.ball.vx || this.ball.vy != model.ball.vy)
  { this.ball.vx = model.ball.vx;
    this.ball.vy = model.ball.vy;
    move(this.avatar.ball,model.ball,this.ball,ball) } 

  if (this.paddle.left != model.left.vel)
  { this.paddle.left = model.left.vel;
    move(this.avatar.pa_l,
         {x: -paddle.x, y:model.left.pos},
         {vx: 0, vy: this.paddle.left}, paddle) } 

  if (this.paddle.right != model.right.vel)
  { this.paddle.right = model.right.vel;
    move(this.avatar.pa_r,
         {x: paddle.x, y: model.right.pos},
         {vx: 0, vy: this.paddle.right}, paddle) } 

  if (this.scores.left != model.scores.left)
  { this.scores.left = model.scores.left;
    this.avatar.sc_l.html(model.scores.left) } 

  if (this.scores.right != model.scores.right)
  { this.scores.right = model.scores.right;
    this.avatar.sc_r.html(model.scores.right) }
}

The render function always checks whether the current value inside the model is different (!=) from the value stored in the view (this). When this is the case, the ‘move’ function is called to move the appropriate avatar in the appropriate fashion (or, in the case of scores, the inner text of the score avatar is changed using the ‘html()’ function from jQuery).

The Controller

The last piece of the game is the controller. It should gather information from the user, compute the AI’s response to ball movement, and measure how long has elapsed since the last time the view has been refreshed and update the model accordingly.

This time, the controller has no reason to be an object, because nobody will manipulate it (except, of course, itself). Instead, we can just define some values inside a function and use them to do the job:

var gameModel = new model();
var gameView  = new view();

As a first step in implementing the controller, we need to extract the keypresses from the user and write a function that applies them. This is done as follows:

  var keys  = { up: false, down: false }; 

  gameView.avatar.play.keydown(function(event){
    if (event.which == 38) keys.up = true;
    if (event.which == 40) keys.down = true;
    return false
  }); 

  gameView.avatar.play.keyup(function(event){
    if (event.which == 38) keys.up = false;
    if (event.which == 40) keys.down = false;
    return false
  });   

  var playerMoveLeft = function(model)
  { model.moveLeft((keys.up ? -1 : 0) + (keys.down ? 1 : 0)); }

The ‘keydown’ function provided by jQueryhas a single parameter, which is a function. That parameter will be called whenever an unpressed key is pressed when the playing field is selected. The same happens for ‘keyup’, which reacts when a pressed key is released. The functions check what the key was by looking at ‘event.which’: a value of 38 is the “up” arrow key while a value of 40 is the “down” arrow key (39 and 41 are the left and right arrow keys, respectively). The functions also use the statement ‘return false’: this notifies the playing field (which is originally a text field from a form) that the key press should be ignored, instead of adding the letter to the field.

What the functions do is set the value of keys.up and keys.down: the “playerMoveLeft” function then reads the value of the keys to determine which keys are currently pressed. The “a ? b : c” construct uses “b” if “a” is true, and “c” otherwise. So:

  • If the up key is pressed but the down key is not, the direction is -1 + 0 = -1
  • If the down key is pressed but the up key is not, the direction is 0 + 1 = 1
  • If neither key is pressed, the direction is 0 + 0 = 0
  • If both keys are pressed, the direction is -1 + 1 = 0

So, the code above correctly responds to player input whenever the ‘playerMoveLeft’ function is called.

Another step is to define a similar aiMoveRight function for computing the AI response. We want the AI do to something smart enough to be challenging. However, since the ball moves slowly from left to right, a perfect AI could simply compute where the ball will land and wait there: it would therefore never lose. This is a good thing for computer science, but a bad thing in game: a good game AI is not an AI that always wins, but an AI that loses in a challenging and fun manner.

The following code accomplishes this:

  var aiMoveRight = function(model)
  { var dir = 0;
    if (model.ball.vx > 0)
    { var dist = (paddle.x - model.ball.x);
      var target = model.ball.y + model.ball.vy * (dist / model.ball.vx);
      while (target > field.h-ball.h || target < ball.h-field.h)
      { if (target > 0) { target = 2*(field.h-ball.h) - target }
        else            { target = 2*(ball.h-field.h) - target }
      }            

      dir =
        (model.right.pos + paddle.h < target ?  1 : 0) +
        (model.right.pos - paddle.h > target ? -1 : 0)  

      var accuracy =
        field.h * Math.exp((model.scores.left - model.scores.right)/3); 

      if (dist > accuracy)
      { dir = -dir }
    } 

    model.moveRight(dir);
  }

The general structure of the code is reasonably easy to get: the code computes the direction in which the AI (right) paddle should move, then sets that direction on the last line. If the ball is not moving right (vx > 0) the AI paddle does not move (dir = 0). However, if the ball is indeed moving right, then the computation starts: the algorithm computes the distance between the ball and the paddle. From that, it computes the point where the ball should meet the paddle (and stores the vertical coordinate in the ‘target’ variable). Once the target is known, the direction is computed: if the paddle is below the target, it moves up, and if it’s above, it moves down. This is a perfect AI: it never loses because it always knows where the ball hits and moves there immediately. So, we dumb it down by adding accuracy: if the ball is further away from the paddle than a certain distance threshold (stored in the ‘accuracy’ variable) then the paddle does the opposite of what it should do (dir = -dir).

The two important questions here are: how is the target determined, and how is the accuracy determined?

The target is computed by determining where the ball would end up if there were no top or bottom edges: one simply calculates the horizontal distance and deduces from the horizontal and vertical speed ratio the vertical distance that it will go from its current position. Once this position is known, the code takes into account bounces: if the target is outside the top or bottom edges, then it will bounce, which means that the target position should be reflected around that edge. For the bottom edge, reflection is done with ‘target = 2*(field.h-ball.h) – target’ and for the top edge it’s done with ‘target = 2*(ball.h-field.h) – target’. The AI repeats this reflection process until the target is within the playing field.

The accuracy is computed by getting the exponential of the score difference (with a few modifiers, ‘field.h’ and ’3′, obtained through playtesting). The point of using an exponential is that, as the score difference increases (in favor of the player) the exponential increases substantially and so the accuracy also increases, and as the score difference increases (in favor of the AI) the exponential decreases substantially without going below zero. So, the point of the exponential is getting an accuracy that increases when the player is doing well, without going below zero.

As a result, the AI starts playing perfectly when the player has three more points than the AI.

The last thing the controller does is keep the model and view up to date. To do this, it computes the current time (in seconds, with decimals) and also remembers the last time it was updated. Then, if the last update is more than one timestep ago, it updates the model and increases the last-update-time by one timestep, and repeats this process until the model is up-to-date. Then, it renders the model.

  var time = function() { return +(new Date) / 1000 };
  var last = time(); 

  var act  = function()
  {
    playerMoveLeft(gameModel);
    aiMoveRight(gameModel); 

    var now = time();
    while (now > last)
    { gameModel.update();
      last += timestep } 

    gameView.render(gameModel);
    setTimeout(act,50);
  }

The time function uses a common trick: it creates a date object (which by default contains the current time), converts it to the number of milliseconds since a fixed point in time, and divides it by 1000. The ‘return’ statement means that when the function is called, it will be replaced by the returned value (var last = time();).

The ‘act()’ function applies input to the game model, then performs as many updates as necessaryand finally renders the model. Then, it asks Javascript to execute ‘act()’ again in 50 milliseconds (that’s 20 times per second).

The result is to wrap all of this in a single ‘controller()’ function and ask jQuery to execute the entire thing when the document has finished loading:

function controller()
{ var gameModel = new model();
  var gameView  = new view();
  var keys  = { up: false, down: false }; 

  gameView.avatar.play.keydown(function(event){
    if (event.which == 38) keys.up = true;
    if (event.which == 40) keys.down = true;
    return false
  }); 

  gameView.avatar.play.keyup(function(event){
    if (event.which == 38) keys.up = false;
    if (event.which == 40) keys.down = false;
    return false
  });   

  var playerMoveLeft = function(model)
  { model.moveLeft((keys.up ? -1 : 0) + (keys.down ? 1 : 0)); } 

  var aiMoveRight = function(model)
  { var dir = 0;
    if (model.ball.vx > 0)
    { var dist = (paddle.x - model.ball.x);
      var target = model.ball.y + model.ball.vy * (dist / model.ball.vx);
      while (target > field.h-ball.h || target < ball.h-field.h)
      { if (target > 0) { target = 2*(field.h-ball.h) - target }
        else            { target = 2*(ball.h-field.h) - target }
      }            

      dir =
        (model.right.pos + paddle.h < target ?  1 : 0) +
        (model.right.pos - paddle.h > target ? -1 : 0)  

      var accuracy =
        field.h * Math.exp((model.scores.left - model.scores.right)/3); 

      if (dist > accuracy)
      { dir = -dir }
    } 

    model.moveRight(dir);
  } 

  var time = function() { return +(new Date) / 1000 };
  var last = time(); 

  var act  = function()
  {
    playerMoveLeft(gameModel);
    aiMoveRight(gameModel); 

    var now = time();
    while (now > last)
    { gameModel.update();
      last += timestep } 

    gameView.render(gameModel);
    setTimeout(act,50);
  } 

  act();
} 

$(function(){new controller});

The Article

This game uses 200 lines of Javascript and 50 lines of quick-and-dirty HTML. It took me about three hours to develop. This article is the longest article so far on Nicollet.Net and took me an entire day to write. You can expect other video games and maybe even other tutorials in the future, in the same vein as this one. If you have questions, or if you have enjoyed this, make sure to add a comment below. Links to this tutorial from places where beginners ask a lot of questions are also most welcome.

Algebraic types, dangerous?

n static languages, algebraic data types allow the creation of complex data types without going through the tedious task of defining a type beforehand. Consider, for example, a grammar description: every rule in a grammar describes how a certain non-terminal symbol can be obtained from a list of terminal and non-terminal symbols, associated to some code that is executed when the rule is matched by the input. As such, one could describe this using the following type:

type grammar = (int * (bool * int) list * string) list

That is, a grammar is a list of rules, and a rule is an integer (the non-terminal being defined), a list of tokens (the identifier, and whether it’s a nonterminal) and some code. Of course, if you were striving for conciseness, this type would never be written down: it would be inferred from how you create, extend and transform the grammar.

And the type system of most languages with algebraic data types will happily infer it without a hitch, leading to concise code with no extraneous definitions.

The problem with this approach is that there is no simple reminder of what is what inside an algebraic data type. Even if the programmer manages to keep types straight (and therefore know what expression has what type) the meaning of some elements might become lost or slightly altered, leading to bugs. And when reading code after a few weeks, the nature of the implicit data type has to be gathered from the code that manipulates it instead of being deduced from member names.

The alternative would have been to define a few types:

type id = int 

type segment =
  { terminal : bool ; id : id } 

type rule =
  { rule : id ; segments : segment list ; code : string } 

type grammar = rule list

This certainly helps: now, the variables being traversed are not the one-letter variables defined in typical lambdas anymore: the structure of the types enforces good naming by adding semantic information to the extraction of data.

Of course, strong-willed programmers can skip this, and directly enforce strong naming constraints when using elements:

let (!!) = Printf.sprintf  

let mapcat list func =
  String.concat " " (List.map func list) 

let print rules =
  mapcat rules
    (fun (rule, segments, code) ->
      let segments =
        mapcat segments
          (fun (terminal, id) ->
            !! "%s%d" (if terminal then "T" else "r") id)
      in !! "r%d:%s{%s};" rule segments code)

In short: when using algebraic data types, semantic information from the problem domain is carried only by the variable names, and especially the arguments of anonymous functions. It is therefore essential that the names of these variables are explicit and clear.

As an aside, note that typical standard library functions tend to place the function to be applied before the data to which it is applied (map func list instead of map list func). However, when using anonymous functions, code at the bottom of the function, which is right above the data, often has no bearing to what the data actually is. This is often noticed when using prefix notation: the first argument is clear, but the second argument is often lost a few lines after the first.

So, my suggestion is, if the data itself is small and the called function itself is local, to swap its arguments (like the mapcat function above) so thatthe data appears before the list. Or, if the data is large, to use the mutator pattern to place it on the left side of the function (so that the sequence operator may be used to identify where the data definition starts).



1170 feed subscribers
(readers who polled a feed this week)