CS 498MC Martian Computing at the University of Illinois at Urbana–Champaign
mint
, nest
, and other checks produce.We distinguish different aspects of programming flaws based on their observational mode:
A failure refers to the observably incorrect behavior of a program. This can include segmentation faults, erroneous output, and erratic results.
A fault refers to a discrepancy in code that results in a failure.
An error is the mistake in human judgment or implementation that caused the fault. Note that many errors are latent or masked.
A latent error is one which will arise under conditions which have not yet been tested.
A masked error is one whose effect is concealed by another aspect of the program, either another error or an aggregating feature.
We casually refer to all of these as bugs.
An exception is a manifestation of unexpected behavior which can give rise to a failure, but some languages—notably Python—use exceptions in normal processing as well.
Let’s enumerate the errors we know about at this point:
We know what Ford is: it’s the build vane. ++ride
is the end-to-end Hoon compiler, which Ford is of course using to build the abstract syntax tree (AST). Two %ride failed
errors are common: "%ride failed to compute type"
and "%ride failed to execute"
. %slim failed
means (one kind of) type issues, typically due to %ride
failure. nest-fail
indicates a failure to match the expected call signature of a gate.
The mint
errors arise from typechecking errors:
mint-vain
means a Hoon never executes.mint-nice
occurs with casts.mint-lost
means that a branch in a conditional can never be reached.For instance, conversion without casting via auras fails because
^-(tape ~[78 97 114 110 105 97])
A fish-loop
arise when using a recursive mold definition like list
. Alas, this fails today:
?=((list @) ~[1 2 3 4])
generator-build-fail
most commonly results from composing code with mismatched runes (and thus the wrong children including hanging expected-but-empty slots).
mull-grow
means it’s compiling the callsite of a wet gate (a generic gate; we’ll see these later).
If you really crash things hard—like crash the executable itself—then it’s a bail
, which has the following modes:
%exit
, semantic failure%evil
, bad crypto%intr
, interrupt%fail
, execution failure%foul
, assertion of failure%need
, network block%meme
, out of memory (this is the most common one in my experience)%time
, operation timed out%oops
, assertion failed (contrast with %fail
)Finally, although hinting at darker powers not yet unleashed, you can start a debugging console with |start %dbug
and access it at your ship’s URL followed by ~debug
(e.g., http://localhost:8080/~debug
).
What are some strategies for debugging?
Assuming that you are working within Urbit (i.e. in or on Arvo, not in the underlying host OS), you don’t have a debugger or a profiler available*. In that case, you have the slight help of the error message (a condition indicated as promoting “moral fiber”) and some standard debugging strategies:
Debugging stack. Use the !:
zapcol rune to turn on the debugging stack, !.
zapdot to turn it off again.
printf
debugging. If your code will compile and run, employ ~&
frequently to make sure that your code is doing what you think it’s doing.
The only wolf in Alaska. Essentially a bisection search, you split your code into smaller modules and run each part until you know where the bug arose (where the wolf howled). Then you keep fencing it in tighter and tighter until you know where it arose.
Build it again. Remove all of the complicated code from your program and add it in one line at a time. For instance, replace a complicated function with either a ~&
and !!
, or return a known static hard-coded value instead. That way as you reintroduce lines of code or parts of expressions you can narrow down what went wrong and why.
If you run the Urbit executable with -L
, you cut off external networking. This is helpful if you want to mess with a copy of your actual ship without producing remote effects. That is, if other parts of Ames don’t know what you’re doing, then you can delete that copy (COPY!) of your pier and continue with the original. This is an alternative to using fakezods which is occasionally helpful in debugging userspace apps in Gall.
The trouble with %sandbox
code is that only %home
desk code gets built by ++ford
as executable. That may change someday, but it’s why we prefer fakezods instead of development desks today.
* I have found a reference to profiling support in the docs. ~$
sigbuc also plays a role as a profiling hit counter but I’ve not seen it used in practice as it would be stripped out of kernel code before being released.
Tlon suggests grading code according to certain stylistic and functional criteria:
But don’t produce A code on the first pass! Let the code mature for a while at C or B before you refine it into final form.