Ada characters are tricky… or not?

Strings in Ada are tricky, and so too are characters – or at least they can be if you don’t use the right function. Remember, ADA is huge. There are a bunch of functions that will turn a string into an integer. The first of these is Integer’Value. Given the declaration:

str : string(1..9);
num : integer;

Then the numeric version of the string stored in str, can be realized using this function:

num := Integer'Value(str);

Now to get the individual digits requires peeling them off one by one, which is somewhat tedious. Another way of doing this is using a function which just returns the ASCII value of a character.

for i in 1..9 loop
  num := Character'Pos(str(i)) - 48;
  put(num);
end loop;

Now, as shown in the example, simply subtracting 48 from the ASCII value gives the actual numeric value.

 

goto not always considered harmful (in Ada)

You never thought I would say that did you? But in the right context, goto can be used for good. In languages such as Ada, which has no continue construct for its loops, there are less options. So can a goto be used to build one? The answer is yes. Here is an example:

procedure gotoEG is
  i : integer;
begin
  i := 0;
  while i<5 loop 
    if i rem 2 = 1 then 
        goto Continue; 
    end if; 
    Put(i);
    New_Line;
  <<Continue>> 
    i := i + 1;
  end loop;
end gotoEG;

This works in a very simple way. In the above snippet of code, if i evaluates to an odd integer, control is immediately transferred to the label <<Continue>>, which means the next iteration of the loop is invoked. Why doesn’t Ada have something like a continue (or skip)? Likely because it’s not really a pivotal construct. On a side note, for some reason, it wouldn’t allow the code to appear in the following manner:

  ...
<<Continue>> 
  end loop;
end gotoEG;

When trying to compile this, it threw an Ada “compilation error” because it didn’t like that there was no instruction between the label <<Continue>> and the end of the loop. Is there a way of doing this without using a goto? Yes, but it is a little bit more convoluted. In the code below, an exception is used

procedure nogoto is
  i : integer;
  Continue : exception;
begin
  i := 0;
  while i<5 loop
    i := i + 1;
    Put_Line("start loop");
    begin
      if i rem 2 = 1 then
        raise Continue;
      end if;
      Put(i);
      New_Line;
      exception
        when Continue => null;
    end;
  end loop;
end nogoto;

 

 

 

Backus on designing Fortran

“As far as we were aware, we simply made up the language as we went along. We did not regard language design as a difficult problem, merely a simple prelude to the real problem: designing a compiler which could produce efficient programs. Of course one of our goals was to design a language which would make it possible for engineers and scientists to write programs themselves for the 704.”

John Backus

“The history of Fortran I, II, and III”, ACM SIGPLAN Notices, 13(8), pp.165-180 (1978)

The utility of sets (in Pascal)

Paying around with Pascal recently, I had forgot about how nice its sets structures are. In addition to arrays and records, sets offer an alternative built-in data structure. For those that don’t know, a set is a collection of items of the same type – it is essentially a packaged, unindexed data structure. They are inherent flexible, and useful, largely because of the syntax. Operations are provided for set union, intersection, membership, and construction. For example:

var digit : set of '0'..'9'
    range : set of 1..100;
    alphabet : set of 'a'..'z';

defines a set, digit, that may contain any combination of the characters ‘0’ through ‘9’. The predicate:

x in digit

tests whether or not the value of the variable x is in the set digit. Here’s a good example of how sets can be used::

operandset, operatorset: set of char;
operatorset := ['%','+','-','*','/','^'];
operandset := ['a'..'z','0'..'9'];

This leads to very efficient statements, of the form:

if x in operandset
then write(' operand ')
else if x in (operatorset + ['(',')'])
     then write(' operator or parenthesis ')
     else write(' illegal symbol ')

Here’s the equivalent in Fortran, which has no similar structure:

if ((x >= 'a' .and. x <= 'z') .or. &
    (x >= '0' .and. x <= '9')) then
    write(*,*) "operand"
elseif (x == '%' .or. x == '+' .or. x == '-' .or. &
        x == '*' .or. x == '/' .or. x == '^' .or. &
        x == '(' .or. x == ')') then
    write(*,*) "operator or parenthesis"
else 
    write(*,*) "illegal symbol"
end if

Now although many languages such as C++ provide support for sets in some form or another, rarely is it part of the core language. So languages such as Fortran, or C contain no real set structure. Why do I care about this? Because there are certain circumstances when a set can help reduce syntactic complexity, as the example above shows.

 

The programmers biggest obstacle: time management

One of the biggest problems faced by students is time management. It manifests itself as assignments that are started later than they should be, and are therefore handed in late – even by as little as 10-15 minutes. The reality is, that the longer you procrastinate on a programming assignment, the more stressed you will become. If you submit a project once, it may happen a second time, and before you know it, it becomes habit. Why?

It’s easy to think “Well, I have 3 weeks to do this assignment, plenty of time.”, then “two weeks left, I should be able to get it done if I start next week”, and finally with a week to go, you put it off day after day, until finally you are left with three days, and realize that it isn’t possible to squeeze all the work into that timeframe. Why does this occur?

  • It’s EASY to procrastinate. We all do it. Easier to play a game, do some sports, go out somewhere. There is always tomorrow, but in reality there never is.
  • The task seems too Herculean. It’s seems too HARD, and may be easier if I start it tomorrow. But it never is.
  • There is a LACK of understanding. But it won’t get easier if it’s left to fester.

So how to manage your time better?

  • Start early. Creating software  involves a number of steps: problem solving, design, build, test. Start on day one with looking at the problem to solve, and explore different ways of solving the problem. If this is all you do, it’s a start.
  • Plan the project. Create a time-line. Prioritize what needs to be done.
  • Write a to-do list.
  • Manage your distractions.  Work in a “closed environment”, which means away from distractions. It may not be great working in a closed office, with no real fresh air, but there are other places to work: the library? coffee shop? Avoid email, and twitter, and the net in general. People think they get more done in the office, but co-workers, and the office environment aren’t always conducive to thinking.
  • Don’t skip on breaks. Okay, so it’s likely not good to pull “all-nighters”. Better to work consistently for a time, then take a break. Go for a walk around the block, or a bike ride. Give your brain a chance to reboot.
  • Create a balance. Try and balance the work you have to do with other things that keep you sane. If you start early this is the best way to approach it. Starting a project due in 3 weeks early means that you may have 50% of it done by the 1-week mark, which means you can take a break from it, and reflect on what you have done so far.

Anyways, the internet is awash with ways to manage your time. It’s not rocket science though. And likely we could all do a better job if we weren’t juggling 101 different things – but that’s the modern world isn’t it?

Re-engineering versus Refactoring

When dealing with legacy software, it is important to understand what can be done with the software. Legacy software often consists of software that has been left to run for a long time without too many inherent changes, the “don’t fix what isn’t broken” strategy. As compilers in languages such as Fortran are backwards compatible, it is often possible to compile and run these old programs. Yet at some point it becomes necessary to deal with the old code. So how to is this achieved? Is the code to be re-engineered or refactored?

Re-engineering means making fundamental changes to the code. Here are three core methods of reengineering:

  1. Porting – programs are modified to work on a new hardware platform.
  2. Translation – programs are translated from legacy language to contemporary one.
  3. Migration – programs are converted from a legacy language to a newer dialect.

In essence this is no different to the work that would be done to an old building. It might be moved in its entirety to a new location, it might be completely rebuilt, or it might be made new, incorporating only the facade of the original building.

Refactoring on the other hand, leaves things more intact. Refactoring involves changing a piece of software in such a manner that the external behaviour of the code remains unchanged, but it’s internal structure and architecture are enhanced. This is akin to modernizing the plumbing and electrical system of an old building. It still functions and looks the same way, but the infrastructure has been improved. Refactoring takes control of decaying code, improving the readability and maintainability of existing code. Refactoring is done to fix short-cuts, eliminate duplication and dead code, and to make the design and logic clear. To make better and clearer use of the programming language. It does not necessarily imply that the code is migrated to a new dialect of the language. Refactoring is often a part of the life-cycle of software, and may not be targeted specifically at legacy code.

Reengineering and refactoring look very similar, and there are likely areas, such as migration, where they overlap. In reality the process of dealing with legacy code often begins with refactoring, and progresses to reengineering. In situations where the code base is too complex, it might be worthwhile trying to improve efficiency first by improving algorithms. If this doesn’t work however, reengineering might be in the cards.

Here’s an example of the possibilities when dealing with a legacy, say Fortran IV, piece of code. The refactoring may involve processes such as:

  1. eliminating equivalence statements: specifies that two or more variables or arrays in a program unit share the same memory.
  2. elimination of common blocks: shared, common storage for Fortran programs prior to F90.
  3. removing dead code: code that is never accessed.

refactorReengDIAG

Reengineering on the other hand could involve a port to a new platform, a translation to C, or a migration to Fortran 95.

 

 

Dijkstra on Ada

Here is a quote from Dijkstra (EWD663), after a month spent reviewing the four contenders for the language Ada.

“And this concludes a month of most depressing work. Why does the world seem to persist so stubbornly in being such a backward place? Why do people refuse to learn from the past and why do they persist in making the known and well-identified mistakes again? Is is all very saddening”.

 

Do kids really need to code?

At what age do kids need to learn coding? The net is awash with articles touting how important it is to have kids “start coding as young as possible”… or something in that vein. After years of saying kids need to get outside more and get more exercise, we are now saying they should spend more time indoors, learning to code. I don’t have a fundamental problem with the concept of learning how to solve problems by designing and writing programs. But the process of teaching kids to program is one that has to be well thought out – not a reactionary one.

What age? I would say no earlier than the 6th grade. Some people will say kids could learn way earlier than that – but writing programs is more than just writing pieces of code in some simplistic language. Kids also need to be kids – building things with Lego, running around outside, making cookies, building sandcastles. The mere act of doing these things helps children learn some of the core skills they will need later on: problem solving, and creativity.

What to teach? Programming isn’t all coding, there are many other skills: problem solving, designing and writing programs, testing programs, and making sure people can use the program in a useful way. Start with problem solving skills. Then progress to  designing simple algorithms – recipes for guiding how a program works. Then introduce the basic concepts of programming using a simple, yet realistic programming language.

What programming language? Programming languages are the building blocks of computer science. Without them, there is no programming. It’s possible to start with a bubble language like Scratch, or even a language which does graphics such as Logo. However the progression from “toy” languages to real ones should be short – it is not hard to introduce programming concepts using graphics in languages such as Python. Even Pascal is a good language for learning the basics.

What not to do? Don’t think of using languages such as Java, C, C++ or the like. They are complicated, and rely on a greater knowledge of programming concepts. Don’t teach object-oriented anything – it is not necessary for kids to learn. Don’t teach memory management.

What to expect? Not all kids will like programming – in fact some likely won’t. Teach programming in the wrong way, and it may turn kids off programming. Don’t push it on kids. I say this because not all kids will have an aptitude for programming, just like not every kid has an aptitude for learning a language such as French. If they have a bad experience, or find they don’t like it – they will learn to hate it. The adage that “everyone can learn to code“, may not be true.

But above all else remember that programming is NOT like playing video games (the exception to this rule may be writing “mods” for Minecraft).

 

The evolution of programming languages

All programming languages evolve. New standards arise by adding features to a language. Most times these features come from other languages. For some strange reason, *bad* features are never removed. Some languages such as C spawn children.  Consider Fortran. FORTRAN was followed by FORTRAN II in 1958, FORTRAN III, FORTRAN IV in 1961, FORTRAN 66, FORTRAN 77, Fortran 90, Fortran 95, Fortran 2003, Fortran 2008, and supposedly Fortran 2015.

It is a tribute to a language that can last for near-on *70* years, and evolve in such a smooth manner, from an unstructured entity with assembler-like structures to a modern, clean language with down-to-earth  structures – even if it know suffers from periodic  seizures of OO.

Here is a program written in FORTRAN IV:

C     IT WAS THE FIRST PROGRAMMING LANGUAGE
C     WITH SUPPORT FOR COMMENTS
      WRITE (6,7)
    7 FORMAT(13HHELLO, WORLD!)
      STOP
      END

And the corresponding program written in Fortran 90:

program HelloWorld
    write (*,*) 'Hello, world!'  ! This is an inline comment
end program HelloWorld

Fixing the “dangling else”

The solution to this dilemma is quite pragmatic – use an explicit terminator for all control structures. For example the statement in the previous post becomes (in Algol 68):

if expr1 then 
    if expr2 then 
        S1
    fi 
else 
    S2 
fi

A sequence of statements is allowed between the keywords then and else, and between else and fi. This makes it unnecessary to use the delimiters  begin and end  to construct a compound statement. Note in early coding, it was not uncommon to express the above in the following format:

if expr1 then if expr2 then S1 fi else S2 fi

A similar solution was proposed by Ada, using the keyword end if. But instead of fixing this nightmare – we leave it in. This starts to become complicated (and messy) with an increase in nesting. For example:

if expr1 then
   S1
else if expr2 then
   S2
else if expr3 then
   S3
else
   S4
end
end
end

So languages that use end-markers often provide a keyword such as elsif, elseif or elif. The above code then becomes:

if expr1 then
   S1
elsif expr2 then
   S2
elsif expr3 then
   S3
else
   S4
end

For those programming in a language that doesn’t offer control-structure terminators, such as C? Use explicit  { } to properly terminate each if-else pair. For example:

if (expr1) {
    if (expr2) { 
        S1
    } 
}
else 
    S2