-
Notifications
You must be signed in to change notification settings - Fork 139
Coding Guidelines
The existing code has a certain style. Submissions should make a good attempt at fitting in.
The unusual appearance is a side effect of writing C as concisely as possible. There are great benefits to writing code in this way. Someone familiar with the style can read and comprehend the code much faster than they could with traditional code. Brevity creates a discipline that reduces bugs. Some of the benefits will not be apparent until you try it. Some of the downsides of the style are inaccessibility and a steep learning curve.
Kona is an exercise in using the coding style of Arthur Whitney. Ostensibly Arthur uses C, but actually he uses the C preprocessor to create a terse language of his own. Take a look at buddy . This file has 2 versions of the “buddy space allocation” system. The first version was written by Arthur and consists of 11 lines. The second version was Morgan Stanley’s baseline version (back in 1992) written in traditional, well documented C and consists of almost 750 lines of code.
The project has good test coverage. There are several hundred tests and they automatically detect memory leaks. Build the tests into the binary by defining DEBUG
. This can be done from the command line using cc -DDEBUG
. You can also produce the test binary using make test
. It is not difficult to get your editor to run the test suite and drop into the interpreter with a single button press. Contributors are expected to run and pass the tests before submitting. Additional tests are always appreciated. See tests.c
for more.
A return value of 0
indicates an error. The name of the error is set in the errmsg
string using the kerr
function. Zero values should bubble up through functions. The special macros U()
and P()
exist to check that an object was allocated correctly or that a given condition was met. The M()
macro can ensure consistency when allocating multiple objects.
When a error is encountered midway through the construction of an object, you must back out of the construction and deallocate the work in progress using cd()
before bubbling up. This complicates the way code is written. It may not be the correct way to do things. Other languages have techniques for minimizing this effect. We may change how this works in the future. Suggestions are welcome.
When a K object is created it has reference count 1. The number of references must be tracked. When a reference disappears, cd()
must be called on the object. When a reference is added after creation, ci()
must be called on the object. When cd()
reduces the reference count to zero, the memory used by the object is returned to the K memory pool (or unmapped). The K execution loop handles reference counting for values returned from verbs. In general, if you create a K object that isn’t part of the return value of a verb, you will have to cd()
that value at some point. It is rare to call ci()
. The initial reference count is sufficient when building nested K objects.
Running out of memory poses a special problem. The M()
macro exists to ensure all objects were allocated successfully before proceeding with the computation. M()
handles decrementing the count on existing allocated objects if any of the objects failed to allocate. Otherwise, out of memory errors should be treated as regular errors and bubbled up.