Learning to program in ...
Archive - Originally posted on "The Horse's Mouth" - 2009-11-15 06:02:00 - Graham EllisAt Well House Consultants, we offer courses at two levels in a number of program- ming languages. Our "learning to program in ..." courses are for delegates who have never programmed before, or who are rusty, who lack confidence, or want a refresher of the basic principles. Our "... programming" courses are for delegates who have prior programming experience, but are converting from another programming language to the one that we're teaching at the time. By offering two different starting points in this way, we can ensure that newcomers to programming aren't swamped in the first hours, yet experienced programmers don't have to sit through a day of the basics.
This module accompanies the "learning to" courses and intentionally leaves out code examples. It's very easy for me to show you "one I wrote earlier", but that doesn't teach you how to write a program for yourself. You need to see the thought process, so it will be done by demonstration. The examples written will be made available to you after the course, and you'll also find code in the remaining modules in these notes which also apply to the courses where we start with experienced programmers.
Stored programs ...
• A series of instructions in a text file
• Each instruction separated from the next somehow
• Instructions run sequentially
Running a stored program ...
• Need to translate from text to runnable
• Compiler, load and go, and interpreter options
• Need for library routines
Hello World ... and Hello delegates too
• Why we do a "hello world" example on every course
• How "Hello World" works in [target]
• Try it yourself.
• Cross-operating system issues
This will be demonstrated, and we’ll have you try it out too. It will feel clunky at first. Don't worry about that, you'll speed up later, and there will be lots of other things to learn about in your chosen language that will make it easier too.
At this point, one of things to think about is how portable your program will be between different computer architectures and operating systems. You may feel it's too early to look at this, but right from the start you'll want to know about the portablity and re-usability of your work.
Operators and operands (or commands)
• The two language patterns, and which [target] uses
• Writing a numeric expression
• Bodmas and brackets
Variables
• Storing a result under a name for later use
• Variable naming rules
• Declaring variables - type, size and scope, perhaps?
• Integer, Float, String and Boolean FAMILIES
• Other types and your own types
• Strong or weak typing
• Casting, converting and co-ercing
• Outputting a variable's content
Information – data – needs to be stored in a program between statements. Or rather it needs to be stored in the computer's memory. At the lowest of levels, that's a binary pattern of 0s and 1s in a numbered memory location that's encoded in such a way that it can be formed back into something that represents a number, or a string of text. In the very early days I've programmed computers that work like this, and it works, but it's pretty impractical for anything but elementary programs. So what do we do?
- We give descriptive names to the places we need to store the data
- We allow the programming language stuff to decide where to store the data in memory so we don't have to bother
- We have the programming language deal with all the low-level formatting too
Variable names are typically the programmer's choice, subject to a strict series of rules that differ from langauge to language. They'll be comprised of a letter, followed by more letters, digits and underscores. Maximum name length, whether upper and lower case letters have a different meaning, whether a variable name may start with an underscore differ.
Also
- In some languages, variable names are [sometimes] preceeded by a special character – a "sigil"
- And in some languages, certain words can't be used as variable names - "reserved words" such as if and break.
In some languages, the programmer is required to state the names of the variable
that will be used so that the compiler can allocate memory efficiently; that also has the benefit of making the programmer think about exactly what's going on. In other languages, it's the langauge internals which work out what storage is needed, and how it's to be used and coded, based on the context in which it's used in the code. Although this latter solution sounds easiest to write and is good, it does have the disad- vantage that it's all too easy for a variable to be misnamed, and for the programmer to end up with a bug that's hard to find.
I've mentioned different types of data that need to be stored. There are whole numbers, numbers with decimals, pieces of text, and others too which are collections or groups of variables, booleans ("true" or "false") and indeed composite variables of our own type definition. As you get deeper into programming, you'll need to under- stand these various type.
Data sometimes need to be converted between types; for example, a string of char- acters input by our user at the keyboard needs converting into a number on which calculations can be done. In some languages, this is done automatically for you, but in others you have to request explicitly that it be done.
There's also the matter, as programs grow, of how long the data in them (and the name) is retained. It would be wasteful in a long running program to retain data that's only required for a very short period as the program starts up right through to when the program finished running, but it would be frustrating if the programmer came to use a piece of data to find that it had gone away. There's the further matter here of a program that's got sections written by different programmers, and the need for vari- able names used by each of the programmers to be distinct from each other. Think of two families living in the same town, both of whom have daughters they name "Lorna". That's fine and good around the home, but when the two young ladies end up in the same class as school, the teacher says "please stand up Lorna" and both will stand up. So there needs to be something extra. This subject is called the "scope" of a variable, and it's so important that we raise it even on your very first day of program- ming to make you aware of an upcoming issue, though solutions and detailed discussions must wait until we're further into the course.
Constants
• Writing constants - implicit type
• Language support for constants
• Giving constants a name - for maintainability
There are some numbers – "constants" – which won't change (or you don't expect to change) in your program. There are 24 hours in a day, and seven days in a week. And there are some values which are constant to you, such as the maximum number of delegates on a public course might always be 7, the number of working days in the week might be 5, the BMI levels below which and above which a person is regarded as being unhealth may be 20.0 and 25.0.
There's nothing to stop you writing these numbers directly into your program, but that's not a good idea:
- You'll find it hard to find all occurrences of the number should it ever change
- You'll write code that's confusing in the extreme if the same constant happens to apply to two things
- The code won't be very descriptive when you come to read it back.
So you'll find that early on we recommend you assign constants into named loca- tions, and on this first day of the course we'll use variables. However, many languages also support a special notation for named constants, and if you use that:
- Your code can run more efficiently as there needs to be no mechanism to amend a value
- In languges which statically assign memory, a whole heap of complexity can be solved if the constant is a "maximum number of ..."
- The maintenance programmer is clearly told "this value won't be changing at run time"
- The constant can be much more widely scoped so that it's available right through your code without scope conflicts.
Your first useful program ... needs user input
• Reading from the user
• Converting a string into the right type
• The need for validation (to come back later)
• Exercises!
Conditionals
• Boolean Conditions
• Optional coding
• need for blocks to define how much is optional
• elseif and else
• Testing needs increased
• if - unless - switch - note shorthands for later
• what is equality
• equality in floats
• nesting
• Exercises!
Every language has some sort of conditional statement. That's a way of looking at some sort of setting or status in the program and performing some sort of action based on that setting or status.
Such statements take the form:
if {some sort of condition is true} then {run a group of statements}
The word if applies in every language that we teach at Well House Consultants at present, but how we define the condition, how we signify the end of the condition and the start of the group of statements, and how we stop and start that group varies.
- a "block" of code is a series of statements grouped together. Actually zero or more statements, as at times you'll want to have a "do nothing" group
- "Delimiters" are the characters or character groupings thet start and end blocks. They may be the words then, they may be the characters { and }, or they may be a pattern of spaces and tabs that insets the block in the source code. Sometimes they may be left out, and if the language supports that they imply a block of a single
statement.
The condition that's used in an if statement is going to be an expression that evaluates to a "yes" or "no" value – true or false. Exactly what comprises true and false varies between languages. Very often if your conditional expression works out at zero, that's false and if it works out to any other number, that's true. But numbers are only used in this way a small proportion of the time, as languages come with special operators that compare two values and return true or false based on that comparison.
Commonly they are:
== "is equal to"
!= "is not equal to"
< "is less than"
<= "is less than or equal to"
> "is greater than"
>= "is greater than or equal to"
But beware, in some languages (SQL and Lua) even these vary, and in many
languages (Perl, PHP, Shell for example) there are alternatives which do somewhat different things, and in some (Java, Python, Ruby, SQL, C, C++ for example) there are functions which you may call to make alternative comparisons. In other words, you're never limited to just the six comarisons.
These are notes to accompany your "Learning to program in xxxxx" course at Well House Consultants, so I'm not going to attempt to describe all the options here. Instead, I will demonstrate the first, most basic conditional statements to you at this point and let you try them out.
One of the questions that comes up for newcomers to programming is "why do I need a closing delimiter?". It's needed to tell your program that you've reached the end of code that's only run in certain circumstances and you're back into "always" code beyond that point. Imagine that you're driving a car and you decide to pull into a service station:
if (ineed == "loo") then { ......}
The block of code in the curly braces defines what you need to do in the service station, but then when you get back on the main road, it's "carry on as before", even if one or two of the variables (such as your comfort level) have been amended. The closure is vital as it removes the need for all subsequent code to be repeated. It's an indication of the coming together.
elseif and else
Usually, you'll want to perform one action if a condition is true, and some different action if the condition is false. Whilst it would be possible for you to write the "opposite" if statement, that's inefficient (at writing and run time) and prone to error, so languages support some sort of "otherwise" statement.
You can follow an if with one or more elseif (or elsif or elif clauses which in each case will have a further condition attached to them, and they'll have a block of code that runs if that alternative condition is true.
Note that the order of the various conditions is important, as once a true condition is found as the code runs, that's the block that will be run and the following ones won't be, even if the condition on them is also true.
Finally, you may finish your if statement with else and a block to accompany it. This is your 'catch all' or safety net which will be performed if neither the if condition, nor any of the el[se]if conditions were true. The else is optional; you can only have one of them, and there is no condition attached to it.
nested and joined conditions
You'll often find that you want to test for conditions within conditions (i.e. within the block of what to do) and you can do this. If you've stopped at the service area above because you needed a natural break, you'll be making other subsidiary deci- sions in there about whether to use the loo, have a coffee, buy sweets for the kids, call your desination to update your arrival time, etc. Note that you'll complete all of those extra actions before you complete the main action of making a stop at the service area. So use a nested conditional that starts in the order of 1, 2, 3 but ends 3, 2, 1.
There are also times that you want to perform a certain action only if two condi- tions are true. You could do this with nested blocks, but you'll also have an alternative, typically using the words and or or to link up conditions into a single composite conditions. Very often, either && or & are alternatives (with subtle differ- ences) for and, and or may be relplaced by || or |. This is a subject for much deeper study later in the course.
testing
As soon as you start introducing conditional code, you introduce multiple routes through the code so it becomes very important to give throught to a thorough testing regime.
As a minimum, you should test your progran before its use in a live application by running every single possible condition through its true and false routes. And you should consider also:
- - -
Running your code such that all combinations of conditions are tested. Testing your data where both valid and invalid user inputs are made. Remember to test "boundary" conditions; if you're testing for age under 18, run your code with (say) 16 and 20 , but also with 18 itself.
Testing gets to be repetitive and (let's admit it) a bit boring at times, and it's far too easy for us to skip. Yet it really should be repeated in full for each and every iteration and release of the code. We'll broach the detail of testing later on the course, but for the moment bear in mind that a standard set of tests, automated in a file so that you can easily rerun them, and with extra software to pick up hundreds or thousands of passes and the occasional fail is going to be far better that your programmer working through each and every test at every upgrade. You might even want to write the tests before you write the code that it's going to be testing – that's "Test Driven Develop- ment "or "TDD".
Loops
If your program always ran each statement just once (indeed skipping over state- ments which were in blocks in false conditions) it would run very quickly and would have little use. You couldn't (for example) run a program which went through a whole series of results from a database query and displayed particular data from each of them (plus perhaps a summary on the end).
• repeating block of code
• difference to conditional
• need to ensure you always exit the loop
• break and perhaps others
• Exercises!
So all programming languages have the ability to repeat a block of code, and the most fundamentel of these repeats ("loops") looks like this:
while {some sort of condition is true} then {run a group of statements}
You'll note that this is exactly the same format as the if statement in the previous section, apart from the replacement of the word if by the word while. Operation- ally, it differs in that once the group of statements in the block has been performed, the program rechecks the condition and if it's still true it runs the block again, keeping doing so until the condition becomes false.
Note:
- If the condition is false when first checked, the block isn't performed at all; a loop runs zero or more times
- If the condition never goes false you potentially have an infinite loop that goes on
forever
- Conditions are just the same as the conditions mentioned for the if statement in
the language you're learning.
Newcomers to programming sometimes take a few minutes to grasp their first program with a loop statement, as for the first time the code jumps backwards as well as forwards as it runs. And they sometimes have trouble working out which state- ments go where.
- If something may need to be run multiple times, it goes within the block (or within the condition to the while)
- If something only runs once and that's before the code in the block that may repeat, it goes before the while ("initialisation")
- If something runs once after any repeated code, that goes after the block that may repeat (e.g. printing a total)
I will show you a while loop in the language you're learning at this point, and have you write one too.
At times, you'll want to jump out of the middle of a loop and continue running code below ; if (for eaxmple) you've identified an incoming record that you were looking for within a stream of data, or if you have reached a threshold. Some languages provide you with a statement that you can put within a loop to get out of that loop even though the condition at the top hasn't been checked and has gone false. The keyword used is usually break but sometimes (in some languages) it's last.
Putting a break into a loop to be run unconditionally would be rather pointless, so you'll find that any break statements will be within a conditional statement such as (but not limited to) an if within the loop.
Most languages also support a continue statement (sometimes next) which allows you to skip the rest of the block code and go back up to test the condition straight away. Very useful if you're filtering a stream of data and you've identified a record such as a comment that you want to skip over without further processing.
Some languages have other flow controls in loops too; you may come across redo and retry. Early programming languages supported goto statements (and indeed some still do), but other than exceptional circumstances, their use is discouraged. They make for code that is very difficult to debug or to follow, and often impractical to upgrade when specifications change, and there are now far better ways.
Algorithms - a first bite
• Accumulator
• Min, max, average
There are common themes for how programming statements are put together to give a complete section of code to perform combined tasks. And typically these are putting together building blocks in a similar way to how we would do things if we were working something out by hand.
Looking for the maximum value in a column of numbers, for example, we would start off by guessing that the first number was the maximum, and then we would check against each of the following numbers to see if it was greater, updating our guess if it was. Come the end of the reading down the column, the final value is no longer just a guess, it really is the maximum.
Such standard application of coding is known as the application of "algorithms" or "design patterns" –that latter term is especially applicable to what we'll describe to you later on the course as "Object Oriented Programming".
All the languages that we teach have at least some algorithms or design patterns built into the language, as standard pieces of code in the library that we've referred to earlier in this module. In some languages, such as Lua and Tcl the standard libraries are quite small, and on the course we'll be showing you how to code certain algo- rithms yourself. In others such as PHP, we have a standing joke around the class that says "there's a function to do that" and indeed a huge array of common functions are available to you which you can call up in a single line to run a particular algorithm against some of your variables, passing back a result into another variable. Java, Python, Perl and Ruby – and some of the other languages – have a large number of algorithms available to you included in the language distribution (and present on your computer's disc or file system) but only loaded into memory at run time, typically on your request through a program statement asking for them to be loaded. And resources are available in virtually every language on the web to provide shared algo- rithms which, whilst commonly enough needed to be included in the distribution, are nevertheless worth sharing.
Documentation - a first bite
Also at this point, we'll take a first look at code documentation. "Hello World" really doesn't need too much backup information for the maintenance programmer – either a colleague of yours, or you yourself when you come back and try to remember what you did in 6 months or 6 years time because it needs updating.
• Comments
• Commentish code
• User documentation
• Exercises!
Comments make no difference to the running of your code, but they make a huge difference later on. You should include information about what the blocks of code do, and also any notes about the environment in which they are designed to run. Version numbers, copyright, support contact details and terms and conditions are also worth considering in serious code blocks.
As well as programmer's comments, instructions for your user should be provided. Most languages provide you with specific tools and an ability to build these instruc- tion into your source code. And it's very likely too, with modern programming, that you'll also provide some sort of test suite that lets you and your customers check that the program's functionality is still working as planned after upgrades and changes.
From here on, we're looking far more at demonstrations to show the delegates the way ahead - there's a revision of how the subjects above relate to the particular language on the main programming course that follows the "learning to program" day, and we'll go on to cover many of the following topics in much greater depth too - and with practicals!
Structure and more blocking
• Avoid repeated code via loops
• Avoid repeated code via named blocks
• Parameters in, parameters out
• Why default global is convenient but bad
• static variables or a clean start?
• Scoping in [target]
• Namespaces, and Structured and OO code
Collections
• Need to store multiple values under a single name
• Accessing via indexes
• Keys 0 based, 1 based, or not based at all.
• Fixed or variable length?
• Dealing with overflow
Pointers
• Extended collections (objects, structures, unions)
• Passing multiple bits of data as one
• Multiple names
• Symbol table and heap model
• Garbage Collection
Loading and Libraries
• Don't reinvent the wheel
• Sharing code between programs
• Sharing code between programmers
• Library Load order
• Mixing languages
• Version Control
Design
• Structured programming and the OO model
• What the user requires
• UML - using the concepts at least
• Future Proofing
And also ...
• Usability, maintainability, robustness and legality
• Debugging and tools
• Other algorithms - sorting and selecting
• Coroutines, parallel processing, threads, network resources
• Coding environments and standards
• Updates and language upgrades
• Security - abuse, misuse and error.
• Tailoring Standard Applications
• User training and support
• How does it work on The Web
• Open source, sell your programs, or just use yourself?
Footnote ...
• HTML, XML and SQL are not PROGRAMMING languages.
• But stored procedures, XSLT and even bash are.