Developer

The Samurai Principle

Death or Glory! Builder AU's Nick Gibson shows how you can use the Samurai Principle to write better code.

Anyone who's seen Rashomon should be familiar with the Bushido, the Japanese "way of the warrior", a code of conduct providing instruction on all parts of life, but especially for a warrior in battle. Bushido emphasises the vital importance of personal honour, even to the death, Japanese warriors — the Samurai — were expected to fight until the bitter end, to "Return victorious, or not at all". What does this ancient code of conduct have to do with software design? For programmers, the Samurai Principle is also a style guideline, primarily intended when using languages that favour exceptions. Put simply, a method should either successfully complete its task, or contract, and return a valid result, or it should throw an exception and stop: Return success, or not at all. This is aimed at eliminating the old practice of using return codes or null objects to indicate that a method has failed or encountered something unexpected.

Hang on, you say, we've been doing things that way for years, and besides, isn't using exceptions all the time going to slow down my program? It might, if you're throwing them around a lot, but there are some definite advantages of the Samurai Principle to compensate:

  1. Safety — If you apply the Samurai Principle religiously then you can always be sure that outside of exception handling blocks, your program will be a safe state. Now an assurance such as this isn't unique to this methodology, you can achieve this advantage just as well by ensuring you check the return values of any function that could fail, however by replacing this with exceptions you get this safety for free, or at least for nothing more than the cost of handling the exception
  2. Consistency — Choosing consistent error codes is hard, because they depend not on the type of error that has occurred, but rather, the return type of the function or method. A method that returns positive integers might be able to use -1 as an error value, but this won't work if the method is to return a list. If you have two functions that can indicate the same error but have different return types, then you must identify this error in different ways, which could lead to problems of maintainability
  3. Clarity — By avoiding error codes or sentinel values we can reference the results of a function in a more natural way. This is particularly noticeable when doing arithmetic operations; for example, if the following code was written with the Samurai principle in mind, and the function countItems() throws exceptions on error, then the following code can be used quite safely:
    int cost = countItems(a) * itemCost(a);

    However, if countItems can return an error code, for example, by returning -1 on error, then the code would need to be rewritten like so:

    int cost = countItems(a);
    if (x != -1) {
        x *= itemCost(a);
    }
    

As you might expect, this idiom is more popular in languages that favour exceptions as the way to escape from errors. The Python standard library follows the Samurai Principle, and by and large so does the Java API. Naturally, like in most things there are a few exceptions (no pun intended) to the rule of applying the Samurai Principle. For example, in Python the substring searching function str.find and the regular expression matching function re.match both return an error code when they fail. str.find either returns the index at which the substring first occurs, or -1 if the substring does not occur at all within the string. Similarly re.match returns None instead of a match object if the expression is not matched. It might appear at first glance that this is out of place, but if you think about it, it all depends upon how you define a functions task, or contract.

Search problems are a special class of problems because it's perfectly acceptable for them to fail to find what they're looking for. Since it's common to use a search function to check if an item does not exist, not finding this item cannot be considered an error, and so interrupting the program with an exception is a bad idea. Most implementations of search functions would return a sentinel value here, however if not carefully managed this can still leave your program vulnerable to the problems of consistency and a lack of state safety. Also, if a null value can occur in the set to be searched, then it cannot be reasonably used as a sentinel value, and some types, such as integers, do not generally allow you to assign NULL to them.

Another way of dealing with this problem has been introduced in some newer programming language — optional types — denoted by Maybe in Haskell or option in Ocaml. Optional types let you define the result of a function either as standard type, or as Nothing. This allows you to do the same thing as using NULL as a sentinel, but avoids the problems of safety and consistency caused by traditional sentinels since Nothing values exist only when using optional types, and all optional types must be manually declared. This has the advantage of ensuring that a Nothing value cannot spread to other parts of your code you don't intend, making tracking down an unexpected bug a lot easier.

Sticking to design principles such as this may seem restrictive, but by adopting some smart guidelines, you make your code easier to maintain, easier to extend and ultimately easier to read. If nothing else, investigating ideas like the Samurai Principle can give you some new ways to think about how you go about writing software.

Editor's Picks

Free Newsletters, In your Inbox