Are programs beautiful?

Compilers don’t care about how a program looks, or feels. From that respect, they can be quite insensitive. What they do care about is whether or not the programmer has provided instructions it can interpret. If the programmer has provided the compiler with sloppy looking code, it doesn’t care, as long as the logic is correct. The compiler cares about the raw syntax of the program, and whether or not it meshes with the rules embedded in its logic. Humans do care about what a program looks like in its coded state. Without our own set of rules, humans would likely create programs that are unreadable by other humans, and of course some do. But can programs really be beautiful? 

It really depends on what you consider beauty to be. Does beauty mean aesthetically pleasing? Many things are beautiful based on this definition, and in some ways this is also true of code. Well styled code looks nice, is easy to read, and therefore easier to comprehend. However beauty is a subtle concept, and truly in the “eye of the beholder”. A programmer from the 1950s would consider Fortran programs to be beautiful in comparison to assembler, or machine-language programs. A Cobol programmer might consider fixed formatting to provide a nice clean aesthetic to a program, and free-formatting, however well done, just don’t hold. 

Beauty has nothing to do with the use of clever algorithms, or using covert language features. Beauty in part has to do with the style used to layout the physical program, but it is more than that. A program should be expressive, i.e. the code should be easy to understand, or intuitively readable for both the compiler, and the human. It should also be concise, i.e. short (and that doesn’t mean using fancy tricks, because those programs often verge on being unreadable). Code written in languages like C often is the opposite of both of these characteristics. Does colour make a program more beautiful? Maybe, to a human.

Is this code, rendered in Carbon beautiful?

For anyone not convinced, I suggest finding and reading a copy of Kernighan and Plauger’s, “The Elements of Programming Style“.

The conundrum of the tab

The tab character is evil. Many early programs used tab characters for indentation, most likely to save on the size of a source file, as a single character could represent many individual spaces. On some Unix systems, particularly ancient dumb terminals and teletypes, the tab character was meant to move to the right until the current column is a multiple of 8. The problem with tabs is that they differ in size depending on the system. This causes problems with the portability of code between systems.

I know, some people will say tabs are great. They offer consistency, are customizable, take less “space” than multiple spaces, etc. etc. There are always pros and cons to everything. The reality however is that tabs are not a universal standard, and the biggest problem lies with code portability. The idea of a tab utopia seems to be fine until you share code with other people that use different editors with different tabs widths. Worse still are those individuals that conjure up the idea of mixing tabs and spaces, i.e. nonconformists. Somehow they think it’s okay to use tabs for primary indentation, and spaces to align the details? Next they’ll be saying that its okay not to document code, or writing programs in CAPS in “ok”. Or heaven forbid use goto statements. Heretics.

To some the idea of style in coding seems to be a foreign issue – “it doesn’t effect me”. They write code as if they live on an island, and nobody will ever have to read or modify their code. The problem is that such isolationist coders don’t really have much of a place in the commercial world anymore. Sure programs don’t care, and neither do compilers. As long as there is some semblance of syntactic accuracy, the compiler will compile the code. But you don’t just write code for machines.

The debate over tabs/spaces may almost be as much of a holy war as the concept of the “best” introductory programming language. But others have postulated spaces are better before. The mastermind behind Python, Guido van Rossum, one of the few languages which uses indentation to differentiate different levels of program, mentions that “Spaces are the preferred indentation method.”. I would suggest avoiding tabs like the proverbial plague, or better still, use an editor where tabs are automatically converted to spaces, the so-called “soft-tabs” in editors such as Atom. Many times people don’t set up their tabs properly in their editors, using a tab that looks like 4 spaces, but when ported to another system, appears as 8. Nobody wants to read code indented with 8 spaces. Like, n-o-body.

Brian Kernighan in a YouTube interview says he started out using tabs, because that’s how Unix worked. Now he says “I think spaces are a better fit for most people, and I think now, when I’m writing my own code, I mostly use spaces, and every once in a while I get bitten because there’s a tab when there should have been a space, or vice versa“.

Programming made easy – loops (iii)

There are of course other loops. These loops are normally used when the number of times a loop iterates isn’t known. These type of loops generally use some form of condition to control the loop. The most prominent type of loop is the while loop. A while loop checks a condition, and if true, processes the code in the loop body, otherwise it exists the loop. Unlike the for loop, which controls the values of the loop index in terms of updating its value, in the loops like while, this process must be added, i.e. the value of i is given the value 1, before the loop is activated, and its value is incremented within the loop body.

We will consider some of these loops using the same Harmonic series, this time in increasing order. The code for the program in Fortran, Ada, Julia and C is shown below. The loop is highlighted in blue.

Fortran

program harmonic
   integer :: n, i
   real :: h

   read (*,*) n
   h = 0
   i = 1
   do while (i <= n)
      h = h + 1.0/i
      i = i + 1
   end do
   write(*,*) h
end program harmonic

Here the index variable, i, must be initiated to the value 1 before the loop begins, and incremented within the loop. The condition states that the loop continues while the value of i is less than or equal to n, i.e. (i <= n) . Fortran also provides a more generic do/end do loop.

C

#include <stdio.h>

int main(void){
   int i, n;
   float h;

   scanf("%d", &n);
   printf("%d\n", n);
   h = 0.0;
   i = 1;
   while (i <= n){
      h = h + 1.0/i;
      i = i + 1;
   }
   printf("%lf\n", h);
   return 0;
}

In the C version, the structure is almost the same, except that the do while of Fortran has been replace with a simple while. With the addition of the statement to increment the value of i, the loop “contents” are now enclosed within { and }. C also has another loop, the do/while() loop, that performs the loop once, then evaluates the condition at the end.

Ada

with ada.Float_Text_IO; use Ada.Float_Text_IO;
with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure harmonic is
   n, i : integer;
   h : float;
begin
   get(n);
   h := 0.0;
   i := 1;
   while i <= n loop
      h := h + 1.0/float(i);
      i := i + 1;
   end loop;
   put(h);
end harmonic;

In Ada, the while loop looks similar to that of the other to Fortran and C, it is just subtleties in syntax that set them apart. Here there are no parenthesis around the condition. Also note that in the for loop, the index variable, i, did not have to be declared, but here it does. Ada also provides a generic loop/end loop loop.

Julia

n = parse(Int64, chomp(readline()))
println(n)
h = 0
i = 1
while i <= n
   h = h + 1.0/i
   i = i + 1
end
println(h)

Same deal here. Similar to Ada, except the loop keyword after the condition isn’t needed. There are only two loops in Julia.

As you can see, over four languages, the only thing that fundamentally changes is the basic syntax of the loop.

Programming made easy – loops (ii)

With the basics of for loops, let’s look at an example of an actual program which calculates the Harmonic series, which is an infinite series of the form:

h(n) = 1 + 1/2 + 1/3 + … + 1/n

The code for the program in Fortran, Ada, Julia and C is shown below. The loop is highlighted in blue.  For interest sake, the loops are presented in reverse, i.e. 1/n + 1/(n-1) + … + 1, as it illustrates clearly how each language deals with the simple issue of a decreasing index. In each case the starting value of the index variable i is n, and the ending value is 1. Here it is the algorithm for the Harmonic series depicted visually, clearly showing the role of the loop:

Fortran

program harmonic
   integer :: n, i
   real :: h

   read (*,*) n
   h = 0
   do i = n,1,-1
      h = h + 1.0/i
   end do
   write(*,*) h
end program harmonic

Here the third item (the modifier) in the Fortran loop denotes the type of change to the loop index, in this case, a decrease by 1. In a  normal loop incrementing by 1, the modifier can be omitted.

C

#include <stdio.h>

int main(void){
   int i, n;
   float h;

   scanf("%d", &n);
   printf("%d\n", n);
   h = 0.0;
   for (i=n; i>=1; i=i-1)
      h = h + 1.0/i;
   printf("%lf\n", h);
   return 0;
}

In the C version, the loop index is decremented using the statement i=i–1. For more than one statement after the for loop definition, the statements would have to be encapsulated in { and }.

Ada

with ada.Float_Text_IO; use Ada.Float_Text_IO;
with ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure harmonic is
   n : integer;
   h : float;
begin
   get(n);
   h := 0.0;
   for i in reverse 1..n loop
      h := h + 1.0/float(i);
   end loop;
   put(h);
end harmonic;

In Ada, the keyword reverse is used to specify a loop will be decreasing in value.

Julia

n = parse(Int64, chomp(readline()))
println(n)
h = 0
for i = n:-1:1
   h = h + 1.0/i
end
println(h)

Here the index modifier is placed in the centre, n:-1:1, implying i has the values n to 1, modified by -1 each loop iteration. In a  normal loop incrementing by 1, the modifier can be omitted.

Programming made easy – loops (i)

Humans are, by nature, repetitive beings. Watch the Star Trek: TNG episode “Cause and Effect”, and you will quickly understand what a loop is as the Enterprise is caught in a causality time loop. There are also times when programs must do a task more than once. If the repetition is limited to some countable number of recurrences with a foreseeable end then it is called a loop. And if, at least in the perception of the individual who is experiencing a certain situation, there is no end in sight then one is talking about endless or infinite loops. All of the above can be desirable or not. Here is a visual illustration:

The code in the program moves linearly from statement A, until it encounters a loop. At the start of the loop, the loop control tests some condition. If the condition is true, then the loop activates the piece of code (made up of one or more statements) in what is called the loop body. When that code is done the loop returns to the loop control, and the process starts all over. If the condition in the loop control becomes false, nothing happens, and the program ends the loop, and continues on to statement B. There is also a possibility that the first time into the loop, the condition becomes false, and in that case the loop is bypassed.

Loops are structures that allow for repetition – repeating an activity a number of times. There are different kinds of repetition:

  1. Loops where the number of repetitions is known before the loop activates.
  2. Loops where the number of repetitions isn’t known, and is controlled by some condition.
  3. Loops that are infinite, i.e. could continue to infinity and beyond.

The best example of the first case encountered in most languages is the for loop. Here we use a variable called a loop index to control the loop. Each time a loop loops it is called an iteration. So if the loop index is x, and it repeats 100 times, then x will begin with a value of 1, and increment by 1 each iteration, until x reaches 100. In Julia this is easily achieved in the following manner (in this case the loop simply prints out each value of x):

for x = 1:100
   println(x)
end

In Ada it takes a similar format (the printing part is a little different, but just ignore that bit):

for x in 1..100 loop
    put(x); 
    new_line;
end loop;

Ada uses the keyword loop to signify it as a loop. Fortran also uses a similar construct, but has never used the for loop, opting instead for the keyword do. Same concept, different name.

do x = 1, 100
   write(*,*) x
end do

C also uses a for loop, although it can be somewhat more convoluted:

for (x=1; x<=100; x=x+1)
   printf("%d\n",x);

All have their varied syntax, but achieve the same goal – a known number of iterations.

Programming made easy – if statements

It’s not hard to make programming concepts appear simple. In fact you can do it with very little effort.

Humans make decisions on a daily basis, so it goes without saying that systems must also make decisions, albeit in the guise of algorithms. Decision, selection, or conditional statements, as they are often referred to, are the basic logical structures of programming. A conditional statement resembles a fork in the road; there are at least two paths that may be taken and one must be chosen. Consider the following description of an if statement:

The if statement allows a program to choose between two alternative paths by testing the value of an expression.

Programs “flow” from start to end, activating each instruction as they proceed. For example, consider the following statements:

1  radius = 3.784
2  height = 12.3
3  areaCir = pi * radius^2
4  volCyl = areaCir * height

The statements are activated in sequence from line 1 to line 4. An if statement is a control structure that allows for a branch to occur in the flow of control in a program: if a certain condition exists, then perform one action, else perform another action. Here is what a basic if statement looks with only one option:

The code in the program moves linearly from statement A, until it encounters an “if” statement. At the if statement, some condition is tested. If the condition is true, then the program activates an addition piece of code (made up of one or more statements). If the condition is false, nothing happens, and the program bypasses the if statement and continues on to statement B. You will notice that there is no else portion of the decision, as it is usually optional – you can just have the if do something if the condition is true, otherwise it does nothing. If there is an “else” part to the decision, activated when the condition is false, the diagram is just modified, so that the if statement activates the piece of code in the else portion. Here is what the if-else looks like visually:

The if statement is pretty ubiquitous in programming languages, and the only thing that really changes is its syntax (how it is constructed). Some languages use the word then, others assume that the statements after the condition are associated with the “true” part of the branch – as is the case with Julia. 

In the Julia example below, a branch is made based on whether a person worked <= 40 hours, or more than 40 hours. Based on the value of hours, a different value of pay is calculated. This value may then be used to calculate taxes owed, or some other things.

if (hours <= 40.0)
   pay = rate * hours
else
   pay = rate * (40.0 + (hours-40.0)*1.5)
end

Here is the same example written in Fortran, the only difference is that Fortran uses the keyword then, and terminates using “end if” instead of just the end of Julia.:

if (hours <= 40.0) then
   pay = rate * hours
else
   pay = rate * (40.0 + (hours-40.0)*1.5)
end if

Python is a little different again, because it uses indenting instead of terminators like “end“.

if hours <= 40.0:
    pay = rate * hours
else
    pay = rate * (40.0 + (hours-40.0)*1.5)

Finally here is C, which in its simplest form looks like this:

if (hours <= 40.0)
   pay = rate * hour;
else
   pay = rate * (40.0 + (hours-40.0)*1.5);

Note that while the syntax changes, the fundamental concept of how an if statement works is the same. Make a decision, branch in a program.

Are Dolphins smarter?

“For instance, on the planet Earth, man had always assumed that he was more intelligent than dolphins because he had achieved so much—the wheel, New York, wars and so on—whilst all the dolphins had ever done was muck about in the water having a good time. But conversely, the dolphins had always believed that they were far more intelligent than man—for precisely the same reasons.” 

Douglas Adams, The Hitchhiker’s Guide to the Galaxy

Do droids have consciousness?

If you are a Star Wars fan you may wonder why technology is the roughly the same in the latest trilogy as it was in the original trilogy. Why don’t they have smarter droids? Likely because they realize that technology does not necessarily lead to a better society. Sure the computers aboard their ships are likely quite intelligent, in performing calculations for hyperspace jumps, and controlling the behemoth ships. But you don’t see any synthetic lifeforms, maybe because in reality they aren’t needed. There are enough different species in the SW galaxy that there is likely no motivation to build synthetic lifeforms. So do droids like C3-PO and R2-D2 show any true signs of consciousness? Maybe. The Star Wars galaxy is rife with droids of every size and shape. Ones like the GNK power droids are basically batteries with feet, so likely didn’t have much to think about (although one is tortured in Jabba’s palace and seems to feel pain, so who knows). Other like the battle droids from the Trade Federation were just inherently stupid.

C-3PO and R2-D2

R2-D2, C-3PO, BB-8, K-2SO. They all appear to have thoughts and feeling beyond the cold binary world of algorithms. These droids are half-way between droids and humans, and we likely feel more warmth towards these machines than any other, in any sci-fi series. They express emotions – happiness, sadness, worry, stress – all things that droids shouldn’t feel. We may be somewhat ambivalent towards their sentient tendencies because of the way they look. In the SW universe there are very few droids that take any human-type form. There are no synths, or Data’s. When R2-D2 seems sad he doesn’t cry, or physically show the emotion, except for maybe a sad beep.

Of course that they have emotions could be explained by having them programmed into their systems? Seems a little far-fetched given how hard it would be to program emotions. The actual emotions likely aren’t that hard, but what of the triggers – what triggers an emotional response like sadness? When we first meet C-3PO in episode IV aboard Princess Leia’s consular ship, he seems somewhat cowardly. I mean he didn’t want to get in the escape pod either. But he was “fluent in over six million forms of communication“, so to communicate properly as a protocol droid he must have had some inkling of how emotion played a role in verbal communication. I mean C-3PO could speak, but sometimes he didn’t exactly seem intelligent.

R2-D2 and BB-8 on the other hand inherently appear smarter, although neither speaks (except in binary), although they can both understand languages. The tone of R2-D2’s beeps helps us understand what emotions R2-D2 is feeling. Yet maybe it is not true emotion. BB-8 shows more emotion than R2-D2, but that may be because he can “show” emotion better. The ability to pivots his head on his body, and move his body so freely makes it easier to pose gestures that allude to emotion. When Rey meets BB-8 for the first time, saving him from a scavenger on Jakku, he seems quite sad at the thought of her leaving him behind to go off on his own. When she tells him to “come along then” with a nod of her head, you can sense his happiness. Of course that implies that BB-8 also understands gestures, and is a good enough judge of character to know that Rey isn’t going to do anything untoward to him (unlike C-3PO who we have seen ending up in many bad situations because he implicitly trusted people).

K-2SO

K-2SO from Rogue One, was originally a KX-series security droid, apparently emotionless. But some re-programming turn him into a quite a cynic, and prone to sarcasm. He would dis-obey orders he felt counterproductive, and was even self-aware enough to know he was a “re-programmed imperial droid”. A good example of his sarcastic tone was on Jedha where he said “There are a lot of explosions for two people just blending-in.” when he ran into Jyn and Cassian in the city. Is is possible for a droid to know what sarcasm is?

Indeed L3-37 from Solo, was a droid that augmented herself from pieces of other droids. To put it in her own words:

“Sure, some guy in a factory probably pieced me together originally, and someone else programmed me, so to speak. But then the galaxy itself forged me into who I am. Because we learn, Lando. We’re programmed to learn. Which means we grow. We grow away from that singular moment of creation, become something new with each changing moment of our lives—yes, lives—and look at me: these parts. I did this. So maybe when we say the Maker we’re referring to the whole galaxy, or maybe we just mean ourselves. Maybe we’re our own makers, no matter who put the parts together.”

―L3-37, to Lando Calrissian

Many of these droids appear to be self-aware, and possess consciousness, even if it is an artificial one of sorts. They show happiness, are sarcastic, fear for the well-being of their friends, get annoyed, are insubordinate, and loyal. They have personalities, and are likeable as more than mere machines. They are of course regulated by programming, and follow orders, so they lack some level of self-determination, but overall their actions are motivated somewhat by emotions and values that aren’t that far remove from our own decision making processes and emotions.

Recursion and marking a rule (ii)

The code in the last post creates the ruler in a particular way, i.e. it marks the middle, then processes the left, and then the right of the middle. This could be called pre-marking. If we wanted to change it up, and use in-mrking, we could put the call to mark() in between the left and the right recursions. This really does nothing to detract from the end result, as the order the marks are drawn is irrelevant. It just offers another way of posing the recursive solution.

void rule(int l, int r, int h)
{
   int m;
   if (h > 0) {
      m = (l+r)/2;
      rule(l,m,h-1);
      mark(m,h); 
      rule(m,r,h-1);
   }
}

To get a simpler ruler than the previous example, let’s try rule(0,128,4), which will result in 15 marks on the ruler. Here is the outcome:

ruler4

The recursive structure can be represented by a recursive call tree. This diagram has a node for each call to function ruler, containing the parameters that are passed to it. The children of any node correspond to the recursive calls to ruler within that function instantiation. A tree diagram can be used to illustrate any type of recursive algorithm. Here is a recursive call tree for rule(0,128,4).

rulercalltree

Recursive call tree.

The other thing the recursive call tree does is to allow divide-and-conquer algorithmics to be visualized.