Programmiersprachen im Vergleich

Programm "Factor"
Input: Zwei Zahlen a und u.
Output: Malfolge von a*1 bis a*u
Wichtig: Das Programm soll sich erst nach Drücken einer Taste beenden.
Gewünschte Form:

Sprachen
C++, Pascal, ObjectPascal (Delphi), Perl, Ruby (1.8.0), Lua, Basic (QBasic 1.1), Echo, Extreme (spezielle Sprachen für dieses Problem)

Vergleich

Sprache Code (Byte) Zeilen

Speicher (KB)

Exe (KB)
C++ 237 13 (11) 1324 25.8
Pascal 199 12 1356 2.8
ObjectPascal 219 13 ? 10.0
Perl 167 9 (8) 1456 -
Lua 155 8 (7) - -
Basic 126 7 (6) ? -
Ruby 120 8 (7) ? -
Echo 92 6 - -
Extreme 59 3 - -

? sind noch zu testen, - sind irrelevant

Codegröße
Hier unterliegt C++ der Konkurrenz. Perl und seine Verwandten Ruby und PHP sind in ihrem Element.

Quellcodezeilen
C++ und Pascal sind gleich auf. Der Perl-Quellcode ist etwas kleiner. Basic gewinnt hier vor allem durch den eingesparten Print-Befehl, Ruby durch Iteration.

Speicherverbrauch
Hier liegt C vorne mit 2% weniger Speicherverbrauch als Pascal und fast 10% weniger als Perl. Allerdings sind die Unterschiede vernachlässigbar klein.

Größe der Ausführbaren Datei (sofern vorhanden)
Das C++-Programm ist ca. 10mal so groß wie das Pascal-Programm und sogar noch doppelt so groß wie die Delphi-Variante.
Damit stellt sich das Gerücht, dass C++ die kleinsten Programme kompiliert, als Mythos heraus.

Übersichtlichkeit
Hier müssen Sie selber beurteilen, was Sie am besten verstehen, denn wir als Pascal-Fans sind wohl voreingenommen. Man könnte aber die Vermutung wagen, dass der kürzeste Code auch gleichzeitig der beste ist: Ruby.

Java
Mit Java (der verbockte C-"hach was bin ich objektorientiert"-Auswurf, Kommentar Korny) haben wir es immer noch nicht hinbekommen, eine simple Konsolenanwendung zu schreiben. Die Applet-Version ist so umfangreich, dass wir niemanden damit belasten wollen. Falls jemand eine Idee zur Realisierung hat...

Echo, Extreme
...haben wir uns selbst ausgedacht. Es soll einfach nur zeigen, wie das Problem mit einer speziellen Sprache zu lösen wäre.

C++

#include <iostream.h>
main() {
  int a;
  int u;
  cout << "Factor: ";
  cin  >> a;
  cout << "Until: ";
  cin  >> u;
  for (int i = 1; i <= u; i++) {
    cout << a << " * " << i << " = " << a * i << "\n";
  };
  cin  >> a;
}

Kommentar (Korny)
Im Gegensatz zur Absicht der Entwickler hilft es der Codegröße nicht, dass die Variablen mitten im Code deklariert werden dürfen. Die höchst abstrusen Befehle cout (fehlt da nicht ein "ist": c ist out?) und cin erledigen die Ein- und Ausgabe, verzichten aber auf Klammern. Wir haben uns an der üblichen Schreibweise orientiert und die Dreieckszeichen untereinander angeordnet.
Statt der sperrigen Anfangswert-Bedingung-Inkrement-for-Schleife hätte wieder mal ein Bereichs-for gereicht, das es in C jedoch nicht gibt. Das nötige Zeilenendezeichen ergänzt den Zeichenwust innerhalb der for-Schleife.
Durch insgesamt 11 Zeichen >> und <<, eine leere Klammer nach dem Prozedurnamen, eine Deluxe-for-Schleife und ein Zeilenendezeichen wird der Quellcode zu größten in unserem Test. Doch auch der Schreibaufwand führt nicht zu größerer Übersicht. C wurde scheinbar nicht konzipiert, um kleine Ein- und Ausgabeprogramme zu erstellen. Fragt sich, wofür dann: Eine Programmiersprache ist so einfach wie möglich und so komplex wie nötig. C ist komplex und unnötig. Wenigstens konnten wir das Programm schnell realisieren, ohne C-Experten zu sein.

C++ (Variante)

#include <cstdio>
int main(int argc, char *argv[])

{
  int a, u;
  printf( "Factor: ");
  scanf("%i", &a);
  printf( "Until: ");
  scanf("%i", &u);
  for (int i = 1; i <= u; i++)
    printf("%i * %i = %i\n", a, i, a*i);
  flush();
  getchar();
  return 0;
}

Kommentar (Happosai)
Der obige Code verwendet vordefinierte Funktionen aus der Standard- (std) Input/Output- (io) Headerdatei. In der Funktion, in der das Programm abläuft (main() mit entsprechenden Kommandozeilenargumenten), werden zuerst 2 Variablen vom Typ Integer deklariert. Dann wird ein Text ausgegeben (printf) und der Input-Stream wird mit scanf nach einem bestimmten muster ("%i") gescannt. Der eingelesene Wert wird an die Variable übergeben, die der Funktion als Adresse (&a) übergeben wurde. Dann folgt die simple for-Schleife, die die geschweiften Klammern auch entbehren kann, da wir nur eine Anweisung im Schleifenkörper haben. Die Ausgabe der einzelnen Werte erfolgt durch Einsetzung nach den Regeln des Formatstrings. Am Ende wird noch auf ein einzelnes Zeichen gewartet. Zur Sicherheit haben wir vorher noch flush() aufgerufen, um den Buffer zu leeren. Zuletzt wird ein Wert ans OS zurückgegeben, dass diesen aber meistens nicht noch explizit auswertet.

Pascal

program Factor;
var
  a, u, i: Integer;
begin
  Write('Factor: ');
  ReadLn(a);
  Write('Until: ');
  ReadLn(u);
  for i := 1 to u do
    WriteLn(a, ' * ', i, ' = ', a * i);
  ReadLn;
end.

ObjectPascal

program Factor;
{$APPTYPE CONSOLE}
var
  a, u, i: Integer;
begin
  Write('Factor: ');
  Readln(a);
  Write('Until: ');
  Readln(u);
  for i := 1 to u do
    Writeln(a, ' * ', i, ' = ', a * i);
  Readln;
end.

Kommentar (Korny)
Auch heute noch benötigt Pascal einen Programmrahmen. Als Applikations-orientierte Sprache muss man Delphi erst per Compiler-Direktive klar machen, dass es sich um eine Konsolen-Anwendung handelt. Aus irgend einem Grund haben sich die Delphi-Entwickler entschieden, das ln am Ende der I/O-Prozeduren klein zu schreiben, was wir beachten. Ansonsten dasselbe Bild wie bei Ur-Pascal.

Perl

print "Factor: ";
$a = <STDIN>;
chop($a);
print "Until: ";
$u = <STDIN>;
for ($i = 1; $i <= $u; $i++) {
    print "$a * $i = ".($a * $i)."\n";
};
$a = <STDIN>;

Ruby

print 'Factor: '
a = gets.to_i
print 'Until: '
u = gets.to_i
for i in 1..u
 
puts "#{a} * #{i} = #{a*i}"
end
gets

Kommentar (Korny)
Es sieht fast so aus, als hätte Matz (Yukihiro Matsumoto, Erfinder von Ruby) seine Sprache extra für dieses Problem optimiert: Keine überflüssigen Elemente wie Semikolons am Zeilenende. Die gets-Methode liefert einen String, der als Objekt in einen Integer-Wert umgewandelt werden muss, wodurch aber a und u als Zahlen erkennbar werden.
Die einfache for-Schleife erledigt die Ausgabe wie gewohnt. puts gibt, anders als print, am Ende gleich das Zeilenende mit aus: Erinnerung an WriteLn. Dann folgt die Ruby-Variante der "Variablen in Strings": Statt wie in Perl zu fordern, dass jede Variable mit einem besonderen Zeichen beginnt, werden Codeelemente in #{Klammern} eingeschlossen.
Dadurch ist auch die Multiplikation im selben String möglich, wo Perl erst verketten muss. Allerdings musste dafür bei der Eingabe erst umgewandelt werden. gets am Ende wartet natürlich auf ein Return.

Lua

io.write ("Factor: ")
a = io.read ()
io.write ("Until: ")
u = io.read ()
for i = 1 , u do
print (a .. " * " .. i .. " = " .. a * i)
end
io.read ()

Kommentar (Günther)
print() ist die simple Ausgabefunktion, sie beendet eine Ausgabe aber immer mit einem Zeilensprung, deshalb io.write() für die geforderte Form.
Es gibt mindestens drei Möglichkeiten zur Ausgabeformatierung: Mehrere Parameter, Stringverknüpfung mit "..", und string.format. Ich habe keine Ahnung, welche die beliebteste ist. print() fügt zwischen zwei Parametern einen Tabulator ein, aber ansonsten funktionieren alle Kombinationen zwischen den Möglichkeiten und den beiden Funktionen wie gefordert.

Basic

CLS
INPUT "Factor: ", a%
INPUT "Until: ", u%
FOR i% = 1 TO u%
  PRINT a%; " * "; i%; " = "; a% * i%
NEXT i%
INPUT "", a%

Kommentar (Korny)
Hier brauchen wir nicht zu mutmaßen, denn Basic wurde für diesen Zweck geschaffen. Die Sprache ist extra für Konsolenanwendungen entwickelt worden, genauer sogar für die DOS-Shell. Daher auch das obligatorische CLS am Anfang, dass bekanntermaßen den Bildschirm löscht. Als einzige Sprache kennt Basic einen Befehl, der Aus- und Eingabe in einer Zeile ermöglicht. Eine weitere interessante Idee ist die Typisierung durch bestimmte Variablenendungen (ähnlich wie bei Perl): % steht für Integer. Und wie in Ruby hat man hier auf ein Anweisungs-Trennzeichen verzichtet.
Die for-Schleife ist Pascal erstaunlich ähnlich und wie immer ist die "von...bis"-Variante sinnvoller. Der PRINT-Befehl benutzt Semikolons als Stringverketter...wollte man hier Pascal- und C-Programmierer verwirren? C's kuriose << sind jedenfalls auch nicht besser. Das Ende der Schleife wird, wenig innovativ, mit der Wiederholung der Variable gekennzeichnet. Man darf diese zwar auch auslassen und nur NEXT schreiben, was allerdings aus Gründen der Übersicht unüblich ist.
Zur letzten Zeile: Das Komma verhindert lediglich, dass INPUT ein "?" ausgibt, was gegen die Vorgaben wäre. Diese Standardeinstellung ist schon seltsam, ihre Verhinderung ebenso: verschenkter Code.

Echo

>
  'Factor: ' ?a% \
  'Until: ' ?u% \;
>> i = 1..u
  a ' * ' i ' = ' (a * i) \;
>?;

Erklärung
Der Bildschirm wird automatisch gelöscht.
">" ist der Befehl zur Ausgabe.
Ein "?" vor einer Variable bedeutet, dass sie durch Eingabe initialisiert wird.
"%" hinter einer Variable weißt auf den Datentyp "Zahl" hin und muss nur beim ersten Auftauchen der Variable angegeben werden.
"\" beginnt eine neue Zeile.
">>" ist eine Art for-Schleife, deren Zähler und Bereich angegeben wird.
Das Verketten von Strings benötigt außer ' kein zusätzliches Zeichen.
Terme müssen jedoch eingeklammert werden, wenn sie Leerstellen enthalten.
Der letzte Befehl wartet auf eine beliebige Eingabe.

Fazit
Ein recht guter Kompromiss aus Übersichtlichkeit und Kürze. Leider wenig Verwendungsmöglichkeiten, da Schlüsselwörter fehlen und es nur zwei Befehle gibt.

Extreme

Factor:_ ?a%
Until:_ ?u%
 {a _*_ i(1..u) _=_ (a * i)}

Erklärung
Hier wird der Code grundsätzlich als Ausgabe betrachtet, und es gibt keine Schlüsselwörter.
"Hallo, Welt!" in Extreme steht demzufolge bereits in Anführungszeichen am Anfang dieses Satzes.
Strings werden per Leerzeichen verknüpft, die als Ausgabe/Code-Schalter funktionieren: Jede Zeile beginnt mit einer Ausgabe. _ gibt ein echtes Leerzeichen aus.
Die Sonderzeichen ? stehen für Eingabe.
Zeilen 1 und 2:  Hier wird mit ?x% ein neuer Zahlenwert eingelesen und erzeugt.
Zeile 3: Das führende Leerzeichen markiert die nächsten Zeichen als Code.
- a wird ausgegeben.
- Ein neuer Wert i wird erzeugt und auf den Bereich "1 bis u" gesetzt. Dieser Bereich soll nun innerhalb des { Blocks } durchlaufen werden.
- Der Wert von a*i wird ausgegeben.
Der { Block } erwartet eine Bereichs-Angabe. Diese wird nur am Anfang ausgewertet und jedes Mal durch den gegenwärtigen Wert ersetzt.
Am Ende des Programms wird gewartet.
Zur Veranschaulichung haben wir die konstanten Ausgaben rot  markiert.

Fazit
Ein schrecklicher Zeichenwust. Aber: Minimallösung! Der Verzicht auf übersichtsteigernde Elemente ermöglicht einen extrem kurzen Code. Die Sprache kann sogar fast so "mächtig" sein wie Echo, wenn man die Möglichkeiten ausschöpft. Falls jemandem noch eine kürzere, sinnvolle Lösung einfällt, so möge er vortreten!