Allgemeine Grundlagen der Programmierung


Kapitel 1: Programmiersprachen


Inhaltsverzeichnis

Dieses Buch ist unter einer Creative Commons-Lizenz lizensiert.


1.1 Aufbau und Bestandteile

Werkzeuge zur Verarbeitung von Informationen

Wenn man Programmiersprachen unter die Lupe nimmt und sie miteinander vergleicht, stellt man schnell fest, dass es große Ähnlichkeiten gibt. Programmiersprachen bestehen aus ähnlichen Bestandteilen. Wenn man verstanden hat, warum es diese Bestandteile gibt und welchen Sinn sie haben, ist es später kein Problem mehr, neue Programmiersprachen zu erlernen. Die Syntax, sprich die technischen Begriffe, sind von Programmiersprache zu Programmiersprache unterschiedlich, die dahinterstehenden Konzepte, auf die es ankommt, sind es - natürlich bis auf Ausnahmen - nicht.

Wozu braucht man Programmiersprachen? Was ist der Sinn und Zweck von Programmiersprachen? Programmiersprachen werden benötigt, um Computer-Anwendungen zu entwickeln. Computer-Anwendungen können ganz allgemein auf einen kleinsten gemeinsamen Nenner gebracht werden: Computer-Anwendungen verarbeiten Informationen. Es ist völlig egal, ob Sie es mit einem Browser, einer Textverarbeitung, einem Computerspiel oder einer Steuerungsanlage für Atomkraftwerke zu tun haben, letztendlich geht es schlicht und ergreifend um das Verarbeiten von Informationen.

Um Computer-Anwendungen zu entwickeln, die Informationen verarbeiten können, benötigt man entsprechende Werkzeuge. Programmiersprachen stellen diese Werkzeuge zur Verfügung.

Informationen können nur dann sinnvoll verarbeitet werden, wenn sich Informationen auch speichern lassen. Computer-Anwendungen müssen in der Lage sein, sich Informationen merken zu können, um beispielsweise später im Laufe des Programms auf vorher gespeicherte Informationen wieder zurückgreifen zu können. Würden nämlich zum Beispiel irgendwelche komplizierten Berechnungen zu einem Zwischenergebnis führen, auf das anderweitige Berechnungen im Programm folgen, bevor später mit dem Zwischenergebnis weitergerechnet wird, muss dieses Zwischenergbnis für später im Programm irgendwo festgehalten werden. Ohne das Speichern von Informationen würden errechnete Ergebnisse andauernd verloren gehen. Das Werkzeug, das sämtliche Programmiersprachen zur Verfügung stellen, um Informationen zeitweilig in einem Programm zu speichern, nennt sich Variablen.

Während Variablen lediglich das Speichern von Informationen ermöglichen, müssen Programmiersprachen noch mehr Werkzeuge zur Verfügung stellen - denn Computer-Anwendungen sollen ja nicht einfach nur Informationen speichern, sondern diese verarbeiten. Jede Programmiersprache stellt daher eine ganze Reihe vordefinierter Operatoren zur Verfügung. Diese Operatoren sind mehr oder weniger kryptische Zeichen, denen eine ganz bestimmte Bedeutung in der Programmiersprache zugewiesen ist. Mit diesen Operatoren können nun Variablen verknüpft werden. Je nach Operator wird diese Verknüpfung auf die eine oder andere Weise ausgeführt und führt schließlich zu einem neuen Ergebnis. Die Information in den beiden verknüpften Variablen wird vom Operator verrechnet und kann dann zum Beispiel in einer dritten Variablen gespeichert werden.

Mit Variablen und Operatoren kann man schon eine ganze Menge anstellen und bereits richtige Computer-Anwendungen entwickeln - zum Beispiel ein mathematisches Programm, das Zahlen addiert. Wenn Sie jedoch eine Software schreiben möchten, die den Anwender auffordert, ein Passwort einzugeben, und in Abhängigkeit des Passworts Zugriff auf geschützte Dateien ermöglicht, so reichen Variablen und Operatoren nicht aus, ein derartiges Programm zu schreiben. Das Problem ist, dass Sie in Ihrem Programm eine Entscheidung treffen müssen. Je nach eingegebenem Passwort muss der Zugriff auf die Dateien gestattet werden oder eben nicht - das hängt ganz davon ab, ob der Anwender das richtige Passwort kennt. Glücklicherweise bieten Programmiersprachen nun auch ein Werkzeug an, das Bedingungen überprüft und in Abhängigkeit dieser unterschiedlichen Code ausführt. Dieses Werkzeug nennt sich Kontrollstrukturen. Mit Kontrollstrukturen können Bedingungen überprüft werden, also zum Beispiel die Eingabe des Anwenders daraufhin, ob sie mit dem tatsächlichen Passwort übereinstimmt. Mit Kontrollstrukturen sind Verzweigungen im Code möglich - Code kann übersprungen oder sogar wiederholt werden. Programme laufen also nicht mehr stupide von oben nach unten ab, sondern verzweigen je nach Abhängigkeit von Bedingungen, die in Kontrollstrukturen überprüft werden.

Variablen, Operatoren und Kontrollstrukturen - eigentlich brauchen Sie schon gar nicht mehr, um Computer-Anwendungen zu entwickeln. Dummerweise ist die Software-Entwicklung eine recht komplizierte Geschichte. Je größer die zu entwickelnden Programme werden, umso schwieriger wird es, fehlerfreien Code zu schreiben. Die Komplexität in Programmen, die aus tausenden Code-Zeilen bestehen, lässt sich kaum mehr vom menschlichen Programmiererkopf erfassen. Programmiersprachen bieten daher ein weiteres Werkzeug an, um die Komplexität in den Griff zu kriegen. Der Code, den der Programmierer entwickelt, lässt sich in kleine übersichtliche Häppchen zerlegen. Anstatt also das gesamte Programm in einem Wisch zu schreiben, wird es in kleine Module zerlegt, die sich dann wieder gut überblicken und verstehen lassen. Das Werkzeug, um das es geht, wird in Programmiersprachen Funktionen genannt. Funktionen gliedern den Code und machen ihn übersichtlicher.

Es gibt Programmiersprachen, die sind an dieser Stelle fertig. Sie bieten Variablen, Operatoren, Kontrollstrukturen und Funktionen und damit alles, was Sie benötigen, um vollwertige Computer-Anwendungen zu entwickeln. Derartige Programmiersprachen werden prozedurale Programmiersprachen genannt. Prozedur ist ein anderer Begriff für Funktion und bezieht sich darauf, dass das höchste und beste Gestaltungsmittel in diesen Programmiersprachen eben die Funktionen sind. Bekannte prozedurale Programmiersprachen sind C, Pascal und Basic.

Leider gibt es in der heutigen modernen Software-Entwicklung das Problem, dass sie so ungeheuer komplex ist, dass Funktionen als Strukturierungsmittel nur ein Tropfen auf den heißen Stein sind. Anwendungen, die aus Millionen von Code-Zeilen bestehen, benötigen bessere Strukturierungsmöglichkeiten, damit die Programme überhaupt noch sinnvoll weiterentwickelt werden können. In den vergangenen Jahren hat sich die Objektorientierung durchgesetzt und nochmal ein Werkzeug auf die prozeduralen Programmiersprachen draufgesetzt. Code wird nun nicht mehr mit Hilfe von Funktionen übersichtlich gestaltet, sondern mit Klassen und Objekten. Die Objektorientierung stellt heute den heiligen Gral dar und ist das leistungsfähigste Instrument, das wir momentan haben, um Software zu entwickeln. So sind beispielsweise Computer-Anwendungen wie der Microsoft Internet Explorer oder die Programme aus Microsoft Office alle objektorientiert programmiert. Bekannte objektorientierte Programmiersprachen sind C++, Java und Smalltalk.

Im Folgenden lernen Sie verschiedene Bestandteile von Programmiersprachen etwas näher kennen. Anhand der Programmiersprache Javascript wird Ihnen gezeigt, wie man tatsächlich mit Variablen, Operatoren, Kontrollstrukturen und Funktionen umgeht und was Sie sich also wirklich unter der Programmierung vorzustellen haben.


1.2 Variablen

Informationstöpfe

Um Informationen in Programmen speichern zu können, benötigen Sie spezielle Töpfe: Variablen. Sie können als Programmierer jederzeit so viele Variablen herbeizaubern wie Sie möchten. Jede Variable stellt einen eigenen Behälter dar, in den Sie eine Information ablegen und sie im Laufe des Programms später wieder herausholen können. In der Programmiersprache Javascript gehen Sie wie folgt vor, um eine Variable anzulegen, sprich um einen Topf herbei zu zaubern.

var topf; 

Mit dieser einen Zeile zaubern Sie eine Variable namens topf herbei. Sie können nun in Ihrem Programm auf diese Variable topf jederzeit zugreifen und in ihr eine Information speichern. Variablen werden in vielen Programmiersprachen immer nach dem gleichen Schema angelegt: Zuerst geben Sie einen Datentyp an. In diesem Beispiel lautet der Datentyp var. Der Datentyp legt fest, welche Art von Information in der Variablen gespeichert werden kann. Es gibt Programmiersprachen, in denen Sie abhängig von der Art der Information, die Sie speichern wollen, einen ganz bestimmten Topf brauchen. Zu diesen Programmiersprachen zählen beispielsweise C, C++ und Java. In Javascript - der Programmiersprache, in der die vorliegenden Beispiele in diesem Buch geschrieben sind - gibt es hingegen nur den einen Datentyp var. Es spielt in Javascript für eine Variable keine Rolle, welche Art von Information Sie in ihr speichern möchten. Eine Variable in Javascript kann also zum Beispiel einen Buchstaben speichern oder eine Zahl oder auch ein Wort. In einer anderen Programmiersprache bräuchten Sie eventuell für einen Buchstaben auch tatsächlich einen Topf, der Buchstaben speichern kann, und für eine Zahl wiederum eine andere Art von Topf, der eben Zahlen speichern kann. Nichts anderes drückt der Datentyp aus - er legt fest, welche Art von Information in einer Variablen gespeichert werden kann.

Dem Datentyp folgt ein Variablenname. Variablen müssen irgendwelche Namen erhalten, damit man auf sie jederzeit in einem Programm zugreifen und sie identifizieren kann. Im obigen Beispiel hat die Variable einfach den Namen topf erhalten. Beachten Sie, dass Javascript wie auch viele andere Programmiersprachen wie C, C++ und Java Groß- und Kleinschreibung berücksichtigt.

Ebenfalls typisch für viele Programmiersprachen ist das Semikolon, das am Zeilenende angegeben wird. Mit dem Semikolon wird eine Anweisung beendet und abgeschlossen. Während Javascript es mit dem Semikolon nicht ganz so genau nimmt und auch mal darüber hinwegsieht, wenn es fehlt, müssen jedoch in C, C++ und Java Semikolons unbedingt gesetzt werden.

Während es in der Programmiersprache Javascript wie eben gesehen nur den einen Datentypen var gibt, muss beispielsweise in C++ einer Variablen, die Zahlen speichern können soll, der Datentyp int gegeben werden.

int zahlentopf; 

Benötigen Sie in C++ jedoch eine Variable, die ein Wort speichern können soll, so müssen Sie der Variablen den Datentyp string geben.

string worttopf; 

C++ ist eine streng typisierte Programmiersprache. Das heißt, Variablen haben keinen allgemeinen Datentyp wie in Javascript und können jede Art von Information speichern, sondern sie besitzen einen ganz konkreten Datentyp und können daher auch nur eine ganz bestimmte Art von Information speichern.

Der Vorteil der streng typisierten Programmiersprachen ist, dass Programmierfehlern vorgebeugt wird. Es ist in C++ nicht möglich, versehentlich in der oben angelegten Variablen zahlentopf ein Wort zu speichern - das funktioniert aufgrund des Datentypen nicht. Der Nachteil ist jedoch, dass Sie beim Anlegen von Variablen sich darüber im Klaren sein müssen, welche Art von Information Sie später speichern möchten. Davon hängt nämlich ab, welchen Datentyp Sie überhaupt angeben müssen.


1.3 Operatoren

Informationen verknüpfen und verarbeiten

Wie man Variablen anlegt wissen Sie nun. Sie können nun jederzeit so viele Variablen anlegen, wie Sie möchten, und darin Informationen speichern. Mit der Speicherung von Informationen allein ist es jedoch nicht getan. Schließlich soll Ihre Anwendung Informationen verarbeiten, also zum Beispiel eine Berechnung durchführen und zwei Zahlen addieren. Sie können mit Variablen Zahlen speichern, aber wie werden sie addiert?

Informationsverarbeitende Vorgänge wie zum Beispiel die Addition von Zahlen sind durch Operatoren möglich. Jede Programmiersprache bietet Operatoren an - ohne Operatoren können keine Informationen verarbeitet werden. Die meisten Programmiersprachen besitzen ähnliche Operatoren, die jeweils die gleiche Bedeutung haben. Wenn Sie beispielsweise wissen, wie die Operatoren in Javascript funktionieren, dann kennen Sie eigentlich auch schon fast alle Operatoren aus Java, C und C++. Im Folgenden sehen Sie ein paar Operatoren der Programmiersprache Javascript im Einsatz.

var i = 1, j = 2, k;

k = i + j;
k = i - j;
k = i * j;
k = i / j;
k += j;
k -= i;
i << j;

k = i > j;

k = (i + j) * 2;

Operatoren können nach ihrer Funktion gegliedert und verschiedenen Gruppen zugeordnet werden. So gibt es beispielsweise eine Gruppe arithmetischer Operatoren, deren Sinn und Zweck die Ausführung von Grundrechenarten mit +, -, * und / ist. So wie arithmetische Operatoren Zahlen verrechnen können, können logische Operatoren wie &&, || und ! Wahrheitswerte verrechen. Bitweise Operatoren wie &, |, ~ und ^ arbeiten sehr maschinennah. Mit diesen Operatoren kann man in Variablen die kleinsten Informationseinheiten bearbeiten, die der Computer besitzt - nämlich Bits. Eine andere Gruppe von Operatoren - die sogenannten Vergleichsoperatoren wie ==, !=, > und < - ermöglichen wiederum den Vergleich von Werten.

Neben diesen Operatoren besitzt jede Programmiersprache eine Präzedenz-Tabelle, in der jedem Operator per Definition einfach eine Priorität zugewiesen ist. Diese Präzedenz-Tabellen sind insofern entscheidend, als dass sie klar vorgeben, in welcher Reihenfolge Operatoren ausgeführt werden, wenn mehrere in einer einzigen Code-Anweisung verwendet werden. So kann beispielsweise die Präzedenz-Tabelle einer Programmiersprache festlegen, dass der * eine höhere Priorität besitzt als das +. Dies bedeutet nichts anderes als die Regel "Punkt vor Strich" aus der Mathematik: Eine Multiplikation wird gegenüber einer Addition bevorzugt ausgeführt. Sinnvollerweise sehen Programmiersprachen wie Javascript, Java, C und C++ genau dies auch vor.

Der Operator mit der höchsten Priorität ist für gewöhnlich die runde Klammer (). Das bedeutet, dass eine Klammerung immer bevorzugt und zu allererst ausgeführt wird. Das heißt auch, dass sich mit den Klammern die Ausführungsreihenfolge von Operatoren, wie sie durch die Präzedenz-Tabelle vorgegeben ist, ändern lässt. So wie in der Mathematik kann also durch geeignete Klammerung auch eine Addition zuerst ausgeführt werden, bevor die Summe dann mit einem anderen Wert multipliziert wird.


1.4 Kontrollstrukturen

Abhängig von Bedingungen unterschiedlichen Code ausführen

Mit Hilfe von Variablen und Operatoren können Sie nun Informationen wie beispielsweise Zahlen verarbeiten. Diese Verarbeitung erfolgt bis dato aber nur linear. Der Computer arbeitet Ihre Anweisungen im Programm von oben nach unten ab, und zwar jede Anweisung genau einmal. Wenn Sie jedoch beispielsweise einen Passwortschutz entwickeln möchten, muss abhängig von der Eingabe des Anwenders entweder Zugang zur gesicherten Ressource gewährt werden oder aber nicht. Verzweigungen des Programmflusses sind mit Kontrollstrukturen möglich. Auch folgende drei Code-Beispiele sind in der Programmiersprache Javascript geschrieben.

<html>
  <head>
    <title>Allgemeine Grundlagen der Programmierung</title>
    <script type="text/javascript">
      var passwort = "abc"; 
      var eingabe = prompt("Geben Sie ein Passwort ein."); 

      if (eingabe == passwort) { 
        alert("Passwort ok!"); 
      } else { 
        alert("Passwort falsch!"); 
      } 
    </script>
  </head>
  <body>
  </body>
</html>

Die if-else-Anweisung ermöglicht eine einfache Überprüfung einer Bedingung. Ist die Bedingung wahr, wird der Anweisungsblock, der durch die geschweiften Klammern definiert wird, hinter dem if ausgeführt. Ist die Bedingung falsch, wird der Anweisungsblock hinter dem else ausgeführt. Ist der jeweilige Anweisungsblock ausgeführt worden, setzt die Programmausführung hinter der if-else-Anweisung fort.

<html>
  <head>
    <title>Allgemeine Grundlagen der Programmierung</title>
    <script type="text/javascript">
      var passwort = "abc"; 
      var eingabe = prompt("Geben Sie ein Passwort ein."); 

      while (eingabe != passwort) { 
        eingabe = prompt("Das Passwort ist falsch. Bitte nochmal probieren."); 
      } 
    </script>
  </head>
  <body>
  </body>
</html>

Die while-Anweisung ist eine sogenannte Schleife. Neben der while-Schleife bieten Programmiersprachen auch andere Schleifen wie die do-while-Schleife oder die for-Schleife an. Alle diese Schleifen arbeiten jedoch ähnlich: Sie führen einen Anweisungsblock wiederholt aus, und zwar solange eine zu überprüfende Bedingung wahr ist.

Im Zusammenhang mit Schleifen taucht oft ein Programmierfehler auf, der Endlosschleife genannt wird. Eine Endlosschleife ist eine Schleife, die unendlich oft wiederholt wird, weil die zu überprüfende Bedingung immer wahr bleibt. Endlosschleifen machen sich dadurch bemerkbar, dass das Programm scheinbar stehen bleibt und auf Benutzereingaben nicht mehr reagiert.

<html>
  <head>
    <title>Allgemeine Grundlagen der Programmierung</title>
    <script type="text/javascript">
      var passwort = "abc"; 
      var eingabe = prompt("Geben Sie ein Passwort ein."); 

      while (eingabe != passwort) { 
        eingabe = prompt("Das Passwort ist falsch. Bitte nochmal probieren."); 
        if (eingabe == "ende") { 
          break; 
        } 
      } 
    </script>
  </head>
  <body>
  </body>
</html>

Über ein zusätzliches Schlüsselwort wie break ist es darüberhinaus möglich, Schleifen vorzeitig zu verlassen. Die Schleife endet dann also nicht, weil die zu überprüfende Bedingung nicht mehr wahr ist, sondern sie endet sofort, wenn die Code-Ausführung auf break trifft.


1.5 Funktionen

Jederzeit aufrufbare Anweisungsblöcke

Den Begriff Anweisungsblock haben Sie bereits im Zusammenhang mit Kontrollstrukturen gehört. Ein Anweisungsblock ist in den Programmiersprachen Javascript, C, C++ und Java durch die geschweiften Klammern { und } begrenzt. Zusammen mit den darin enthaltenen Anweisungen bilden sie einen Anweisungsblock, der beispielsweise dem Schlüsselwort if folgen kann.

Anweisungsblöcken lassen sich auch Namen zuordnen. Über diesen Namen kann ein Anweisungsblock aufgerufen werden. Dadurch wird er ausgeführt. Ein derart aufrufbarer Anweisungsblock wird Funktion genannt.

<html>
  <head>
    <title>Allgemeine Grundlagen der Programmierung</title>
    <script type="text/javascript">
      function hallo() { 
        alert("Hallo!"); 
      } 

      hallo(); 
    </script>
  </head>
  <body>
  </body>
</html>

Obiges Code-Beispiel zeigt, wie Funktionen in Javascript aussehen. Hinter dem Schlüsselwort function folgt der Name der Funktion. Hinter dem Namen werden gegebenfalls in Klammern Parameter angegeben. Ansonsten bleiben die Klammern leer. Im Funktionsrumpf - also im Anweisungsblock - werden nun alle Anweisungen definiert, die ausgeführt werden sollen, wenn die Funktion aufgerufen wird.

Parameter sind Eingabewerte, die man an eine Funktion weitergeben kann, wenn man sie aufruft, und die intern in der Funktion verarbeitet werden. Nicht jede Funktion benötigt Eingabewerte. Die Funktion im obigen Beispiel zeigt einfach eine Meldung am Bildschirm an, so dass es nicht nötig ist, irgendwelche Parameter an diese Funktion weiterzureichen.

Wenn man auf eine mit function definierte Funktion zugreifen möchte, ruft man sie über den Funktionsnamen auf. Man gibt hierzu den Namen der Funktion an und dahinter in Klammern eventuell zu übergebene Parameter. Nachdem die Funktion hallo() keine Parameter erwartet, wird beim Aufruf auch keiner zwischen den Klammern angegeben. Die Klammern sind dennoch wichtig und dürfen nicht weggelassen werden, um hallo() eindeutig als Funktionsaufruf zu identifizieren und nicht als Variable.

<html>
  <head>
    <title>Allgemeine Grundlagen der Programmierung</title>
    <script type="text/javascript">
      function add(a, b) { 
        alert(a + b); 
      } 

      var i = 1, j = 2; 
      add(i, j); 
    </script>
  </head>
  <body>
  </body>
</html>

Im obigen Javascript-Code wird nun eine Funktion definiert, die zwei Parameter a und b erwartet. Das heißt, bei Aufruf der Funktion add() müssen in Klammern auch zwei Parameter übergeben werden. Im Beispiel sind das die Variablen i und j. Durch den Aufruf der Funktion add() und die Übergabe der beiden Variablen wird innerhalb der Funktion die Summe der übergebenen Werte gebildet. a und b stellen letztendlich nur Platzhalter dar für die Werte, die beim Aufruf der Funktion angegeben werden.

Wenn Sie sich obiges Beispiel genau ansehen, stellen Sie fest, dass unter anderem eine Funktion alert() aufgerufen wird. Diese Funktion ist eine in Javascript eingebaute Funktion und steht dem Programmierer in Javascript automatisch zur Verfügung. Mit alert() öffnet sich ein kleines Fenster auf dem Bildschirm, das jeweils das anzeigt, was als Parameter der Funktion alert() übergeben wurde - im obigen Fall also das Ergebnis der Addition.


1.6 Strukturen

Datenblöcke

So wie sich mehrere Anweisungen zu Funktionen zusammenpacken lassen ist es auch möglich, mehrere Variablen zu einer Struktur zusammenzustellen. Diese Möglichkeit besteht jedoch in der Programmiersprache Javascript nicht, so dass folgendes Code-Beispiel der Programmiersprache C++ entnommen ist.

struct adresse 
{ 
  string Vorname; 
  string Nachname; 
  string Strasse; 
  int PLZ; 
  string Ort; 
}; 

adresse MeineAdresse; 

Durch das Erstellen einer Struktur ist es möglich, Datentypen in seinem Programm zu verwenden, die es noch nicht gibt. Nachdem C++ nicht von Haus aus einen Datentyp für die Speicherung von Adressen zur Verfügung stellt, können Sie dank Strukturen nun diesen Datentyp selber erstellen. Einmal erstellt können Sie wie gewohnt von diesem neuen Datentyp eine Variable anlegen. Im obigen Beispiel ist der Name der Variablen MeineAdresse. Und diese Variable kann nun Informationen vom Typ adresse speichern.


1.7 Sonstige Bestandteile

Von Klassen und Objekten

Die in diesem Kapitel bekanntgewordenen Bestandteile einer Programmiersprache finden Sie in fast jeder Sprache. Darüberhinaus bieten Programmiersprachen teilweise Elemente wie Klassen und Objekte an. Zu diesen Programmiersprachen gehören beispielsweise Smalltalk, C++ und Java. Es handelt sich hierbei um objektorientierte Programmiersprachen. In derartigen Programmiersprachen wird mit Objekten gearbeitet, die eine Programmentwicklung ermöglichen, die näher an der Problembeschreibung orientiert ist. Durch geringere Abstraktion vom Problem zum Lösungs-Programm lassen sich vor allem größere Anwendungen einfacher entwickeln, die durch fehlende Klassen- und Objekt-Unterstützung zu unübersichtlich werden würden.

Objektorientierte Programmiersprachen stellen derzeit den heiligen Graal unter den Programmiersprachen dar. Sie sind das leistungsfähigste Instrument, mit dem heutzutage Software entwickelt werden kann. Die meisten großen und erfolgreichen Anwendungen wie zum Beispiel der Internet Explorer von Microsoft oder sämtliche Programme aus Microsoft Office sind objektorientiert programmiert. Dennoch hat auch die Objektorientierung etwas von ihrem Glanz verloren. Galt sie noch vor Jahren als das Nonplusultra, als die endgültige Lösung aller Probleme in der Software-Entwicklung, so muss man dennoch erkennen, dass sie kein Allheilmittel ist, sondern ebenfalls durchaus verbesserungswürdig ist. Selbstverständlich entwickeln sich auch Programmiersprachen und Managementmethoden in der Software-Entwicklung weiter, so dass auch hier sicherlich noch nicht aller Tage Abend ist.


1.8 Sprach-Entwicklung

Von proprietären Sprachen und offenen Standards

Die Entwicklung der Programmiersprachen verläuft großenteils sehr verflochten. Die heute sehr verbreiteten Programmiersprachen C, C++ und Java sind sehr ähnlich gestrickt. C trat hierbei zeitlich zuerst auf, wurde dann um objektorientierte Elemente zu C++ ergänzt. Die Entwicklung der Programmiersprache Java Jahre später wurde sehr eng an C++ angelehnt. Javascript wurde gleichzeitig zu Java entwickelt und hieß ursprünglich ActiveScript. Vor dem ersten Release wurde die Sprache dann an Java angepaßt - sowohl von ihrer Syntax als dann auch vom Namen her.

Die vor allem im Bereich der Windows-Betriebssysteme verbreitete Sprache Visual Basic stammt von Basic ab. Basic selbst ist ebenfalls wie C eine recht alte Sprache, die auch unter dem Vorgänger von Windows, MS-DOS, als qbasic vertreten war. Auch VBScript, eine Konkurrenzsprache zu Javascript, ist sehr eng mit Visual Basic verwandt. Heutzutage ist Basic in all seinen Dialekten vor allem eine Programmiersprache, die stark von Microsoft unterstützt und weiterentwickelt wird und daher vorrangig auf den Betriebssystemen von Microsoft Einsatz findet.

Die allermeisten Sprachen gehören der Allgemeinheit, um es etwas salopp auszudrücken. Sie werden von Programmierern weltweit weiterentwickelt, was spätestens seit dem Internet kein Problem mehr darstellt. Die Standardisierung der Weiterentwicklungen übernehmen internationale Gremien, in denen meist Vertreter führender Softwarefirmen sitzen. Die prominenten Gründerväter der Programmiersprachen sprechen innerhalb der Weiterentwicklung und Standardisierungsgremien natürlich häufig auch ein paar wichtige Worte mit.

Die wohl bekannteste Programmiersprache, die einer Firma gehört und nicht von internationalen Gremien weiterentwickelt wird, ist Java. Java ist eine proprietäre Sprache und gehört der Firma Sun Microsystems. Wer Java benutzen will, muss die Lizenzbestimmungen zu Java akzeptieren. Eine unabhängige Weiterentwicklung der Programmiersprache ist hierbei verboten. Im Januar 2001 endete ein mehrjähriger Gerichtsprozess zwischen Sun und Microsoft, in dem Sun Microsoft vorwarf, sich nicht an die Lizenzbestimmungen gehalten zu haben, sondern auf eigenständige Weise die Programmiersprache Java verändert zu haben. Seit Januar 2001 wird daher Java von Microsoft nicht mehr unterstützt.


1.9 Compiler und Interpreter

Vom Quellcode zur Programmausführung

Wenn Sie wie in den obigen Beispielen kleine Programme schreiben, arbeiten Sie als Programmierer immer mit dem Quellcode. Der Quellcode ist der für den Menschen lesbare Programmablauf. Während Sie und ich diesen Quellcode recht gut verstehen, kann der Computer damit überhaupt nichts anfangen. Das ist insofern von Bedeutung, als dass Sie ja möchten, dass der Computer Ihr Programm ausführt. Der Computer versteht aber nur Maschinencode. Das heißt, irgendjemand muss den Quellcode des Programms in Maschinencode umwandeln.

Zum Umwandeln von Quellcode in Maschinencode werden Programme verwendet, die Compiler heissen. Je nach verwendeter Programmiersprache und Computersystem brauchen Sie einen anderen Compiler. Wenn Ihr Quellcode in der Programmiersprache C++ geschrieben ist und Sie das Programm beispielsweise auf einem Computer mit dem Intel-Pentium-Chip ausführen lassen möchten, brauchen Sie einen Compiler, der C++-Quellcode in Maschinencode für den Intel-Chip umwandeln kann. Soll Ihr C++-Quellcode dagegeben auf einem Computer mit einem PowerPC-Chip laufen, brauchen Sie einen Compiler, der C++ in Maschinencode für den PowerPC umwandelt. Compiler müssen also auf der einen Seite die Sprache des Quellcodes beherrschen, auf der anderen Seite auch den Maschinencode des Zielsystems.

Neben Compilern gibt es noch sogenannte Interpreter. Wenn Sie Javascript-Beispiele ausführen, stellen Sie fest, dass Sie nirgendwo Ihren Quellcode in Maschinencode umwandeln. Der PC versteht Ihren Quellcode scheinbar automatisch. Dies funktioniert nur deswegen, weil das Programm, das Ihren Quellcode ausführt, zuerst einen Interpreter startet, der Ihren Quellcode analysiert. Nach dieser Analyse weiß dann das Programm, was Sie eigentlich in Ihrem Quellcode machen wollen, und führt die entsprechenden Funktionen aus. Da in den modernen Browsern heutzutage ein Javascript-Interpreter integriert ist, können Sie normalerweise ohne Probleme sämtliche Javascript-Beispiele in Ihrem Browser ausführen.

Quellcodes, die mit Compilern in Maschinencode umgewandelt werden, müssen diese Umwandlung nur einmal vornehmen. Danach liegt eine ausführbare Datei vor, die Sie - beispielsweise durch Doppelklick wie in Windows - jedesmal sofort starten können. Man spricht auch von nativen Anwendungen. Sie brauchen den Quellcode nicht mehr, da in der Datei bereits der vollständige Maschinencode vorliegt. Und das ist das einzige, was der PC benötigt.

Quellcode wie beispielsweise der in Javascript muss jedesmal, wenn er ausgeführt werden soll, neu vom Programm analysiert werden. Hier wird nirgendwo Maschinencode erstellt oder gar für spätere weitere Programmausführungen gespeichert. Dadurch, dass jedesmal eine neue Analyse notwendig ist, sind Programme, die interpretiert werden, in der Ausführung langsamer als Programme, die bereits als Maschinencode vorliegen. Hier fällt eine Analyse weg, der Computer kann den Maschinencode sofort ausführen.

Die Programmiersprache Java nimmt hier eine Sonderstellung ein. Quellcode in Java wird kompiliert, jedoch nicht für ein ganz bestimmtes Zielsystem wie einen Intel-Pentium-Chip oder einen PowerPC-Chip, sondern für eine virtuelle Maschine. Diese virtuelle Maschine ist letztendlich ein Computer-Programm, das den kompilierten und virtuellen Maschinencode interpretiert. Durch die Umwandlung von Java-Quellcode in virtuellen Maschinencode und durch die Interpretierung des virtuellen Maschinencodes kann eine höhere Ausführungsgeschwindigkeit erreicht werden als bei rein interpretierenden Sprachen. Die Ausführungsgeschwindigkeiten von rein kompilierten Programmiersprachen im Vergleich zu Java sind dennoch um das zehn- bis zwanzigfache schneller - ganz grob über den Daumen gepeilt. Durch die Kompilierung des Quellcodes für eine virtuelle Maschine ist Java aber eine Sprache mit größerer Portabilität. Während beispielsweise C++-Programme entweder für einen Intel-Pentium-Chip oder aber für einen PowerPC-Chip kompiliert werden, laufen Java-Programme auf allen Computer-Systemen - immer vorausgesetzt, ein Programm für die Interpretierung des virtuellen Maschinencodes existiert. Java-Programme tauschen sogesehen Ausführungsgeschwindigkeit gegen Portabilität ein.


1.10 Aufgaben

Übung macht den Meister

Sie können die Lösungen zu allen Aufgaben in diesem Buch als ZIP-Datei erwerben.

  1. Entwickeln Sie ein Programm in Javascript, das den Anwender zur Eingabe eines Passworts auffordert. Wird das Passwort dreimal hintereinander falsch eingegeben, soll keine weitere Eingabeaufforderung mehr erscheinen.

  2. Entwickeln Sie ein Programm in Javascript, das den Anwender auffordert, zwei Zahlen einzugeben. Addieren Sie die beiden Zahlen und geben Sie das Ergebnis auf den Bildschirm aus.

  3. Entwickeln Sie ein Programm in Javascript, das den Anwender auffordert, zwei Zahlen einzugeben und danach eines der vier Zeichen +, -, / und *. Je nach eingegebenem Zeichen sollen die beiden Zahlen addiert, subtrahiert, dividiert oder multipliziert werden. Das Ergebnis der jeweiligen Rechenart soll auf den Bildschirm ausgegeben werden. Entwickeln Sie keine eigenen Funktionen zur Lösung der Aufgabe.

  4. Entwickeln Sie den Javascript-Taschenrechner der obigen Aufgabe diesmal unter Verwendung von Funktionen. Dabei soll für jede der vier Rechenarten eine andere Funktion aufgerufen werden, die die jeweilige Rechenoperation durchführt und dann das Ergebnis auf den Bildschirm ausgibt.