21 April 2023
Programming in heaven ... and in hell
I'm currently writing a new A-level textbook on programming, and I'm writing it simultaneously for Python, VB, and C# - which is even more painful than it sounds! (BTW, each reader of the finished product will see only one of the three.) But it's also an educational process in itself. With each example I write, I am struck that it works better in one language than another – though different in each case. Sometimes the difference is small – the code is just a little more elegant and/or easier to read in one of the three languages. Other times the difference is startling.
I found my mind wandering back to a joke that I used to tell – back in the days when most people had a sense of humour – about the difference between heaven and hell. The joke now feels dated, even inappropriate, for multiple reasons - but it worked well last century:
Heaven is where the English are the policemen,
the French are the chefs,
the Germans are the engineers,
the Italians are the lovers,
and the Swiss organise everything.
Hell is where the English are the chefs,
the Germans are the policemen,
the French are the engineers,
the Swiss are the lovers,
and the Italians organise everything.
I started musing about a programming languages version of this joke. Not hard to write, but, at best, funny only to a rather narrow audience! More seriously, it would be quite easy to design a language that incorporated the best features of each of Python, VB, and C#, while eschewing the worst – and in a way that the supporters of each would recognise the roots in their own language. (No, it wouldn't look like 'pseudo code'.) Getting such a language implemented, and then adopted in schools, however, would obviously be a very different story.
There's also another reason not to attempt it. Because from an educational perspective all three languages belong in hell, for one specific reason, the same one for all three languages. And so does every other programming language I've used (I stopped counting some years ago) in my nearly 50 years of coding. The reason they all belong in hell is: error messages.
As I write the book, constant switching of languages causes me to make even more errors than I would normally. But in all three languages, many of the error messages are absolutely incomprehensible. I'm an experienced professional developer (well, in C#, anyway). How does a newbie cope with this? Nor are things getting better over time. Those of you teaching AQA A-level may recall your first experiments with Haskell. Absolutely wonderful language, when you get it right – but the error messages should send Haskell straight down to the ninth circle.
And let's be clear: just trying to write 'friendlier messages' isn't going to solve anything. Even when I do understand what the message means, they are often pointing at the wrong place in the code – the cause of the error lies elsewhere.
I find myself wanting to advice to pupils: 'Don't bother even trying to understand the error message, just recognise that there is an error and use [these techniques] to narrow down the cause…'
The most extraordinary thing is that this is all now unnecessary. It is perfectly feasible technically to now eliminate the possibility of coding errors. I am not talking about errors in your algorithm – called 'logic errors' in most textbooks, though I don't think that's a good term. I'm talking about errors that are recognised – whether at compile time or run time – by the language system. Not just syntax errors, token errors (names), and type errors, but null reference errors, range errors, division by zero errors.
The languages, or rather family of languages, that has most advanced the state of the art in this respect are the block-based languages such as Scratch. You can't create code that has syntax errors in Scratch – and that is a significant achievement. Some people argue that block-based languages will eventually displace text-based languages even in professional development contexts. I'm not sure about that: the spatial overhead of the primary-coloured building blocks and the need to switch so frequently between the mouse and keyboard are not going to go down well there. Scratch and its cohort are also strongly oriented to procedural programming, and/or event driven programming - not (unless someone can tell me otherwise) modern, functional programming. There have been attempts to find hybrid models between blocks-based and text-based programming, but they haven't gotten very far.
However, it would be perfectly feasible to design a text editor that could work with any mainstream text-based programming language – that not only made it much easier to write error-free code (modern IDEs already do this increasingly) but made it impossible to enter code that would cause errors in the first place (or edit existing code that would result in an error). (Remember: I am talking all kinds of errors that are detected by the language system, not errors in your algorithm).
One of my hobbies is restoring, maintaining, and driving a pre-war car. Believe it or not, the only way to check the oil level is to open the bonnet, locate and pull out a metal stick, wipe it clean on a rag (or my handkerchief usually!), insert it again, pull it out, and look at where the oil is on the stick. I have a more modern car, too. It has multiple computers on board. And now to check the oil level I just need to … you've guessed it … open the bonnet, and …
Those of us interested in both the pedagogy and the supporting resources for teaching programming need to set our ambitions higher - and address the issues that have simply been ignored for 50 years.
And, in case you're thinking 'AI' – what I'm describing doesn't need the faintest (malodorous, IMO) whiff of 'AI'. It's just plain old fashioned programming – the best kind. Not easy, but then nothing worth having is easy to acquire.
I hope to have a go at this myself, in the not too distant future. Meantime I have a book to finish writing, and a whole lot of software that goes with it. And that's not to mention the 'technical debt' accumulating on the car …
Discussion
Please login to post a comment
Well I think you’ve answered your own question: if ‘logic error’ actually means ‘error in algorithm’ why not call it that, or ‘algorithm error’? The problem is with these broad categories. The error might have been caused by an error in the algorithm, or the algorithm might have been correct but was wrongly implemented in the code. To me the term ‘logic error’ implies an error in deductive or inductive reasoning - which can play a role in programming, but typically a minor one. I think what they are really talking about is simply a ‘program executed successfully but produced the wrong result’. ‘Wrong result error’ for short.
@eefe - do you not think that Snap! shakes up the notion that jigsaw languages are only for beginners?
Its use as a teaching language at undergraduate level suggests that we should not be limited in our vision of how programming will evolve.
I for one feel it is probably the shape (geddit!) of things to come, and would use it as a matter of choice to work through algorithmic ideas. I also use its simpler derivative, Turtlestich, extensively to enjoy programmed embroidery.
My interest in Snap! began when I realised early versions of Scratch had watered down Logo (as well as empowered it with new graphics and parallelism, so simplifying games creation). BYOB put back something Logo started with.
Seymour Papert said in Mindstorms "The idea of programming is introduced through the metaphor of teaching the Turtle a new word.” (Mindstorms, 1980, p12)
He meant that the metaphor for learning Logo was linguistic, not the obvious Turtle Graphics (alone). He proposed we coould learn by building our own procedures, or sub-programs, undersood as extensions to Logo, that would be re-used to build larger ideas. Early Scratch dropped this for some obscure reason, Snap! brought it back, and subsequently so did Scratch.
Both the concepts of sub-program and parallelism are not very explicit in our curricula - why not?
Interesting read Richard. But why do you think “Logic Errors” is a misnomer for errors in algorithms?
Also, @John Stout, something about Snap just seems off to me, I just don’t like using it at all, lol…
Richard
To find a brilliant example of a non-procedural (well, not necessarily procedural) block based programming language look no further than Snap!
Snap! downloadable from here and run in a browser, is a ‘grandchild’ of Scratch V1, via BYOB (Build Your Own Blocks). Both BYOB and Snap! were primarily developed by Jens Mönig, BYOB in Squeak (aka Smalltalk) and Snap! in Javascript.
Snap! has the concept of ‘ringifying’ a statement or block of statements, which turns it into a item of data. So, for a simple example, consider the plus block:
Double clicking the block ‘evaluates it’ and displays the result. In this case Snap! takes the empty slots as having a value of 0 and so the result is 0.
Fill in the slots with values, double click and the block adds the two slots together and displays the result:
Now right-click the block and select ‘ringify’:
The plus block is surrounded by a grey ring and double-clicking it gives its value, which is itself.
This is now a block which can be evaluated, supplying it with values to fill in the empty slots:
By filling in one of the empty slots we get partial function application, so this:
is a block that, when evaluated with a single parameter, adds the value of that parameter to 4:
By filling in the other slot you get a block that, when evaluated with a single parameter, adds 5 to the value of that parameter:
Given this one simple idea (ringifying or deferring evaluation until required) you can define new control structures in Snap!, so for example, here is an unless block:
The first parameter is a Boolean (indicated with the ?) whereas the second is a block of code that won’t be evaluated (run) unless the Boolean value of this is false (it’s symbol is a lambda which is a pretty big clue!)
This:
doesn’t spin the sprite in a circle, but this:
does.
In this example simply by reordering the Boolean and the lambda parameters and changing the text (unless and do) we can change the block to:
Brian Harvey and Jens Mönig have often said that Snap! is Scheme disguised as Scratch (see the manual here on page 4).
Higher order functions (functions that take a function as a parameter and/or return a function) such as map, filter, reduce are easily implemented, as are more complicated computer science concepts such as continuations, streams and infinite data structures.
Snap! also allows you to do object-oriented programming but using the idea of prototyping instead of classes and instances.
The latest addition to Snap! has been a series of hyperblocks implementing APL concepts which let you do things like adding two matrices using the same plus block as for adding ordinary scalar numbers.