Preface
I wrote a popular answer on Quora. It involved an Amiga based language, and it occurred to me that it could be a good fit for the blog. And here we are.
Just remember though: while the post itself is jocular, the horror behind it is genuine. If you should decide to embark on this journey for yourself, gentle reader, be mindful of my warning. Heed the words of Signor Dante Alligheri.
Lasciate ogni speranza, voi che in Amos entrate
The Worst Language in the World
There are some really awful languages out there. I’m not counting the ones that are bad by design. Nobody’s seriously developing in Malbolge or INTERCAL or if they are, they’re presumably making some kind of masochistic point.
No, we’re talking real programming languages. Programming languages fit to purpose. Languages to make your life easier.
Programming semantics exist to shoulder cognitive burdens. They let us dispense with trivial code so that we don’t have to recreate old solutions. That way, we can focus on higher level code, the solutions and algorithms that really matter. Otherwise, we might as well all write in Assembler and be done with it.
In short, we leverage the power of programming languages to dispense with makework. When at their best, when coding a solution looks difficult and arduous, good programming languages are your best friend.
This is AMOS Professional, a BASIC variant for the Amiga personal computer.
It is not your friend.
Oh, it wants to be. It’ll always be there when you call. But somehow, that’s part of the problem.
This is your friend AMOS. Whenever it tells you about this great idea it just came up with? That’s how you know you should start running.
A brief history lesson
AMOS began on the Atari ST, in the form of the popular STOS BASIC. It was created by François Lionet and Constantin Sotiropoulos, then of Mandarin Software. Both were able programmers, with both vision and the ability to make that vision a reality: the noble goal of opening up the ST’s full multimedia capabilities to the user-base.
On release in 1988, STOS immediately grew popular, although not without earning its share of criticism. Two years later, the Amiga version (named AMOS) was released. You now no longer had to mind line numbers, and with the Amiga support you could now program the custom chips in various ways, with functions to manipulate the blitter, the copper, and various peripherals. It was more powerful, more polished, and more accessible than STOS. In fact, it was capable enough to allow you to write commercial grade software, or even games, for the Amiga.
In short, AMOS stands as a testament to the parable of the road to hell being paved with good intentions.
None of those things sound bad. What’s the problem?
The first issue is that of the runtime. AMOS is a black box. On paper, you need no knowledge of the innards of AMOS to produce a set number of impressive effects.
Notice I didn’t say “any number” effects? No, AMOS has a set bag of tricks which it thinks you should be allowed to employ. If what you want to do lies beyond that, tough luck. It enforces this limitation by encapsulating your code in the AMOS interpreter. This means the runtime will always stand between you and the actual machine, and even when it pretends it’s allowing direct access (such as with AREG and DREG), that’s actually not what’s happening under the hood. Even when you use the AMOS compiler so that the program is no longer interpreted, AMOS will still enforce this artificial separation.
If you want to do something under AMOS, that’s only easy as long as the programmers planned for it: if they didn’t, the runtime makes greater control all but impossible.
This, of course, also applies to access to AmigaOS.
AmigaOS was a fairly revolutionary operating system back in its day. It was lightweight and flexible and had nifty features like preemptive multitasking. It seems obvious that if you want to create a universal programming language for such a machine, it should produce applications for the OS. Europress disagreed, in effect creating an entirely separate and parallel graphical interface for AMOS programs. This was slow, bloated and unwieldy, even when compiled; compilation also made certain functions such as setting copper control to manual crash the computer. Above all else, it meant AMOS programs would always be visually recognizable, and so carry the distinct graphical signature of failure.
Second problem is the language itself. It’s shit.
Hey, aren’t you being a bit harsh?
You tell me. AMOS was written in the late eighties. It’s not as if we didn’t by then know perfectly well what sound language design principles looked like.
These are the hallmarks of a well designed language:
- Elegance. A sparse design with a small set of highly useful keywords that behave more or less similarly. Function arguments always follow the same order, naming conventions are kept consistent, and the syntax encourages doing the right thing.
- Expressiveness. An expressive language lets you describe problems in terms of the problem domain. This allows you to simplify the problem through abstraction. It also allows you to exclude categories of error, ideally at compile time, because of its semantics.
- Consistency and simplicity. The language behaves in well-defined ways that let you reason about it. The simpler a language is, and the less unexpected its behavior, the easier it is to master.
- Extensibility. A good language allows you to add new functionality to it. Ideally, such extensions should be functionally indistinguishable from core components of the language.
- Power metrics. By which we’re talking execution speed, memory requirements, etc.
AMOS is the ugliest language I’ve ever used. Everything has keywords, and those keywords have names that frequently make no sense. There’s tons of them. With no consistent naming scheme or parameter succession, you’re forced to commit all these things to memory.
A sane language would structure this somehow using namespaces or packaging. In Java, hardly a paragon of elegance, an instruction might be invoked using
System.Security.Cryptography.AsymmetricAlgorithm
That’s a bit verbose, but the idea is clear: you go in the direction of organizing the language as specifically as possible, so that the keywords don’t conflict.
AMOS… chooses the opposite direction.
Wait… what does that even mean?
It means that other than inside comments and text strings, all the text in the editor (yes, that most certainly includes variables) is matched against existing keywords, of which there are hundreds. And if they match, case insensitively of course, the variable name is broken apart by the ever-helpful editor.
Look. Suppose you have this line of code:
Rain_Water_Level = 12
print "The water level is " + Rain_Water_Level + "!"
Looks like legal syntax, right? Unfortunately, turns out the word “Rain” is a keyword, so the variable name will be broken up. And since this occurs even case insensitively, good luck trying to write things like RAIN_water_level. That reduces the set of variables you can use to write descriptive code to an alarming degree, quickly making most code impenetrable. And yes, of course Cos, Sin and Tan are reserved keywords.
You may also notice that the language is not typed. Nor is it consistent: it will silently convert values for the print statement, in an effort to be helpful. Just like back in the day when Internet Explorer allowed incorrect code to still produce a usable webpage, this sort of help will sooner or later backfire as the errors overflow and you’re left with a turgid mess.
Under IE, of course, you could still enforce strict rendering. In AMOS, you cannot. It will cheerfully give you a coil of rope and then help you tie the knot just so.
This is horrible.
Oh, I’m just getting started. You see, there were some things AMOS was too slow to actually do. It’s an interpreted language after all, and what you needed for moving objects on the screen was speeds on the Assembly level. So what do you think they did?
…they let you use Assembly, to really leverage the processor?
Hahahahano. Not really. They created a whole new metalanguage called AMAL (AMOS Animation language) which you then have to write within AMOS. AMAL code is fed into AMOS as a text string and precompiled into assembly, but with its own semantics, with its own way of assigning variables, its own evaluation order, its own object system, and its own set of control structures. So no, it’s entirely its own language.
So there’s actually one entire extra language built into in AMOS?
Of course not. Two separate languages? That would be ridiculous.
There are three. Well, five if you count the pseudo-Assembly and the copper list code (which as mentioned earlier, will crash the computer if you try to use it under the compiler).
The third language is called Interface. It’s an entirely separate body of semantics for building and displaying windows and widgets. As for why there’s a separate system for interface widgets, guess what? The existing commands were too slow, so, well… they made an extra language. Because there’s not as if the operating system already contains perfectly suitable and fast code for a GUI, right?
And if you’re thinking that this could be something like MFC or wx, i.e. a graphical GUI creator with fit-to-purpose semantics, let me disabuse you of that right away. No, it’s just the same functions with different names and syntax, the only difference apparently is implementation. It’s like you’re hacking PhP in the days before there was PhP!
Structured programming (o cruelest joke!)
BASIC is often maligned, but the language family itself doesn’t preclude good structure. You could do a lot with very little. Something like duck typing would allow the creation of objects that could sensibly group related data, which could then be sent as function arguments.
But this is AMOS, where there’s no such thing as an object or a function argument. There are only integers, floats, strings and arrays, and naturally, they’re all of static length (without using its dodgy OS calling facility, you simply cannot reasonably use malloc from AMOS). And since the language is dynamically typed and variables are automatically instantiated, and since scope is something that only happens in procedures (which are so cumbersome as to preclude easy use)…
Yes, you guessed it: if you try to create a variable named x, let’s just hope you haven’t previously declared another variable called x somewhere in the program and forgot about it, because if you did, you’re now assigning a new value to that original variable, trashing it. Look forward to weird bugs, especially from the plethora of goto-like constructions (such as “every x gosub HELLO”, which will recall fond memories of the joys of debugging race conditions in C).
But there are functions which take arbitrary length input, however, such as polygon functions. You might even be forgiven for thinking we’ve finally stumbled into something sensible and useful. Alas, no — the number of arguments in those functions are set at compile time. That is, you can’t simply define an array of coordinates and then push it into the polyline function — no, you have to type out all the specific coordinates (“Polygon x(0), y(0) to x(1), y(1) to x(2), y(2) …”). Look forward to hilarious keyboard slips and the resultant bug hunt.
What it means is essentially that, contrary to languages like C in which you can raise the abstraction level by carefully encapsulating resultant functionality in functions and libraries, doing the same in AMOS quickly becomes a chore. The easier, more immediately productive choice is always to write it as one big blob of data, possibly with a few subroutines sharing data with the main function. Which boils down to the fact that while longer C programs can go toward greater order, longer AMOS programs naturally trend toward chaos and situational homicide.
It’s ironic to me that after learning rudimentary 68K Assembly, I already consider it far more well-formed and expressive than AMOS was, and AMOS was supposed to be instructive and easy to use!
But surely, if it was popular and skillfully coded, it couldn’t have been all bad!
To the contrary, I argue the greatest sin of AMOS was its popularity and the fact that it worked. A hated language would never have convinced so many young coders to waste their time in the vain effort of trying to learn AMOS well enough to write a proper game. A poorly written language without snazzy graphical features would have immediately dispelled the myth of its speed and power.
Instead, the fact that you could do some fairly cool things out of the box in AMOS concealed the fact that there was a cutoff point after that. Because try as it might, AMOS simply wasn’t capable of harnessing the full speed and capabilities of the Amiga.
To heap insult onto injury, learning the full scope of AMOS Pro was a full-time job easily comparable to the time it’d take learning Assembly. Only difference is, the AMOS programmer would end his journey realizing it was all smoke and mirrors, with few transferable skills that would make sense in other coding languages.
In closing, I admire Francois Lionet and co. They did a tremendous job on a project that clearly meant a lot to them, and obviously, a lot of Amiga fans disagree with me and loved their product.
Even so, I personally think that if there was ever any specific BASIC dialect Dijkstra alluded to when he said, “[..] students that have had a prior exposure to BASIC [..] are mentally mutilated beyond hope of regeneration.”,
then surely it must have been a prescient reference to the coming of AMOS.