Uncommented Beginner Programming Concepts

Uncommented Beginner Programming Concepts

This is an attempt to describe some things that I find lacking in many programming language learning materials. Whether I do a good enough job of describing them, to inform more than to confuse, is the exercise for the reader.

The topics covered are:

  • Compiled versus Interpreted
  • Define Before, Execute After
  • Appendix A – Compiled vs Interpreted Examples

Compiled versus Interpreted

It seems that this isn’t mentioned as clearly per language as it used to be, so I’ll boringly describe them.

For starters, the simple concepts are:

  • Interpreted – means there is a live-run-time approach to running the program. Generally it means that your program gets run by another program, the interpreter, and hence at run time you’ll need to have the interpreter installed on your computer and then have your program for it to run.
  • Compiled – means that a program that will read your program text and use it to create a run-time executable program – i.e. something that can then run without either your program text or the compiler present.

In practice, the distinction between these gets to be quite blurry, for all sorts of technical reasons. It would be too distracting to list those here – I may put them in an appendix.

  • Some languages, by design, are nearly always interpreted.
  • Some languages, by design, are nearly always compiled.
  • Some languages are readily available as either interpreted or compiled.
  • And to just to keep things complicated, there are many hybrids – for example a full language might be interpreted but a subset of it can be compiled.

Still, there are two major distinctions that cross over into the nature of various languages – and of programmer behaviours:

  • compile-time error checking (that usually mean a failure to compile at all) versus having run-time errors happen;
  • the immediacy of running the program after making an edit.

The latter there used to be the norm for using an interpreted language and not for a compiled one, but Turbo Pascal changed that in the 1980s. Nonetheless there is often a matter of scale, such that large and very large programs are rarely done in interpreted languages – and as a consequence such large programs can take quite a while to compile (sometimes more because of the amount of orchestration required rather than the compilation itself). This means you’re less likely to make a small change and immediately compile and test run to see how it goes.

As already stated, often the very design of a language may direct whether it is or can be interpreted or compiled. See the appendix for a short list of which common languages are done which way.

Define Before, Execute After

Something that varies across languages, is the order in which you need to do things in the program text.

While that sounds like a simple thing – and if you search for “declare before use” you will find a great many forum threads on the topic – it actually has quite a bit of subtlety to it. Usually, you will find this discussed about variables, and in particular, about which languages let just create a variable by putting something into it, versus those that require you to pre-declare it first.

However, I want to discuss the topic with a different slant, so my examples here will be about defining functions/procedures versus calling them.

Perhaps because I really learnt my craft with Pascal, I’ve usually worked with the approach that was taken in Pascal – and that was:

  • Define Before
  • Execute After

Let’s see what this is all about. To do that we will compare the concepts using several simple languages.

BASIC

Here is a simple program in the BASIC language. Execution will begin at the first line and stop when we run out of lines.

10 Print "Example program"
20 Print "After this line, we'll jump past the next ones."
30 Goto 80
40 Print "This line might never get run"
50 Print "This line also might never get run"
60 Print "This line also might never get run"
70 Print "This line also might never get run"
80 Print "This is the line that we jumped to"
90 Print "This line is the end of the program"

When it reaches line 30, in order to jump “ahead” (or “down” or however you want to think of it) the BASIC interpreter has to know (or at least to check) if there is actually a line 80 to jump to.

So clearly, in a BASIC program, if you (the human) are reading from the start of the program, you can use things that you haven’t yet defined.
i.e. you can write it, trusting that the thing you’re referring to (in this case, line 80) will be findable at run time.

Interpreters for the BASIC language do actually vary a lot in how they handle this kind of thing.

  • Some might scan the whole program, noting the Goto references and then, before executing anything, complain if any of them refer to nonexistent places.
  • Some might be so integrated with the editor that as you leave each line, it will check if it was valid and tell you immediately if it isn’t.
  • Some might not check anything, and merely try to do the jump at run-time and fail then if the target does not exist.

Ok, another example – but this time we’ll use the jump-down but then carry on where we were. That’s because instead of Goto we will use Gosub and its companion statement Return which is like a “goto but back to the line after the gosub call was done” action.

10 Print "After this line, we'll call the Gosub."
20 Gosub 70
30 Print "This line is between the two Gosub calls"
40 Gosub 70
50 Print "This line is the end of the program"
60 End
70 Print "This line is in the Gosub"
80 Return
90 Print "This line might never get run"

What we should note about this, is that while each Goto could perhaps be checked for validity before running the program at all, the same can’t be done for the Return statements. For example:

  • What if there never is a Return statement?
  • What if the line the Gosub refers to is reached without being sent via a Gosub – i.e. what does the Return do then?

Pascal

Here is a simple Pascal program.

program Example ;

procedure ExampleSubroutine ;
begin
WriteLn( "This line is in the ExampleSubroutine" ) ;
end ;

begin
WriteLn( "Example Program" ) ;
WriteLn( "After this line, we'll call the subroutine." ) ;
ExampleSubroutine ;
WriteLn( "This line is between the two subroutine calls." ) ;
ExampleSubroutine ;
WriteLn( "This line is the end of the program." ) ;
end.

What I’d like you to notice is that ExampleSubroutine had to be declared (and defined) before it could be referenced.

This means that the program text style in Pascal is to declare/define things first, and then use them afterwards. Indeed, Pascal was explicitly designed to allow for compiling programs in a single parse, i.e.run-through. (To be pedantic, there are some twists for dealing with linked pointers and mutual recursion but we’ll ignore those here.)

However it means that to “read” a Pascal program as a human, you would often skip past most of the code and find the begin end pair at the very end and read that to see what the program was doing. Then as each/any subroutine was called, you would go back to earlier in the text and read there to see what each would do when called.

Back to the “define before use” requirement, in classic Pascal, the following program text would not compile:

program Example ;

procedure ExampleSubroutine ;
begin
WriteLn( "This line is in the ExampleSubroutine" ) ;
AnotherSubroutine ;
end ;

procedure AnotherSubroutine ;
begin
WriteLn( "This line is in the AnotherSubroutine" ) ;
end ;

begin
ExampleSubroutine ;
end.

because the compiler would encounter the reference to AnotherSubroutine and not know what that would mean.

Therefore it would be necessary to rearrange the program as per the following:

program Example ;

procedure AnotherSubroutine ;
begin
WriteLn( "This line is in the AnotherSubroutine" ) ;
end ;

procedure ExampleSubroutine ;
begin
WriteLn( "This line is in the ExampleSubroutine" ) ;
AnotherSubroutine ;
end ;

begin
ExampleSubroutine ;
end.

However, improved facilities soon meant that it was feasible to write compilers that weren’t fazed by such simple issues. When the creator of Pascal made his later languages the order requirement was relaxed. In practice, many Pascal compilers also changed to cope with that too. While this might seem a little strange, the job of the compiler is that its task is inherently to compile the whole program before anything actually gets run.

Note, we’re still only talking about the order of things at the same level of “scope” – and I’ll defer talking about how scoping varies among languages to some other article.

Lots of languages..

Now I’m going to cheat and say that there are so many languages that almost every possible variation on these approaches exists in one, some or many of them.

Another reality is that many of the reasons for the early language being how they were became less vital, and so the requirements are often relaxed – with the compilers and interpreters doing the extra work to make it all happen.

Python

Ok, so what about Python?

Well, you certainly can write the program text in the same kind of order as for the Pascal example, where we are careful to define things (in text order) before we use them.

def AnotherSubroutine():
    print( "This line is in the AnotherSubroutine" )

def ExampleSubroutine():
    print( "This line is in the ExampleSubroutine" )
    AnotherSubroutine()

print( "Example Program" )
print( "After this line, we'll call the subroutine." )
ExampleSubroutine()
print( "This line is between the two subroutine calls." )
ExampleSubroutine()
print( "This line is the end of the program." )

But actually, Python will happily start executing direct code from the very beginning of the program text. So in the following example there are two lines of code that get executed before the function definitions occur.

print( "Example Program" )
print( "After this line, we'll call the subroutine." )

def AnotherSubroutine():
    print( "This line is in the AnotherSubroutine" )

def ExampleSubroutine():
    print( "This line is in the ExampleSubroutine" )
    AnotherSubroutine()

ExampleSubroutine()
print( "This line is between the two subroutine calls." )
ExampleSubroutine()
print( "This line is the end of the program." )

But the not-inside-function lines at the end, that call the functions, still has to come after they’ve been defined.

However, things are not quite the same as Pascal. In the following variation, the AnotherSubroutine definition comes after the place in the text where it gets used.

print( "Example Program" )
print( "After this line, we'll call the subroutine." )

def ExampleSubroutine():
    print( "This line is in the ExampleSubroutine" )
    AnotherSubroutine()

def AnotherSubroutine():
    print( "This line is in the AnotherSubroutine" )

ExampleSubroutine()
print( "This line is between the two subroutine calls." )
ExampleSubroutine()
print( "This line is the end of the program." )

But this is ok, because both definitions have happened before either of them actually gets called at the end of the program text.

So in Python, it is actually the run-time order of events that matter, rather than the placement of the text.

Appendix A – Compiled vs Interpreted Examples

Table

A quick list of commonly known and used languages – no matter how many I’d list I’d be missing someone’s pet language.

LanguageCompiled or InterpretedComments
JavaScriptInterpreted
PythonInterpreted
JavaCompiled
CCompiled
C++Compiled
C#Compiled
PHPInterpreted
VBAInterpretedas found inside Microsoft Office applications
VB.NetBoth
RInterpreted
SQLInterpretednot really a “programming” language
GoCompiled
PerlInterpreted
AssemblyCompilednot to be confused with “Web Assembly”
RubyInterpreted
Visual BasicBothi.e. the “Classic” VB, mostly VB6
RustCompiled

Leave a comment

Design a site like this with WordPress.com
Get started