Posted on 09.09.09
A recent reddit thread on the joy of programming contains a lot of comments to the effect that working on green-field code is pleasurable and rewarding, while working on bug-ridden legacy balls of mud represents soul-destroying drudgery.
The past five years or so I’ve been working on very large code bases, in an industrial/high tech setting. The flagship product suite at Almos Systems (wide-area meteorological real-time data collection and analysis) was about a million lines of C++. At ASML it takes 25 - 30 million lines of code to run the latest lithography scanners. And though I would not have believed it 5 years ago, I find working on these immense projects (all with code dating back to the mid ’90’s) the most rewarding work I have done in my career to date.
When faced with an immediate problem, like finding and fixing the root cause of a bug, or adding new features or functionality, the pre-existing mountain of legacy code certainly adds often severe constraints to any potential solution. The lack of freedom that exists compared to starting with a fresh slate can be quite daunting. I can readily imagine that the very prospect sucks the joy out of programming for many people.
On the other hand, programming is about problem solving. Working with large code bases, with legacy code, with reams of undocumented code and the original authors long gone, is in and of itself a challenge. It is generally not an intractable challenge. It isn’t easy, but it is solvable. And this is what I did not know 5 years ago. To be asked to do the impossible, is soul-destroying. To be asked to do the difficult, can be very rewarding.
It requires the the right tools. Testing - adding unit tests, functional tests, integration testing. Refactoring, decoupling, cleaning up interfaces, eliminating dead code, rationalization of API’s. It’s hard and invariably tedious work, but if planned reasonably carefully, and executed methodically, it produces positive results. As I once remarked to a colleague when faced with the seemingly endless prospect of interface normalization, if you have to clean out the Aegean stables and all you have is a small shovel, the only thing you can do is close your eyes and start shovelling. It will seem interminable, but there will come a time that you can reopen your eyes and discover that the manure has all been shovelled away, and the stables are - well, maybe not shiny and new, but certainly a lot cleaner and more tractable than when you started out. And then you can stand back, lean on your shovel, and survey your work with satisfaction.
It also requires teamwork. Programming is by-and-large a solitary activity: even in large projects individual developers prefer to work on a piece of code alone. Maintaining a large code base, used by hundreds to thousands of developers, requires continuous and methodical planning and coordination. Existing functionality must not break, migrations and maintenance efforts must be scheduled and delivered on time, and without hindering the reality of delivering new functionality and following the demands of the market closely. This requires a gregariousness that, while not necessarily atypical of developers, is for many certainly not second nature. The level of communication involved is to some extent at odds with the need of the individual developer to program in peace and quiet, in the “zone". Juggling the conflicting requirements of frequent and precise coordination between developers and development teams, and the need to allow developers to get in the flow and finish their tasks, is work that I find surprisingly enjoyable. I recognise, however, that this is not necessarily the case for everyone. Still, to a large degree, work is what you make of it, and it is certainly possible to derive satisfaction from working on large, hairy projects … maybe even more so than on spanking new problems.Comments Off
Posted on 25.12.08
Over the years I’ve grown attached to the Minimalist GNU for Windows package for C & C++ development on Windows, which I use together with MSYS. I’ve also grown fond of the OCaml compiler, so when version 3.11 was released earlier this month I decided to install it on the Unix systems I work with regularly. I normally build from source, and version 3.11 was as easy to build and install as previous versions.
Yesterday I decided to upgrade the compiler on my Vista laptop from 3.10.2 to 3.11, so I downloaded the self installer for the MinGW toolchain, installed it without fuss, and tried to compile the project I was working on.
To my displeasure, a warning message about missing flexlink.exe was barfed out when I tried running ocamlopt. A brief google session later turned up Alain Frisch’s flexdll site, which had downloads containing the binary flexlink.exe, and this fa.caml thread, which contained instructions of how to make flexlink.exe work nicely with MSYS.
- Download and install the self installer for the MinGW toolchain
- Download the flexdll binary release, and unzip it somewhere temporary.
- copy flexlink.exe and flexdll_mingw.o to the bin directory of your OCaml distribution
- Open an MSYS shell, and edit your profile (
cd /etc; vim profile)
- Add the following line:
export FLEXLINKFLAGS="-nocygpath -L C:\MinGW\lib", where
C:\MinGW\libshould point to the actual lib directory of your MinGW installation
And voíla! ocamlopt works again. Personally I feel that flexlink.exe should be in the binary installer, and it should look for flexdll_mingw.o in ../lib, not in the directory where it’s located (bin).Comments Off
Posted on 01.09.08
I bought the Asus Eee PC 701 (7″ screen, 512 MB memory, 4GB SD card of which 2.5 GB was already taken up by the operating system), primarily for travelling purposes.
After this ocaml was installed and ready for use.No comments
Posted on 19.02.08
A little later than expected, I’ve put out GLCaml release 20080215. The first tar packages contained a GL constant overflow bug on 32-bit systems (which crept in despite testing on a 32-bit system before uploading to Sourceforge from a 64-bit system). My apologies for any users bitten by it. A bug fix release has been put up.
What does it contain? The API has been revamped. In particular, the use of Bigarrays was not very popular: Bigarrays do not coexist effortlessly with native OCaml array types. The problem with using native Ocaml int, float and bool arrays is twofold. First, on 32-bit systems, arrays are limited in length to 4 million elements. Secondly, native Ocaml types (floats excepted) do not match on the bit-level with the native C types used in OpenGL implementations. So conversion between the different types is necessary, and adds an extra layer of inefficiency. In addition, a number of parameters to OpenGL functions are read-write, meaning that for a function call two conversion layers must take place: Ocaml to C, then the function call, and then from C back to Ocaml.
A (not exhaustive) examination of the uses of arrays in OpenGL functions demonstrate three basic uses:
- As array-based alternatives for vertex functions, in which case the typical number of elements is between 2 and 4
- As a fudge to emulate variable parameter passing with variable length arrays, in which another parameter directly or indirectly determines the array length. Typical numbers of elements are between 1 and 4
- As textures or bitmaps
In the first two cases there will be some performance hits translating between types, but this is not significant except in the cases that large amounts of vertex data are being processed. Fortunately float arrays are passed directly to OpenGL, so vertex data passed to functions taking double precision floating point array arguments do not have to carry out any conversions. For case 1 and 2 I decided that the performance hit for conversion to and from Ocaml types was acceptable. (Luckily, I get to define what the definition of “acceptable” is).
For textures and bitmaps, typically void pointers are passed, and another argument informs OpenGL of the nature of the void pointer. A kind of poor man’s run-time type determination, as it were. Textures are large, and copying back and forth would be prohibitive. So there must be some way to pass a texture directly to an OpenGL function without copying it to a Bigarray first. The question is, in what form are textures stored in the first place? Normally, textures are packed arrays of unsigned bytes representing RGB or RGBA values (or RGB[A] values packed into 16-bit words). Other texture formats are possible, such as the representation of a texture as an array of single-precision floating point numbers. In all cases, they do not correspond to arrays of standard Ocaml types (31-bit ints or double precision floats). Additionally, bitmaps are generated and stored by other programs in almost all occasions as packed byte arrays.
The native Ocaml type coming closest to a packed byte array is a string. Strings have a 16 million byte length limitation on 32 bit systems, but can be used to hold texture-maps. In SDLCaml, I have written a pure-Ocaml function to load a TGA bitmap into a string. So I think that OpenGL functions taking void pointers should accept strings.
Also important: bindings to external libraries, such as SDL, generally return pointers to packed byte arrays. SDL.surface_pixels returns such a pointer. So these should be accepted as well.
Solution: void pointers become polymorphic types, and the GLCaml FFI binding looks at the tag of the variable passed in and does a conversion from string or Bigarray accordingly. The downside of this is the possibility of segfaults if something other than a string, a bigarray, or a pointer from an external FFI is passed. But then, I wouldn’t want to deny Ocaml users the dangers associated with void pointers in C.
The second major change is that Glenums (or the glenum type in GLCaml) have been changed to ints. In theory Glenums are enumerated types, in practice OpenGL uses them as both enumerated types and integer arguments. I provided functions to convert between glenums and ints in earlier versions of GLcaml, but converting back and forth between ints and glenums quickly becomes a pain. So the glenums are gone. Everything is an int.
The third change is that silent fails are no longer possible. Every time an OpenGL call fails because the call is not available an exception is raised and has to be handled (or not) by the caller. This is because functions with in/out parameters can leave their parameters in an undefined state. (Ocaml allows string creation with garbage in it, for instance).
There’s some new stuff as well. The Win module, that integrates OpenGL with Ocaml graphics windows on Unix and Windows, has been included. This precludes the necessity for GLUT, SDL or some other library in order to display OpenGL graphics. There have been some bug fixes as well in SDLCaml.
And shaders work. That was the whole reason for revising GLCaml in the first placeComments Off
Posted on 29.12.07
In between the social duties usual during this time of the year I’ve been trying to work on and off on GLCaml. I’ve had some feedback from the (not very large) user base over the past few months and it’s clear that some changes are needed.
For instance, the use of enumerations is a pain, because OpenGL mixes enumerations and integers willy-nilly, and having to convert back-and-forth in Ocaml is just not worth the hassle. Also, although the use of Bigarrays is in my opinion mostly unavoidable, I’m trying to minimize usage where it is not strictly necessary.
A couple of weeks ago, Jon Harrop mailed that he had gotten GL shaders to work, albeit with some difficulty and hand tweaking. I’m taking the opportunity to test shaders and related bindings more thoroughly, but this will take some time.
I think the next release of GLCaml will have some fairly major changes; some cosmetic, some fundamental. Basically GL constants (glenums in GLcaml) will become ints, and as a result GL_ALL_CAPS notation will have to become gl_lower_case notation. But before I release it I’d like to test it reasonably well. Revise and revamp the documentation, examples and website as well. This might take a month or so, depending on free time.
What does all this have to do with Zlib’s inflate algorithm? Nothing. But about a month ago I implemented an Ocaml-only implementation of Zlib’s inflate algorithm (RFC 1951). It’s not the first one: Extlib has one, but using it requires pulling in a lot of other stuff as well. I was writing a pure-Ocaml PNG decoder (mostly done but very buggy, will finish it when I have the time), and needed a simple zlib decoder.
So I wrote one. The source code is available (under the BSD licence). It’s pretty compact: about 250 lines of code, including comments. Usage is very simple: pass a string containing data compressed with the zlib deflate algorithm, and a string large enough to contain the decompressed data, and it returns the same string with the decompressed data.
uncompress -> string -> string -> string. I added a small, simple example to uncompress gzipped files.
The code is based more or less on the specs, with a peek every now and then at Andrew Church’s tinflate.c when I got stuck on some ambiguity or other. It’s pretty compact - 200 lines of code - and pretty slow: gunzip beats it by a factor of 10 to 100. Maybe if I have time I’ll try and optimize it. First I have to find the time to finish the PNG decoder. And GLCaml, of course.Comments Off
Posted on 13.12.07
A finite state machine consists of a finite number of states, and a transition function which, given a state and an input, results in another state and an output.
An example of a simple FSM is a door, such as can be found in an elevator. Such a door requires a push on a button to open it. It opens, remains open for a short period of time, and then automatically closes again.
Normally, such a door would be modelled with two states, Open and Closed, and two transitions: from Closed to Open after a push on the button, and from Open to Close after a time out.
However, I would like to implement such a door as simply as possible. If I were to represent a door as a collection of states, there has to be a state available at any given time. So I use four states: Open, Closing, Closed, and Opening. At any given time the door is in one of these four states. A transition from one state to another is instantaneous. The states themselves, however, have duration. For instance, it takes some time for the door to open or close; once open the door will close after some time, and once closed it remains that way until someone presses a button.
A simple implementation in 20 lines of Ocaml can be found here. The demo takes up another 27 lines of code. (Excluding comments). Compile with
ocamlc graphics.cma unix.cma test.ml -o test and run; press a mouse button to open the door. The doors take 3 seconds to open or close, and an open door will start closing again after 5 seconds.
Screenshot, demonstrating the subtleties of Programmer’s ArtComments Off
Posted on 29.11.07
Ocaml’s floating point numbers are double precision i.e. 64 bytes. There is currently no way to read in 32-bit single precision numbers from a binary stream using the Ocaml standard library. Of course, a small stub function in C to read in a float and return it is always possible. But I find it irritating. So, being ill at home today with the flu and having nothing better to do, I looked up the definition of an IEEE 754 32-bit single precision float on Wikipedia and implemented a pure Ocaml function to read a 32-bit float from a binary stream.
let n = read_float32 ic
where ic is a standard input channel
Update: Jon Harrop points out that there is an Int32.float_of_bits function that achieves the same task. This is like kind of charging a closed door only to find it unlockedComments Off
Posted on 08.08.07
Collision detection is an important part of any physical simulation. The basis is formed by the intersection of primitives, and the triangle-triangle intersection test is one of the most commonly used tests.
As described in the CGA FAQ:
Let the two triangles be and . If lies strictly to one side of the plane containing , or lies strictly to one side of the plane containing , the triangles do not intersect. Otherwise, compute the line of intersection between the planes. Let , for and , denote the interval of intersections between the triangles and the line. Either interval may be empty. and intersect if and only if and overlap.
The Ocaml implementation of this test can be viewed online. Compiling with the command
ocamlopt graphics.cmxa unix.cmxa collision.ml -o collision produces the following program:
A quick comparison with the canonical implementation by Thomas Moeller shows that my straightforward Ocaml implementation runs roughly 5 times as slowly as Moeller’s implementation in C.
My implementation currently handles coplanar triangles rather erratically, so I will either have to add a special function to check and handle coplanar triangles, or possibly check triangle normals for parallelism and perturb one of the triangles slightly to bring it out of plane before applying the normal test.No comments
Posted on 29.07.07
Previously, I had written a simple 1d spring demo.. The next logical step was extension to three dimensions (wholly trivial) and the addition of constraints.
To start with, I begin with the canonical problem: a bead on a round frictionless wire hoop. (This is also equivalent to modeling the bob of a simple rigid pendulum). This is a path constraint. Movement is free along the path, but prohibited in any other direction. This can be represented by a constraint vector and a path. The constraint vector is the local radius of curvature and is perpendicular to the free path. The path represents all the positions in space a particle under that constraint may occupy.
For a bead on a hoop, the constraint vector is simply the radius of curvature, and for a hoop this is a vector of constant magnitude pointing towards the center of the hoop.
Any force acting on the bead produces an acceleration and over a period of time dt a displacement dx. This displacement causes the particle to travel in a straight line to x0, and (often) deviate from the path. So a vector can be constructed starting at the (deviated) position x0 along the constraint vector. This vector will intersect the path at a point x1. At this position a new velocity vector can be constructed tangent to the path (i.e. perpendicular to the constraint vector), with the same magnitude as the velocity vector at x0 (with, however, a different direction).
Source code can be viewed online. Compile with
ocamlopt unix.cmxa graphics.cmxa physics.ml -o physics or
ocamlc unix.cma graphics.cma physics.ml -o physics
Posted on 21.07.07
While playing around with a number of simple integrators I wrote a quick 1 dimensional spring demo. Four point spring unit masses are animated using various methods of evaluation (simple Euler, Newton-Stormer-Verlet, 4th order Runge-Kutta and a simple explicit Verlet integrator.
All four methods have the tendency to explode over time, although the Euler integrator does that the easiest. Somewhat to my surprise both Verlet integrators are more stable than the 4th order Runge Kutta integrator.
Source code can be viewed online. Compile with
ocamlopt unix.cmxa graphics.cmxa physics.ml -o physics or
ocamlc unix.cma graphics.cma physics.ml -o physics
This piece of Ocaml code leaks memory:
let rec main () =
let _ = Graphics.auto_synchronize false in
let _ = Graphics.auto_synchronize true in
let () = Graphics.open_graph ” 800x600″; main ()
Posted on 12.02.07
I’ve always thought it would be nice if it were possible to use OpenGL calls in a window created with the Ocaml Graphics module. This would prevent the need to require external toolkits such as SDL or GLUT.
The Ocaml Graphics module is quite limited compared to SDL or GLUT, and also fills a slightly different niche, but it does come with a number of useful functions for drawing text, various graphics primitives, and for polling mouse and keyboard events. Simple standalone programs or demos can be created and distributed without requiring that the SDL or GLUT shared library be present on those systems.
To get an Ocaml window working with OpenGL I wrote a stub file in C and a few lines of ML code. When the test program is compiled and linked (download a gzipped tar file containing all necessary files here) it results in a program that runs as seen in the screenshot below.
The file win_stub.c and the few lines of ML code in the prologue of win_test.ml is all that is needed to use OpenGL within an Ocaml application. For the actual OpenGL bindings either GLCaml or lablgl will suffice.
For the provided examples, extract the files contained in glgraphics.tar.gz, and run make. Edit the makefile if necessary, to ensure that the line
CLIB=GL is uncommented on Linux, and the line
CLIB=opengl32 gdi32 is uncommented if compiling on Windows with MinGW.
You need the file win_stub.c and the ML code contained in this section, specifically the function init_opengl () and the external functions init_gl’(), find_window() and swap_buffers (). Link the resultant executable with libGL.a on X11, opengl32.lib and gdi32.lib on Windows.
- First set up your caml window with Graphics.open_graph ()
- Next, call the function init_gl ()
- After this you can (re)set the window title (if you set it previously it will be empty)
- Feel free to call any OpenGL calls you wish. lablgl, glcaml and camlgl may all be used.
- You may mix the Ocaml graphics functions with OpenGL.
- Call swap_buffers () any time you need to flip the contents of your back buffer to the screen.
How does it work?
The method used is similar, but not identical, on both Windows and X11. Ocaml does not expose the internals of the window (understandably, because they are highly platform-specific), so they have to be obtained via other means. On both X11 and Win32 you can obtain pointers to internal rendering surfaces of windows provided you can identify them by name. After opening the window with Graphics.open_graph (), the function init_opengl () has to be called. This function gives the current window a (hopefully) unique title Then C code is called which searches through all available windows for a window with that particular name, gets pointers to its internal structure (both Win32 and Xlib allow this) and sets it up for use as an OpenGL surface. This method works on Windows and X11; it may work on OS-X (with a little tweaking in the #defines) but I have not tested that.
Posted on 26.01.07
The GLCaml and SDLCaml bindings proved to be more popular than I had thought they would be, averaging a frenzied 2 downloads per day. (Really, people, restrain yourselves). Still, that’s been around 350 downloads since I first put it up in June ‘06.
So I’ve moved the project to glcaml.sourceforge.net. It’s now got its own website and project page. I’ve updated GLCaml to include support for OpenGL 2.1, which came out in August ‘06. The generated code has been cleaned up, and a minor bug fixed.
Why GLCaml instead of lablgl? Well, GLCaml consists of only three files (two, if you want to forego the .mli file), without any dependencies whatsoever, so you can drop them into whatever project you’re working on, and you’re ready to go. It supports OpenGL up to the latest version (2.1 at the moment), whereas lablgl only supports OpenGL 1.2. It’s a very thin wrapper, so it’s fast. The nomenclature is exactly the same as the native ‘C’ OpenGL API, so you can copy and paste code from books, tutorials and C/C++ projects without trouble.
Why not GLCaml? Well lablgl is elegant, typesafe, it’s been written by smarter people than I (you might want to take that into account before rushing to ship 50K copies of your GLCaml-powered 3D shooter), and it’s been around longer - thus better tested.
GLCaml had a companion library, SDLCaml, which was a similar compact binding to SDL (and in fact somewhat pre-dates GLCaml, since I’d worked on it on-and-off since April ‘06). I’ve decided not to make a separate project page for SDLCaml, but to leave it as a supported, optional library within the GLCaml project. I will continue to maintain and update it, but it won’t be as visible as GLCaml: I do think it’s incredibly handy, but the OCaml landscape is littered with good SDL bindings (like OcamlSDL and Jean-Christophe Filliatre’s ocamlsdl) and mine doesn’t add extremely much value, aside from being very compact.No comments
Posted on 15.01.07
I use Ocaml purely in a private capacity; I’ve noticed that I’ve posted almost exclusively Ocaml code to my blog, which gives a very skewed view of the languages I actually use in everyday life. So what do I like and dislike about Ocaml?
What I like about ocaml
- terse, non-verbose language
- type inference
- good standard library (compared to C or C++), removes a lot of the need to roll-your-own data structures
- Closures, first class functions, lambdas, currying, pattern matching, variants
- fast, generally non-intrusive garbage collection
- no pointers
- fast compiler, fast executables
- excellent support for both functional and imperative programming
- reasonably good foreign function interface, at least for C code
- Self-contained executables, allowing the distribution of small programs without a huge accompanying VM framework (possibly justifiable for languages piggybacking on top of the JVM or CLR, but deadly for tiny niche languages like Mercury, AliceML, Mozart-Oz etc)
What I don’t like about ocaml
Lack of arbitrary precision integer arithmetic (like Haskell, or Scheme’s Bignums)
- Native int, array and string size limitations on 32-bit machines. The 4MB limit on arrays and 16MB limit on strings is especially irritating. On 64-bit machines Ocaml is a lot better.
- Aesthetically unpleasing in places (’;', ‘;;’, ‘+.’ and co, ‘let rec’ versus ‘let’, begin-end and if-else blocks, scope delimiters)
- native windows toolchain support is minimal, especially w.r.t IDEs and debugging
- compiler warning and error messages are terse and minimal
What I’m indifferent about
- OO features
Reasons to use ocaml in a commercial setting
- Strict type inteference, automatic memory management, and lack of pointers automatically eliminates entire classes of bugs. Troubleshooting consists mainly of chasing bugs in logic, not investigating mysterious segfaults.
- Cross platform, with reasonably consistent behaviour across platforms compared to C, C++ and even Java.
- Toolchain is minimalistic but complete, on most major platforms
- Good performance
- Few dependencies
- For some application domains there is reasonable standard and third-party library support available
- There is a reasonable amount of available (open source) source code for a variety of domains
Reasons not to use ocaml in a commercial setting
- Non-mainstream language, difficult to find programmers experienced in Ocaml, ML or Haskell (cross-over between these languages is relatively easy; someone versed in Haskell will have no difficulty in picking up Ocaml, and will already have acquired the right programming habits)
- For programmers without prior functional language exposure (the vast majority), Ocaml has a non-trivial learning curve.
- For some application domains, standard and third-party library support is lousy (especially GUIs) (The very similar language F# changes some of the dynamics, being a .NET language.)
- Ocaml has, and is defined by, a single implementation; it’s open source but the existing user base is too small to maintain it in the absence of Xavier Leroy and team.
- Documentation and tutorials for the language, tools and third party libraries are generally sparse (although often better than for other functional languages)
Posted on 30.12.06
This is a little experiment in abstracting away explicit state in functional programming. Objects, such as avatars in a game, or widgets in a GUI, are normally represented by objects that have an explicit, time-dependent, mutable state. The underlying idea behind widgets is that a widget should consist of two things:
- A function to process any mouse and keyboard input delivered to it
- A function to display itself.
I would like to abstract the rendering and event-gathering details away as much as possible. Instead of a widget being represented by a mutable structure, immutable structures can be used to represent different states of a particular widget.
For example, consider a simple push button widget. A simple push button has the following properties:
- dimension (top, left, width, height)
- state (pressed, unpressed)
When a push button receives an input event, such as a mouse button click, it checks to see if that click occurred within its boundaries. In a stateful framework, the click toggles a mutable state variable from ‘unpressed’ to ‘pressed’, and this in turn triggers a redraw function to render the button in its pressed state. At this point an event handler function is triggered.
However a simple push button can also be replaced by two widgets, representing the ‘pressed’, and ‘unpressed’ state respectively. The ‘unpressed’ widget will have a function to draw itself. Its input-processing function will check to see if a click occurred within its boundaries, and if not, return itself, or else return a ‘pressed’ widget. This ‘pressed’ widget will also know how to draw itself. Both ‘pressed’ and ‘unpressed’ widgets have no knowledge of how to draw each other, or have indeed any knowledge of each other.
The widget interface will consist of a type composed of a function that processes events (signature: fun mouse_x mouse_y mouse_button key_pressed -> returns a new widget) and a function to draw the widget itself. Certain general information needs to be passed around, nevertheless. Normally this is done by passing a general catch-all argument: a structure with appropriate fields containing the necessary information. However I want to eliminate this as well: a passed structure would simply bloat to accomodate each new widget type. Instead I’m going to try and use closures to preserve the strict function type signatures while allowing almost unlimited latitude in information passing.
To this end I’ve written an exceedingly simple test program, consisting of two embarassingly bare-bones “buttons". One is a static, square push button that changes colour from black to red when it gets the focus. The other is a draggable, circular button that changes colour from black to red when it gets the focus, and changes colour to yellow when it is being dragged around. Compile with
ocamlc -o test graphics.cma test.ml. The result looks like this:
Posted on 08.11.06
‘BASIC used to be on every computer a child touched – but today there’s no easy way for kids to get hooked on programming.’
“What’s important is having an easy to use graphics API. I don’t mean easy like GLUT or SDL, say. I mean easy. On my BBC Micro years ago I could type a command to go into a ‘high-res’ graphics mode and then start interactively typing in graphics commands. Within 5 seconds of switching it on I could have graphics of my own creation on the screen. In a modern OS I have to write a few hundred lines of code just to grab a window reliably, and when I’ve done that, I can’t experiment interactively. Kids need instant feedback. Even the kids of my generation, before ADD had been invented, needed instant feedback.”
Graphics on the BBC were very easy. Here is one of my first programs. Note that the exclamation marks are not optional:
“PRINT “[shift+f1][shift+f8]EDWARD RULEZ!!!!!!!!!!!!![shift+f0]”
This printed a message about me in flashing red text. An addition of another [ctrl+f?] allows the text to be mixed with coarse graphics. This is particularly appealing, since it requires next to no knowledge, which is why it was one of my first programs. The next program propably proceeded that line with the SOUND command.
My point is that the barrier to entry was so low that it was hard to get discouraged and give up.”
make me scratch my head in puzzlement, because I would say the exact opposite is the case.
Posted on 25.08.06
As a kind of finger exercise, a short (less than 60 lines, including comments) linear algebra listing of one, two or three-liner vector and matrix functions, including vector addition, subtraction, negation, scaling, dot product, matrix addition and subtraction, matrix-vector multiplication, matrix-matrix multiplication, matrix transpose, determinant, and matrix inverse.
These functions work (theoretically) on vectors of any dimension, and square matrices of any rank.
I wrote it to see how compact I could get the code using functional idioms, without intentional obfuscation. The code is therefore not the most efficient for either vectors or matrices of low dimension (where special casing would be of benefit), or high dimension (matrix inversion, for instance is done naively using the matrix’s adjugate and the performance of such an approach will not scale well at all with increasing dimension).
But it is short, anyhow.
Posted on 30.06.06
UPDATE: This project has moved to glcaml.sourceforge.net.
The (automatically generated) OpenGL bindings cover OpenGL 1.1, 1.2, 1.3, 1.4, 1.5, 2.0 and most current non-platform-specific extensions. There are no dependencies whatsoever: the system opengl shared library is loaded dynamically, and the functions are called dynamically, so there is no need to link against import libraries.
The SDL bindings are fairly but not wholly complete; they are hand-written and functions are bound on an as-needed-by me basis. They are only dependent on the SDL main library and not on the mixer, ttf or image libraries. Because I wanted to have basic sound capabilities, the SDL_Audio modules are implemented, along with extra functions for panning and pitch shifting audio buffers.
- The source code, in a tar gzipped file, along with around 20 examples
- The documentation, fairly complete for SDL
This has been tested and works on Windows 2000, Windows XP, and Ubuntu Linux running on AMD64.
On Windows I use the mingw Ocaml compiler suite along with the msys shell; the source tarball contains makefiles that work as-is on the Windows mingw/msys port and under Linux. It will probably work as-is for the cygwin port of Ocaml, and will definitely need some tweaking to work under the Visual-C port.
Posted on 12.05.06
I saw this article on cellular textures and wrote an Ocaml cellular texture generator (source code, public domain).
ocamlc graphics.cma celltexture.ml -o cell
ocamlopt graphics.cmxa celltexture.ml -o cell
The end result looks like this:
Posted on 11.05.06
Mark Probst (see his website) wrote a very bare-bones proof-of-concept scheme interpreter in Objective Caml, licensed under the GPL. Good stuff, well written, easy to extend. I rearranged the code a trifle, added floats and strings, apply, line comments, and a bunch of built-ins for a small project I was doing, and some basic error-messages (line number and approximate cause of whatever’s making the interpreter barf). There’s also an extract_string function in the parser that I’m pretty sure I didn’t write myself, but it’s been a year and I have no idea where I got it from. It’s not R5RS compliant, or R-anything-RS compliant; in fact since there are no guarantees that tail recursion will run in constant space it’s probably better not to think of it as a scheme implementation, per se. It’s more of a pseudo scheme.
The OCaml source code can be downloaded here, under the same licence as the original, the GPL.Comments Off
Posted on 24.12.05
My old workstation, a second-hand 1Ghz Duron probably born sometime around 2001, had been flakey for a month. It begun to require a number of attempts before it would power up and boot successfully, so a little earlier than I’d originally planned for I decided to buy a new PC.
It wound up being a budget AMD 64 Sempron with a 160 GB hard disk, 1Gb of memory, and an Nvidia 6200 with 256 Mb of video memory. I bought it from PC Dump Winkel for, if memory serves, around 500 euros. Buying it took all of 30 minutes, and that was including the drive to Waalwijk to pick it up after placing the order at the Den Bosch branch.
The (slightly) more time consuming part was installing Linux.
Posted on 14.05.05
Last autumn, on holiday in Rhodos, I was ill with the flu during the first week there, and so amused myself during the first couple of days by playing around with Ocaml a little. I wrote a coding diary to document my experiences; it was written purely for myself but I’ve decided to put it up here …
Posted on 07.03.05
Posted on 04.03.05
Posted on 10.08.04
These are notes for my own future reference.
Objective Caml can be downloaded from the ocaml website. The front page is infrequently updated; the latest ocaml compiler version displayed in the “News” section there is out of date with the release version (3.07 versus 3.08 as of writing).
Posted on 21.06.04
Cheating in online networked games is a serious problem, that is spoiling the game-playing experience for non-cheaters. This is especially so with open-source projects, where server and client source code is open and readily available for hacking by anyone with the ability and desire to do so.
Since I have a passing interest in networked multiplayer vapourware, I’ve been giving some thought to methods of making online gaming relatively secure from cheating. I’m primarily interested in server-client game models, not peer-to-peer, and my main interest is in FPS/RPG type games, although I suspect the same principles apply to other forms of online games.
Posted on 11.06.04
I have been using Mandrake Linux as the sole operating system on my home computer for about a year now. I still use Windows (2000, NT) almost exclusively at work. I made the decision to use Linux at home because I’m an old fashioned stickler for using only legal software, and a skintflint when it comes to paying for it. I do not own, as far as I know, any pirated software, and on Windows that limited my choices somewhat. Not terribly so: there is a windows port of the OpenOffice suite, and for programming I used the MinGW toolkit, and that combination covers 90% of my daily needs. Nevertheless using exclusively free software on Windows means constantly dealing with non-industry standard applications on that platform, and it was giving me a feeling akin to being a second-class citizen.