A r t i c l e s
Navigation

Note: This site is
a bit older, personal views
may have changed.

M a i n P a g e

D i r e c t o r y

Suggestion for Modern Pascal Error Contracts


Note: when I use the term 'contracts' I'm not speaking of Eiffel or existing contract philosophies. I'm just using the term contract because the error happens within our programmer contract on the screen (interface specification, declaration, etc.).
Exceptions hide errors and other things in upstream code, basically implying that Out of site, out of mind and ignorance is bliss is a better way of programming. Hide your error system (raise) in upstream code, and magically all your error problems go away! Oh really.

What a "raise" is: an intraprocedural goto... Worse than a local goto!

Error codes on the other hand expose your errors in the function using if logic and the code becomes overly verbose with error correcting code..


Something I've always hated are Exceptions and Error codes (well, a love hate relationship... but a lot more hate than love). In many ways each has some advantages over the other. Can we develop a better error system than error codes or exceptions though?

The solution

A function like this:
  function StrToInt(s: string): integer;         {the result contract}
                                error: boolean;  {the error contract}

The above function returns an integer, but also an error. If a compiler setting is on that forces the error contract, then the program will not compile if the user has not checked for the error properly. If the compiler setting is off, then the programmer can get away with sloppy programming and not all errors must be checked.

This could be a function that returns a tuple (two function results) or it could be built into the compiler in a different way (returning a hidden Var parameter).

Update: August 2015: It seems Go Language from Google has implemented something very similar to error contracts proposed in this article. I wrote this article many years ago (not in 2015 it must have been 200X) back in the day when Go Language was possibly unknown to man. Interesting that some languages are getting better hopefully than our current messes. Whether google Go implements true error contracts that can be checked and enforced though is something to be researched further.. is google Go mission critical?

Some examples

Below: example 2 is just an idea.. example 1 is a tuple way of doing it. A tuple is kind of like returning a Record or Struct with two fields but without the annoyance of having to declare a record type for every function (it's a usability issue, just like SELF in object orientation is hidden from us).

There are a few different ideas I came up with on how to handle the error:

example 1...

begin
  i:= StrToInt('12345ty');
  // we could just handle the error here, but see the second example too
  if i.error then 
  begin
    writeln('bad!! please enter a number, no text allowed');
    halt; // you don't have to halt, it is up to you
  end;
  inc(i);
  i:= i + 60;
  inc(i);
end.

example 2...

begin
  i:= StrToInt('12345ty');
  // if an error occurs above, the i.error label is executed below instead 
  // of continuing
  // else we continue on with our regular programming
  inc(i);
  i:= i + 60;
  inc(i);

  // error labels
  i.error: 
  begin
    writeln('bad!! please enter a number, no text allowed');
    halt; // you don't have to halt, it is up to you
  end;
end.

Extra 'error' parameters in the function are ugly and we should not bloat up the function declaration with many extra parameters. However, function results are clean and elegant. The language should have a contractual error system built into the function declaration. The function declaration is the contract. Exceptions are not in the contract!

The old way of doing errors is to use a var param:

  StrToInt(s: string; var error: boolean): integer;
Extra function var parameters in roll your own error systems are not enforced, because it is a roll your own error system rather than an error contract system like I am proposing which a compiler can know about.

Exceptions can kind of be enforced in a way (i.e. java?), but this causes most programmers to just not use enforced exceptions because exception programming is too hard to get right, and it becomes tedious to trap every single exception under the sun, and code becomes just as convoluted as error codes (despite the naive view that somehow magically exceptions just wish away the truth and make it disappear).

If we were to use ugly parameters for error code returning, then we'd have a bloated up function like this:

  function StrToInt(s: string; var SomeError: boolean): integer;
  function StrToInt(s: string; out SomeError: boolean): integer;
or we return the result as a parameter and return the error as the function result:
  function StrToInt(s: string; var res: integer): error;

This is the old way, and not ideal compared to an error contract system.

You might be thinking, what is the difference between the old way and the new contract example at the top of the page? We still have to declare the error in the contract? What's the big deal? Well, extra function parameters are much less elegant and are not enforced.. one can make a dummy var parameter and ignore it. Error contracts are parseable by the compiler.. as errors.. special errors.

It's similar to SELF in object oriented programming. It's just a matter of elegance. Self doesn't have to be used in object oriented code.. you could pass in the object instance as a parameter each time.. but why do so if the compiler already supports SELF as a hidden var parameter?

With error codes as old var parameters, we'd have to declare a temporary SomeError variable which bloats up declarations everywhere.

var 
  SomeError: boolean; { bloat up declarations here too }
begin
  i:= StrToInt('12345ty', SomeError);
  if SomeError = true then 
  begin
    writeln('bad!! please enter a number, no text allowed');
    halt; // you don't have to halt, it is up to you
  end;
  // now continue on with your regular programming
  inc(i);
end.
With error codes as simple function results (not a second result), we have another problem: The actual function purpose is not to return a error, its purpose is to return something like an integer or a string. So when we return the integer or string as a Var parameter since the error is being returned as the result, we add confusion to the program and more declaration bloat. With contractual errors, the error is returned as part of the function whether or not we already have a function result such as a string or integer.

The advantage of binding the error into the function contract, is that the programmer knows the error is there. With exceptions, the error can be ignored or the error can be unknown because you don't know where a "raise" will occur since it is hidden upstream, and programmers don't look at every line of upstream source code since they have better things to do (the upstream source is generally written by other people, and you don't know what they were thinking). With error contracts like I describe, a compiler could force us to check the error contract. True, in the error block of code you could do the wrong thing and screw the program up just like with exceptions.. but that isn't what I'm getting at.

What I'm getting at here is that error contracts show you (outright and obviously) that an error could occur, whereas exceptions can pop up any time (raised) and you don't know how to program for them, since it is like an intraprocedural goto (a raise goes to another procedure elsewhere! This is terrible since intraprocedural gotos have obviously been proven to be very confusing things - they are worse than a local goto).

The error contract system on the other hand, is shown to you in the function declaration! You know the error contract. But not with exceptions.. Exceptions require you to read all of the source code that you are utilizing (libraries) to find out what will be raised... or you can try the documentation which can contain misleading info (or the documentation may not even exist for the library you are using, or it may be incomplete). Whereas error contracts are in the declaration itself! It's in the contract.

What is bad about error contracts in the function? The really bad thing about them is that no languages really support them at the level I'm talking about. True some languages support tuples.. but that isn't enough. I'm talking about a compiler level or interpreter level error contract system - not just a language that supports simple tuples.

Compared to exceptions and error codes, don't error contracts seem reasonable and advantageous?

You may be thinking that exceptions can be forced too.. but really they cannot be logically enforced. People put the try finally blocks in the wrong places or figure out ways to trick the exception system so they don't have to catch those exceptions (putting an empty catch block of code). With error contracts, it is much easier to know where the error should go. That's because it is a logical flow. If the function does the wrong thing.. then the contract tells you it is going to pop an error and the compiler tells you that you better check that error since that function has a contract that says it can return that error.

You can put try finally blocks around code but the compiler can't enforce whether or not the try finally blocks are even in the right place trapping the right errors. There is no error in the contract with exceptions. There may be skimpy documentation outlining the exceptions, but no one is genius enough to know how to nest try finally blocks the right way (and if you think you are smart enough, then ask Raymond Chen, Joel Spolsky, and me, and several others, who aren't dumb).

When a function has an error as part of its contract, it is bloody obvious that the error is expected (we can only program for expected situations, otherwise you couldn't program for them). What errors can exist are layed out to you as a function result in the contract - the function tells you there may be errors! With exceptions it is not obvious what exceptions can occur where, because they are not in the contract (again, they can be in the documentation, but some exceptions go flaring off out of nowhere since programmers had no procedure contract telling them that this error was going to pop up).

What is exceptional?

When a string is attempted to be converted into an integer and it fails, in my opinion this is not exceptional. It is very obvious that in typical desktop or web software apps, sometimes a person will input an invalid string which contains text and not just numbers. That's called an expected error.. you expect that people are going to make mistakes. So when using a function like StrToInt() we must not consider text input as and "exceptional" circumstance. In a rocket ship, it may be more exceptional if something was sent in as text which should have been integer.. but I'm not so sure. What is an exception? I have no clue. Neither do many other people. Computing science is an open topic far from being closed.

Errors and exceptions are an open area of research. Defining scientifically what an error is, and what an exception is, should be on every serious programmers todo list. The topic is riddled with ignorance, and lacks rigor.

Error Codes Suck

Error codes are horrible because you don't have to check the error code, you can ignore it.

Error codes are horrible because you bloat up the source code with if logic checks (well, some sort of logic is needed.. a try finally block is just as bad since it hides logic into weird try nests that aren't logical, they are just kind of hidden logic and you keep your fingers crossed that you put them in the right place).

Error codes are horrible because they are hated by lots of people.

Exceptions Suck

Exceptions are horrible because they don't give any contract in the code. You can ignore exceptions and the program can crash and give the user a fucked up message that doesn't tell the user anything useful. Even with forced exceptions you can leave the finally/except blocks empty or simply put the exceptions in the wrong places.

You don't know where to put the try finally blocks, and you don't know where to put except clauses (if at all). Sure, an expert who has read the documentation very carefully may manage to figure out how to handle the exception.. but usually the documentation does not or cannot inform about how to handle the exception properly. Some of the smartest programmers and programming managers in the world such as Joel Spolsky, Raymond Chen, and myself (haha!) do not understand exceptions. And if we can't understand them, then no one can.

Contract Programming Sucks?

Nothing is perfect. Contract programming might suck because it is similar to error code programming and it bloats up the code with 'if logic'. Remember though, in example 2 I offered a way to handle errors withoug bloating up the main algorithm. But in mission critical software, it is essential to logically know what the fuck the program is doing. You do not want to hide errors upstream and you do not want to bloat up the source code with Var parameter error codes. You do not want some exception blowing up your rocket ship since you forgot to trap the try finally in the right place. You need a contract that tells you what is happening, and you need to see in the code what is happening. And your compiler needs to tell you that "YOU DID NOT CHECK THAT FUNCTION FOR ERRORS, THE COMPILER WILL NOT CONTINUE UNTIL YOU CHECK THE ERROR PROPERLY".

No compiler can be smart enough to tell you exactly how to handle errors or exceptions in the perfect manner.. but a contract can help enforce that you check for errors and it can help enforce that you check errors properly.. instead of shoving code all into one big try finally block and crossing your fingers when upstream code blows up, but you don't know why, how, or where - as there was no contract in the function - it was all hidden away, Out of Site, Out of Mind.

With strong error contract compiler checking option on, it takes discipline since you would have to check all errors. However, contract error checking could also be turned off as a compiler option in non mission critical software. A default error handling could also be set up such as "write all errors to log file if the error goes unchecked".

Quote from Raymond Chen:

"It's hard to write good error-code-based code..." but ..."It's really hard to write good exception-based code"
And there lays the problem. More quotes on the links below from Taylor Hutt, Joel Spolsky, and Dr. Andrew P. Black if you read through the paswiki "See Also" pages.

See also

Try-Finally-Is-a-GOTO-That-Is-Too-Limited

Improve Or Ditch the Rude Exceptions

Joel Spolsky Discusses the problem with exceptions

Raymond Chen Discusses the problem with Exceptions

Back in 1994 There was a conversation on USENET about exceptions.. Taylor Hutt seems to be the one to pay attention to in the conversation. Many of the replies show how ignorant we are of errors and exceptions. This was in 1994, and we are about just as ignorant today on the subject. It has become a religion instead of a science or a maths.

More people have written in the subject:
"Forcing the calling code to handle the error right away is the correct approach, because it forces the programmer to think about the possibility of an error occurring. That's a key point. The fact that this clutters the code with error checking is unfortunate, but it is a small price to pay for correctness of operation. Exceptions tend to allow, even encourage, programmers to ignore the possibility of an error, assuming it will be magically handled by some earlier exception handler."

http://www.lighterra.com/papers/exceptionsharmful/

About
This site is about programming and other things.
_ _ _