Strong vs. Automatic Typing.

MAWL is a agressively typed language, like C++. The idea (and it's not a bad one) is to give the compiler as much information as possible so it can catch as many of the programmer's mistakes at compile time as possible. Specifically, if you say something is an integer, and you pass it to a function that needs a character string, the compiler will complain.

This is part of the modern (last decade) programming movement towards provability. Ideally, the view of programming is this:
  1. You have a specification of exactly what the program should do.
  2. You write code that implements the specification.
  3. The compiler takes that code and the specification and (ideally) proves that your code behaves as specified.
Now, #3 is essentially impossible for any interestingly complex program, but the intent is to prove as much as possible, and make as many checks as possible.

I'm not a believer in this programming school, or at least I'm not a disciple. Let me explain why.

Imagine that you could really prove that a program met a specification. Then, what you have created, with rules 1-3, is a compiler from a different language (the specification), which uses a human in the loop as a preprocessor. You may have abstracted things, but you haven't gotten rid of the basic problem of deciding what your program ought to do.

That's the hard part. Or at least a hard part. A computer program exhibits very complex behavior, and specifying that behavior in detail is not easy. If you've read the Hitchhiker's Guide to the Galaxy , you've seen this issue is discussed in detail.

So, you really have to balance the extra effort required to include all that extra information against the benefit that you obtain. The C++ approach is essential (probably) for large projects, where it forces the programmers (who otherwise wouldn't talk to one another) to agree on common interfaces between their functions. It lets the compiler make sure everything is consistent. It helps catch mistakes earlier, when they are less embarrassing (like at compile time, rather than after you've shipped the product).

However, it does make the whole process of writing code slower and clunkier. Also (since there are more details) it takes more people to remember all the details, so the organizational problems get more severe. This means fewer new versions of the program, and therefore slower improvement in the aspects of the program that are neither right nor wrong, but rather better or worse. Slower evolution. Dinosaurs vs. small little mammals.

It's essentially double entry bookkeeping, which allows errors to be caught, but takes twice as long to enter a number. The code is more likely to work to spec, but the spec doesn't get upgraded as often. It;s a tradeoff.

In C++, for instance, imagine a simple situation. You have a function that wants to return a value (say a character string), and also wants to return a code (maybe specifying where the string came from).

What do you do?

Strongly Typed Example

Here we define the thing that gets returned. It has two things inside -- a character string (named 'x', and a code named 'y'). Note the inside names are often redundant - you have only one character string here, so you don't really need a name for it.

struct some_name_or_the_other { character_string x; code y;};

Next we declare the function:


some_name_or_the_other function_name(argument, ...);

Then, we give the guts of the function:


some_name_or_the_other function_name(argument, ...)
{
 // We calculate things here...
 TheString = ...;
 TheCode = ...;
 ...
 //Then, we return the values...
 return some_name_or_the_other(TheString, TheCode);
}

Then, we're almost ready to use it. First, we declare the variable that we're going to put the result of the function into:


some_name_or_the_other fval;

// We call the function
fval = function_name(...);

// Then, finally, we can look at what we got:

print fval.x;
print fval.y;

Note that you have to go back and look up what x and y are. Unless you use redundant names, like


struct some_name_or_the_other { character_string char_string; code Code;};

(we call the character string "char_string", and the code "Code") instead of


struct some_name_or_the_other { character_string x; code y;};

You will certainly be wasting a lot of mental effort keeping track of all these definitions and extra names.

Automatically Typed Example

You could imagine a language ( like Alef or perl or lisp, but better) where you say


function_name(arguments ...)
{
 return (TheString, TheCode);
}

And the compiler figures out the type information, then you use it by saying


[MyString, MyCode] =  function_name(...);

and it's smart enough to now remember that MyString is a character_string.

Now, Perl isn't perfect, but it is powerful, and one doesn't waste a lot of typing or neurons.