Usability – When “updating” software goes so wrong.

I recently upgraded my Macbook to a wonderful new version, running El Capitan. Nothing bad to say about the machine itself, it is a wonderful piece of design, and OSX on the whole is great. What is a complete turnoff is the retrograde of software such as Pages. There was intrinsically nothing wrong with Pages 4 (iWork ’09),  yet Pages 5 (5.6) is not well designed. This is not the first time software designers in a company have messed with a product that worked fine before. Often these upgrades exist of removing features that were previously useful, providing only a subset of the original. Here are some of the issues:

  1. Incompatible file formats. So open an old document in Pages 5, and it will ask you to convert it before you can edit it. Backwards compatibility = 0, i.e. you can’t go back.
  2. Removal of features from the Thumbnails view. Pages 4 made it easy to add new pages, or even move old pages around. Pages 5 doesn’t make it easy at all. No ability to duplicate pages, or re-order via drag-and-drop.

    thumbnails
    Thumbnails: Pages 4 vs. 5
  3. The information bar has disappeared from the bottom of the document in Pages 5. It is possible to “Show Word Count”, but it puts an annoying bubble on the base of the document. The document zoom feature has also moved in Pages 5 to the top of the application.

    wordCount
    Lower toolbar and word count (Pages 4 (top) versus Pages 5)
  4. In Pages 4, it was easy to create two shape objects and add a connecting line between the two. In Pages 5, you have to modify the arrangement of each object to “Stay on Page” before it allows a connection line to be drawn. On the flip side Pages 5 does allow curved and right-angle connection lines, which is nice.
  5. The new format menu in Pages 5 bites. I prefer the floating inspector palette, much nicer, and seemingly better organized. And I can place it anywhere I want to on the screen.
  6. The lack of a format bar in Pages 5 is also extremely sad – I don’t always want the format menu to have to open to change simple things like a font, or colour of an object. I get that the format menu on the side performs the same task, but it takes up an incredible amount of real estate, and it isn’t just “there”, you have to open it to change basic things.formatBar
  7. The toolbar icons in Pages 5, have become much more simplistic, to the detriment of actually understanding what some of them do (yes, I understand they all have subtext, but that’s not the point). Even those icons with pull-down functionality, i.e. Charts, contain graphics which are sub-par (and sometimes meaningless). Simpler is not always better.

    pagesIcons
    Toolbar icons old (top) versus new

What else is gone? The ability to customize auto-correct.  The problem with some of these new applications is that Apple has attempted to “simplify” them. After you have used them you begin to wonder if they even involved existing users in the design. Pages 4 was a *good* product. It did most things, and it wasn’t Word. Pages 5 just seems like it’s missing some of the nicer features / layout of Pages 4. Sure Pages 5 has iCloud syncing, and great compatibility between iOS and OSX, but for those that are using it to write larger documents than just a few notes, get a copy of Pages 4, or look for an alternative.

Pages is not just a word processing application, it is also a simple page layout app. I have since installed Pages 4 from CD, and upgraded it to 4.3, and it seems to work quite nicely.

Is it possible to fix C?

Many languages have evolved over time to fix their inadequacies. Fortran moved from unstructured to structured programming by nixing structures like the arithmetic if and all those nasty goto statements. C has never done this – sure features have been added but issues like the dangling else, and fall-through in switch have never been remedied. Is it possible to fix these things, or is it too late?

It may likely be too late. The evolution of languages such as Apple’s Swift may displace others such as Objective C. A good example is the switch statement. In C-like languages it suffers from fall-through, where unless a break statement is specifically applied, one statement will flow through to the next – a common source of problems. Here is an example:

switch (n) {
    case 1: code1;
    case 2: code2;
            break;
    case 3: code3;
    default: code4;
}

In this case, if n=1, code1 will be executed, and then the code will fall-through into code2, which will be executed. This is obviously a problem because it is easy to miss these break statements. Conversely, in Swift, fall-through does not occur (unless you specifically specify it) – the entire switch statement finishes its execution as soon as the first matching case is completed, without requiring an explicit break statement. But the statement goes further… it allows for multiple matches for a single case statement, and interval matching (as well as a bunch of other cool stuff).

switch n {
    case 0:
        println("zero")
    case 1,2,3,4,5,6,7,8,9:
        println("single digits")
    case 10..99:
        println("double digits")
}

Swift also allows break statements in the switch, and a keyword fallthrough, which mimics the behaviour in C. Swift has clearly improved the usability of the switch statement.

Watch out C… the party might be over!

Removing tabs from programs in Unix

Tabs are evil. Partially because they are usually set to something like 8 spaces, and indents are typically 2 or 4 spaces. So how to automatically rid a program of tabs and replace them with spaces? One way is by using the Unix command expand, which expands tabs to spaces (specified as 4 in this case):

expand -t 4 input.c > output.c

Another way is using Perl (here replacing the tabs with 4 spaces):

perl -p -e 's/\t/    /g' input.c > output.c

This command replaces all tabs with 4 spaces. A third option is the use of sed (here replacing the tabs with 4 spaces):

sed $'s/\t/    /g' input.c > output.c

 All three of these methods deal with getting rid of tabs.

Chef vs. programmer

Ever watch a cooking reality show?

What always surprises me about those shows is how ill-prepared the chefs are. Usually it’s because they are too focused on one type of cuisine. Maybe it’s Cajun, Italian, or classic French. Leaving their comfort zone for some of them is challenging… not only that many suffer from one great Achilles-heel – a lack of ability to make desserts. It’s not that they don’t have the technical know-how, it’s because they don’t prepare themselves – maybe avoiding desserts, because they don’t like making them, or are perplexed by the thought of baking.

Programmers are very similar to chefs. We both use algorithms/recipes, and tools to build them. Many programmers suffer from similar issues to chefs. They know how to code in one family of languages – C, or maybe Java, Objective-C? But their programming knowledge suffers from a lack of breadth. Do they know how to code in a language family that is not derived from C? What about Fortran, Cobol, Ada? Awk, Pascal, Modula-2? Julia, Rust? Exploring new languages helps make you a better programmer. Writing Cobol programs may not be everyone’s cup-of-tea, BUT a basic understanding of the language provides a better understanding of programming in the large.

The concepts of a programming language are universal. An if statement in any language has roughly the same syntax, it does the same thing. It is usually the intricacies of a language which differentiate them: how they store and deal with arrays, do they have a built-string data types, pointers?

Bottom line? Learn a bunch of programming languages, it will make you a better programmer.

Origins of the for loop

Where did the for loop come from?

ALGOL 58 introduced a for statement of the form:

for i := base (increment) limit

This closely resembled a loop structure in Rutishauser’s programming language Superplan, developed in the early 1950s. His loop used “=” instead of “:=”, and the German keyword Für in place of for. Algol 60 modified this slightly, replacing the parentheses with keywords:

for i := base step increment until limit do
...
end

Fortran I went another route instead of the for loop: do. The functionality was the same, but it might have evolved this way to differentiate it from Algol58.

    do 10 i = base, limit, step
10  statement

After the early years, many languages adopted the use of either of these renditions. BASIC adopted for, PL/I adopted do, and COBOL created it’s own variant using the keyword PERFORM. By 1970, the for loop had become the norm, edging out do. C, Pascal, and Ada all adopted some variant of the for loop.

What’s with the “dangling” else?

One of the problems novice programmers are faced with is syntactic ambiguities such as the dangling-else problem, sometimes known as the hanging else. Dangling-else really just means that an optional else clause in a nested conditional structure becomes ambiguous. The original of the dangling else dates back to the design of the language ALGOL 60 which introduced the notion of two forms of the conditional if statement:

if expr then S1
if expr then S1 else S2

This was an unfortunate sequence of events, because it gave rise to inherent ambiguities in the code when nested statements were used. Consider the following piece of code:

if expr1 then if expr2 then S1 else S2

This can be interpreted one of two ways:

if expr1 then (if expr2 then S1 else S2)

OR

if expr1 then (if expr2 then S1) else S2

Or course the compiler will interpret it the way it was designed to, which may or may not gel with how the algorithm has been designed. We associate the dangling else predominantly with C, however it exists in other languages. Pascal for example had a similar issue. Java, C++, all seem to be afflicted. Many of the languages that avoided the dangling-else, did so with the use of explicit end markers.

Why Pascal is a good language

I recently stepped back into doing a bit of programming in Pascal, the first language I learned. What I realized is that Pascal is an inherently learnable language. Why? Because the novice programmer can get a feeling of what’s happening in a program, just by looking at it. There is a easier learning curve, because for the most part, the novice programmer is able to transfer knowledge they already have to the programming realm. Take for example the following Pascal program which calculates a factorial, n!:

program factorial;
var i, n, fact : integer;
 
begin
    writeln('Enter a number: ');
    read(n);
    fact := 1;
    for i := 2 to n do
        fact := fact * i;
    write(n,'! = ', fact);
end.

It is easy to look at the program, and get a sense of what is happening, despite the fact that it has no comments. Firstly, it tells you it’s a program, which is always nice, and it gives the program a name. Then it uses the keyword var to denote that the variables are to be created. It the creates i, n, and fact as integers. It’s nice that it uses the full word, integer, as the programmer, doesn’t have to worry that they have the right abbreviation. Pascal deals with four basic data types: integer, real, char and boolean, although the latest implementations have added extended data types.

Next it uses the delimiters begin and end to define the “programming block”, where the action will occur. This is seemingly better than the non-descriptive use of { and } in C. Input and output are provided by the read/write pair. Assignment turns the clock back to a time when := was used for assignment, which isn’t such a bad idea, leaving = for equality, thereby reducing the confusion created by the =/== pair. Even the for loop tells you straight away that i has a value from 2 to n, with an assumed increment of 1. All-in-all a much more readable program, and language.

So what makes Pascal a good language?

  • It is a very clean language, with a natural English language-type syntax.
  • Arrays aren’t limited to being indexed from 0, which can be useful for implementing some algorithms.
  • Pascal has a data structure called sets, which allow you to do really nice things.

Many will argue that Pascal was only ever an educational language. There is no doubt that is true, but what’s wrong with that? Learning to program means learning the structures needed to implement an algorithm, for example a loop. It doesn’t really matter what language is used, but a more usable language for novice programmers is obviously better. People would better understand programming concepts with a simple language.

 

One programming book you should read

If you are a computer science student, one classic book you should read is “Algorithms + data Structures = Programs“, by Niklaus Wirth (Prentice Hall, 1976). Old books you may ask – well, they are often extremely well written, and still highly relevant today. Although the examples are shown using Pascal notation, it should not take any competent programmer long to translate the code into any high-level language. The book covers five core areas:

  1. Fundamental Data Structures – an overview of arrays, records, and sets
  2. Sorting – sorting algorithms for arrays, and sequential files
  3. Recursive Algorithms – backtracking and classic problems including the 8-Queens, and a rationale for when *not* to use recursion.
  4. Dynamic Information Structures – linked lists, trees, and hashing.
  5. Language Structures and Compilers – the basics of compiler construction.

While Sec.5 may not be as relevant today, the remainder of the book is as relevant today, as 40 years ago when it was first published (although Wirth does provide the code for a basic compiler in 11 pages of Pascal code – which may be interesting to decipher). The section on recursion is one of the few which bypasses the traditional use of Towers of Hanoi to illustrate recursion, opting for the use of more visual algorithms such as Hilbert and Sierpinski curves.

WirthADSP

You can find copies at most libraries, or buy a copy from Abebooks.

What happens when the glass falls?

Consider a question such as this:

What happens to a glass of water if a person lets go of it?

A human might answer this by asking a series of questions:

  1. Is the glass on a stable surface?
  2. Is the glass being held in space?
  3. Is the glass tempered?
  4. How high is the glass from the surface?
  5. Is there liquid in the glass, and if so, how much?
  6. What is the shape of the glass?
  7. What sort of surface sits below the glass?

From these questions, one can determine whether or not the glass will drop, and if it will break. If the answer to Q1 is true, then nothing will happen – the glass will just sit there. If Q2 is true, then letting go of it will cause it to fall. IF Q3 is true, then there is a chance the glass will survive its impact with the surface below. The extent of the impact will depend on the height specified in Q4 – 1″ will not cause any problems, 4 feet will cause a greater impact. Q5 will only really impact how large the mess will be, although it could impact how the glass travels as it is falling, but that also depends on the shape specified in Q6. Finally Q7 determines the type of impact. If the glass falls on grass, or water, the outcome will be vastly different from a tile or concrete surface.

Now consider the number of questions involved in determining what happens when the glass of water is let go. A human can infer what happens to the glass after seeking answers to the questions. But how does an AI know what happens? Most AI relies on the use of factual information, and given all the relevant information, it would not be hard for an AI to come up with an appropriate answer. But questions like this do not contain factual information, nor can it be assumed that factual information exists. Can the AI’s architecture extrapolate from the original question to formulate questions of it’s own?

AI is limited by the factual information we give it. An intelligent thermostat may work by using information on our location, or how active we are near the thermostat, but it won’t ask you how warm or cold you feel.