In the following, we will discuss the development of programming languages as a means to improve their ability to capture the software design at ever increasing abstraction levels. Or, from another point of view, we discuss why advances in programming language technology are driven by the need to make programming languages capable of capturing higher-level designs.
Programming Languages and Design Principles
Making Code Look Like Design
“Designing” with Pseudo-Assembler
“Designing” with Pseudo-Assembler
What does the following program do?
i = 1
TEST: if i < 4
then goto BODY
else goto END
BODY: print i
i = i + 1
goto TEST
END:
“Designing” with Pseudo-Assembler
What does the following program do?
i = 1
LOOP: print i
i = i + 1
if i < 4 goto LOOP
END:
Though both programs just print out "123" the second one is easier to read and comprehend. It has a better style:
Clear structure
No crossing gotos
Better names
Code structure closer to what we want to express.
"Print out i, i smaller than 4“
Hence, the second variant, though functionally identical, is easier to understand, debug, change.
But:
Style can only be recommended, not enforced!
Designing with Structured Programming Languages
Designing with Structured Programming Languages
i = 1
while ( i < 4 ) {
print(i)
i = i + 1
}
Style gets enforced!
In the 1960th programming language support for better structuring of code emerged. Gotos were replaced by loops (while) and conditionals (if/else). Furthermore, procedures were introduced to support user-defined abstractions.
New words, new grammars, new abstractions enable developers to directly express looping/conditional computations, instead of emulating them by jumps. Using a – by then – modern structured programming language, it was no longer possible to write crossing gotos!
Better languages, More challenging tasks…
A simple image browser with structured programming:
Code for Image Browser Structured into Procedures
main () {
draw_label(“Art Browser”)
m = radio_menu(
{“Whale”, “Eagle”,
“Dogfish”})
q = button_menu({“Quit”})
while ( !check_buttons(q) ) {
n = check_buttons(m)
draw_image(n)
}
}
set_x (x) {
current_x = x
}
draw_circle (x, y, r) {
%%primitive_oval(x, y, 1, r)
}
set_y (y) {
current_y = y
}
radio_menu(labels) {
i = 0
while (i < labels.size) {
radio_button(i)
draw_label(labels[i])
set_y(get_y()
+ RADIO_BUTTON_H)
i++
}
}
Modular programming introduced modules, higher-level units/modules introduce higher-level abstractions! One can handle a whole module as if it was its interface.
Programming language mechanisms for supporting information hiding: interface hides module internals.
Module-based Abstraction
Abstraction enables us to:
look at the overall structure of the system (architectural thinking).
zoom in on individual units as needed
with more or less details
Hence, abstraction is the key to managing complexity.
Abstraction mechanisms enable us to code and design simultaneously!
"Write what you mean."
"The significant problems we face cannot be solved at the same level of thinking we were at when we created them."
Einstein
Makes the code easier to understand, debug and change.
Allows structured organization of code.
Ability to ignore details.
Makes the code closer to what we want to express.
Let’s “develop” application families with sophisticated GUIs with uniform look and feel with modular programming…
Great variability:
checkbox button, toolbar button, toggle button, radio button …
Modeling variability with modular programming languages appeared complex…
Designing with Object-Oriented Programming Languages
Designing with Object-Oriented Programming Languages
Object-oriented programming languages introduce new abstraction mechanisms:
classes,
inheritance,
subtype polymorphism.
(Still) Dominating Programming Paradigm
The roots of object-oriented programming languages are in the sixties.
Dahl and Nygaard, Simula 64, 68
Allan Kay, Smalltalk 70 - 80
Object-oriented languages are popular because they make it easier to design software and program at the same time.
They allow us to more directly express high level information about design components abstracting over differences of their variants.
Make it easier to produce the design, and easier to refine it later.
With stronger type checking, they also help the process of detecting design errors.
Result in a more robust design, in essence a better engineered design.
[…] improvements in programming techniques and programming languages in particular are overwhelmingly more important than anything else in the software business […]
[…] programmers are interested in design […] when more expressive programming languages become available, software developers will adopt them.
Jack Reeves, To Code is to Design, C++ Report 1992
Designing with Functional, Object-Oriented Programming Languages
Designing with Functional, Object-Oriented Programming Languages
By fusing object-oriented and functional programming we are provided with further means to raise our abstraction level. This enables us to better express our intention.
Example
Creating an abstraction to express that we want to repeat something n times.
def repeat[T: scala.reflect.ClassTag](times: Int)(f: ⇒ T): Array[T] = {
val array = new Array[T](times)
var i = 0
while (i < times) { array(i) = f; i += 1 }
array
}
Usage
Now, we can express that we want to read in two values from the command line.
val values = repeat(2) { System.in.read() }
Programming Languages are not a Panacea
Programming Languages are not a Panacea
Accessibility of object-oriented programming drives more complex designs!
Programming languages are powerful tools, but cannot and will never guarantee good designs.
Programming always needs to be done properly to result in good code.
Human creativity remains the main factor.
We need good style to cope with complexity!
...
Help is provided through established practices and techniques, design patterns and principles.
Good style can only be recommended, not enforced!
Eventually style rules will have to be turned into language features to be really effective.
General Design Principles
The following principles apply at various abstraction levels:
Keep it short and simple
Don't repeat yourself (also just called "DRY-Principle")