INSE - Lecture 10 Programming practice & style u Control constructs u Layout & Names u...

Post on 15-Dec-2015

222 views 4 download

transcript

INSE - Lecture 10

Programming practice & style

Control constructsLayout & NamesInitialization

To bear in mind while “coding”

A key target is readability of the code,because that

leads to understandability; and learnability.

Control Constructs

"Those things in the language that determine in which order instructions are obeyed."

Control constructs - sub-topics:

“Stucturedness” Linear sequence ("too obvious" - and not

much to say anyway); Loop constructs; Choice constructs (if , case/switch, etc.); Subroutine constructs (?recursive); Labels and goto ("unstructured"); Other? (e.g. error-handling; parallelism...)

What does “structured” mean?

1960's - “programs must be 'structured'.”

(With at least two inconsistent definitions of the term!)

1970's -(1) “What's that?”

-- please define it better!

(2) It's a straitjacket.

-- what forms of structure do we really want?

(3) "The 60's doctrine is fine forbeginners."

Example: input, skipping

spaces, buffering non-spaces: the first character can be either space or non-space: stop at end of input.

Can this be made structured?

Not a chance!

“Structured” loop constructs

These are “natural” loop constructs for many applications, but there are situations where the need goes beyond either of these… e.g. ...

Another “natural” loop need:

“Copy characters from an input file to an output file, up to (but excluding output of) the first ‘@’.”

(Assume there will be a ‘@’ before end of file.)

Copy up to but excluding… That “naturally” calls for

the flow diagram on the left.

This flow diagram is of a “N-and-a-half-loop”.

Note that it is structured in the sense of “one entry, one exit”.

Coding that in (say) Java - try 1

do

// read C

if (C!=‘@’)

// write C

while(C!=‘@’);

The duplicated condition makes it hard to understand

Testing the condition twice each time round the loop is inefficient

Prone to mis-maintenance?

Coding that in (say) Java - try 2

// read C

while(C!=‘@’)

{

// write C

// read C

}

More understand-able?

Safe? What if the “read” is

many lines of code? - a maintenance problem...

Coding that in (say) Java - try 3

boolean stop=false;

while(!stop)

{

// read C

if (C==‘@’)

stop = true;

else

// write C

}

Obscures the real flow Longer than it needs

to be Somewhat inefficient

Coding that in (say) Java - try 4

do

// read C

if (C==‘@’)

break;

// write C

while(true);

Understandable, because it “says what we mean” by the N-and-a-half flow diagram

Efficient Hard to mis-maintain

Other special loops...

There are other special design situations calling for special control flows…

… the one on the left is a search loop

it’s one-entry one-exit.

It’s a special case of...

...

… a multi-exit loop

(still “one entry, one exit”)

An unavoidable goto - even in Ada

procedure Sort(X:Arr) is

Old : Element;

begin

<<Restart>>

for I in X’First+1..X’Last loop

if X(I-1) > X(I) then

Old:=X(I-1); X(I-1):=X; X(I):=Old;

goto Restart;

end if;

end loop;

end Sort;

Exceptions

Another unstructured situation … when something in the program goes

catastrophically wrong…e.g.– arithmetic overflow or underflow;– over-running the bounds of an array or other

fixed-size container;– hitting end-of-file but needing more data from the

file;– communications line errors ...

Especially for reliable programs – we can’t let them crash, or run amok!

Where to handle the abort?

Often the handling can only be done many levels of call back from the site of the problem.

So any aborting mechanism needs to be (potentially) back to the call, often repeatedly.

Traditional solution

Pass some error flag out of each call; after every call of every procedure test

all flags for all possible kinds of abort until a “handler” is met for a particular abort...

Problems with that solution

How do we guarantee some handler will be met for every possible abort in every possible call sequence? (especially in a compiled program - i.e. impossible to test exhaustively).

In languages without return, how do we abort from the middle of a procedure?

How do with abort without a value from the middle of a function? ...

In Ada, C++, Java The languages provide exceptions … ...with statements to “raise” (or “throw”) an

exception aborting the current set of instructions…

…there is syntax to “handle” (or “catch”) particular exceptions…

… when an exception is raised, it is “propagated” out of blocks and calls until a handler is found for it.

Subroutines...… or “subprograms”… or “procedures and functions”… or “PERFORMable paragraphs and sections”… or OO “methods”… or ...

How functions return their results

Some older languages tended to try return function results without any special syntax -– hard to “spot” when reading the program;– sometimes made it possible to exit a

function without defining a value.

In Ada C++ & Java

an explicit “return” instruction to define the result;

if execution tries to leave the function’s instructions by “falling off the end”, then an exception is raised.

Recursion

not often needed - but when it is needed, it can make otherwise-nasty code very simple;

easy when you know the trick -– at the place of a recursive call, think of the call as “seen from the outside” - just as you would for a call of any other subroutine.

from the programming units, you should know all about it?

Backtracking

for “brute-force search” programs

Example - in “extended” Adafor all I in 1..8 loop -- statements which might include -- instructions like success and -- failureend loop;

Backtracking is build into Prolog as the basis of the flow-of-control mechanism.

“Others” - many! e.g. ... co-routines for pseudo-parallelism:

– really only one program counter - but it “jumps” between co-routines (usually at controlled places in the source - e.g. semicolons);

parallelism/concurrency: – multiple program counters in a single program, one

per process» problems of synchronization» problems of intercommunication» problems of conflict & deadlock

A personal conclusion

[but one that many other people came to in the 1970’s]

We need adequate programming language constructs: they should give us the ability to state disciplined structures in forms which are– not concealed; and– understandable.

Layout

I.e. prudent use of blank lines; indentation; blanks within a line; placement of comments.

Purpose of layout

LEGIBILITY!

1/ by separation into “natural units” - usually by blank lines; visible boundaries to the “natural unit”

remove one uncertainty when thinking about it;

good for different granularities of “natural unit”.

Purpose of layout… legibility!!

2/ by drawing attention to “local structure”:

usually by indentation;

used to help us see where constructs start & end;

also to see which construct.

for

Purpose of layout… legibility!!

3/ by “phrasing” within the line: e.g. by spaces within the line:

= - the spaces make it very clear that the line represents an assignment.

Consistency of layout

It helps to have rules of thumb; habits; “house style”.

Know when to break the rules: e.g.

rule 1: “one instruction per line”;

rule 2: space either side of the assignment operator“;

butint OldA=A;A=B;B=OldA;

Postscript to “layout”

Objective: to help the reader So consistently-applied rules avoid the reader

having to adapt to changing style; But deviations from the rules might be useful to

attract the reader’s attention.Having a style is more important than exactly

what it is…“Adding layout and comments later” is false

economy.

Names

Choosing them for understandability

Names ...

… should be thoughtfully chosen to be– as short as possible; but also– to say as much as possible.

… we need to find a trade-off between these usually-conflicting objectives.

?standard abbreviations ?

? influence of the programming language?

!! inspiration !!

Initialization and...

[Avoiding too-obvious bugs…]

General program form

Many programs & program-components are of form

– do some setting up; then– do the real work; then– do some wrapping up.

The setting up is easy to forget…– especially uninitialized variables => bugs;– most especially uninitialized pointer variables.

Easy to forget...

The setting up is easy to forget…– especially uninitialized variables => bugs;– most especially uninitialized pointer variables.

The wrapping up (“finalization”) is very easy to forget…

– many diverse and subtle forms of this error…» e.g. omitted CLOSEs on some operating systems.

After this lecture (1) look at the loops in your past

programming efforts – – how easy to read were they?– how prone to mis-maintenance?

read the notes – especially– for the problems of coding a search loop;– for choice constructs (un-lectured);– for Boehm-Jacopini theorem (un-lectured).

After this lecture (2) From here out, compare constructs in

programming languages you meet for their strengths and weaknesses.

think about your past programming efforts - how good was the layout & naming?

do better in future - thoughtfully!!

be more alert for initialization & finalization issues.

© C Lester 1997-2014