Wenn der Code-Schreiber keine Ahnung von Compiler hat, sich aber auf ihn und seine Optimierungsalgorithmen verlässt …

Es gibt Code-Schreiberlinge, die glauben tatsächlich, dass „der Compiler eh alles optimiert„.
Andere glauben sogar, dass der Compiler eine gewisse Intelligenz besitzt.
Dann gibt es noch die Code-Schreiberlinge, die glauben, dass es gut ist, wenn sie jede Methode mit einem Try-Catch-Block zu versehen. Nachdem Motto „Bringt nichts, schadet nichts“ und/oder „Doppelt hält besser„.


Schauen wir uns das ganze Mal genauer an.
Wieder mal ein Stück Code aus freie Wildbahn (Industrie):

// Listing 1 (ugly code)

void Main()
{
	Console.WriteLine(GetSomething(0));
}

public double GetSomething(int value)
{
    try
    {
        return 0;
    }
    catch(Exception ex)
    {
        return 0;
    }
}

Man stelle sich nun vor (das wird mir niemand glauben) es gäbe ein SW-System mit hundert und mehr solche Methoden wie „GetSomething(int)„.

Der folgende Code tut exakt das Gleiche, nur viel CPU und Speicher freundlicher, überschaubarer, verständlicher und einfacher zu lesen:

// Listing 2 (better code)

public const double DBL_CONST = 0.0;

void Main()
{
	Console.WriteLine(0);
}

Und nun schauen wir uns mal an, was der Compiler:

  • Optimiert, und es dann
  • in „Intermediate Language“ (IL) Befehle für CLR übersetzt, und anschließen für den echten CPU (Hardware)
  • ins Assembler übersetzt

Fangen wir mal mit Listing 1 (ugly code) an:

Von links nach rechts: C# optimiert, IL, ASM (intel x64)

Man stelle sich vor der Code oben wird in einer Schleife immer wieder aufgerufen …

Und nun schauen wir uns Listing 2 (better code) an:

Von links nach rechts: C# optimiert, IL, ASM (intel x64)

Wie man sieht, wird der CPU bei Listing 1 (ugly code) unnötig beschäftigt. Man könnte meinen, es handle sich um eine „Beschäftigungstherapie“ für den CPU: „Das es eahm jo ned langweilig wird!„.

Wegen solche Code-Schreiberlinge, benötigen wir immer stärkere CPUs, noch mehr Cores pro Sockel, und immer mehr RAM. Von der Energieverschwendung und dem CO₂ Bilanz ganz zu schweigen.

OOP Sprache == OOP Programm?

Alles (aus) Gold glänzt, aber nicht alles was glänzt ist Gold.
Alle Nüsse sind rund, aber nicht alles, was rund ist, ist eine Nuss.


Jeder kocht Zuhause. Aber deswegen ist nicht jeder ein Koch.
Jeder kann ein Auto-Motor oder -Getriebe zerlegen. Aber deswegen ist nicht jeder ein Auto-Mechaniker.
Jeder kann mit einer Lötpistole (oder einem Lötkolben) in einem Radio oder Fernseher herum löten. Aber deswegen ist nicht jeder ein Elektroniker.
Jeder kann mit einem Taschenrechner umgehen, aber deswegen ist nicht jeder ein Mathematiker.
Jeder kann beim Schachspielen drei Züge vorausdenken, aber deswegen ist nicht jeder ein Profi-Schachspieler.

Nur weil man in eine Objekt-orientierte Programmier-Sprache wie C++, Java oder C# Code schreibt, heißt es noch lange nicht, dass das Programm (der Code) Objekt orientiert ist!

Ich habe C# Code in „professioneller“ Umgebung (Industrie) gesehen und gelesen … Es war SPS/PLC Programmier-Stil in .NET/C# !
Ja, ich weiß! Ich hätte es selbst nicht geglaubt, wenn ich den Code nicht persönlich gelesen hätte (eine mind. viermonatige Tortur! Eine pure Verschwendung von teurem Arbeits- und Lebens-Zeit! Dazu noch: Augen- und Hirn-Schmerzen sowie schlaflose Nächte! Das wünsche ich niemandem!).
Ich selbst habe früher Mal, als Autodidakt, Visual Basic programmiert, ohne je von OOP, Klassen, Interfaces, Kapselung, Vererbung, Polymorphismus usw. je gehört/gelesen oder verstanden zu haben. Es hat (damals für mich) „funktioniert“. Dessen Code-Qualität war gleich 0 (null), bzw. eher am Ende der Minus-Bereich, je-nach Code-Qualitäts-Bewertungs-System.

Jede Programmier-Sprache hat seine Geschichte, geschichtliche Entwicklung, Konzepte, Paradigmen sowie „Eigenheiten“ und „Features“.

Es ist von großer Wichtigkeit die Geschichte einer Programmier-Sprache, dessen Sprach-/Programm-Elemente, Paradigmen und Konzepte zu kennen. Erst dadurch kann man sie 1.) begreifen und 2.) wissen Wann, Wo, Wie und Warum ein Programm-Element (Pre-Compiler-Symbol, Konstanten, Enumerations, Properties, Delegates, Events, usw.) oder OOP-Muster zu verwenden sei.

Jemand der C++ beherrscht kann nicht automatisch auch Java oder C# beherrschen.
Jemand der Java beherrscht kann nicht automatisch auch C# beherrschen.

Beweis durch Widerspruch:
Annahme: Wer C++ beherrscht, kann automatisch genauso Java/C# beherrschen.
Vergleiche in alle drei Sprachen werden mit dem Schlüsselwort „if“ durchgeführt.
Gegeben: if ( person != null && person.Name == "Bob" ) und die Variable person ist null.
In C++ (bis mind. C99 Standard) wird ein Fehler ausgelöst (Null Reference), weil person.Name == ... ausgeführt wird, und die Variable person ist/referenziert ja null! Man kann nicht auf Etwas das NULL ist, auf dessen Eigenschaft/Variable/Methode (in diesem Fall „Name“) zugegriffen werden.

In Java und C# hingegen geht es gut, weil beide Sprachen den sogenannte „Kurzschluss-Ausschluss-Verfahren“ beim Vergleichen anwenden (was in C++ je nach Compiler und Standard nicht gibt/gab). Das heißt, nachdem „person != null“ Falsch (false) ist, und der nächste Vergleich Konjunktiv („&&“) gebunden ist, wird der Rest („person.Name == ...„) nicht mehr ausgewertet,
da es gilt: false && True_Or_False ==> false oder binär (0 && (0 || 1) ==> 0). („==>“ steht hier für „daraus folgt“).
Daher der Name: Kurzschluss-Ausschluss-Verfahren.
Quod erat demonstrandum! (1)

Nun unterscheiden sich auch die Semantik (Bedeutung) und somit das Verhalten zwischen Java und C# auch noch:
Gegeben: person ist nicht null UND der Inhalt von person.Name ist „Bob„.

In Java: person.Name == "Bob" erzeugt einen neuen anonymen immutable String Object(eine Konstante) von Typ String mit dem Inhalt „Bob“ und vergleicht den Referenzen von person.Name mit der Referenz von anonymen immutable String Object. Das Resultat ist: false, da jedes Object auf eine andere Adresse zeigt, und somit es sich um zwei unterschiedliche Referenzen handelt.

In C# werden hingegen die Inhalte von beiden immutable String Objekten (person.Name und anonymen String Objekt, = Konstante) durch den Operator „==“ verglichen. Das Resultat ist: true, da der Wert von „person.Nameinhaltlich dem anonymen immutable String Objekt (Konstante) „Bob“ gleicht.
Kurz: Strings in Java und C# sind immutable Objects (siehe und vergleiche ECMA-334, Abschnitt 8.2.1 „Predefined types“ mit Java-String von Oracle!)
In Java müsste der Code so umgeschrieben werden damit es funktioniert:
if (person != null && person.Name.equals("Bob"))
Quod erat demonstrandum! (2)

Dazu kommt noch…

Das Kennen von Schlüsselwörter (if, else, new, while, …) sowie die Grammatik (Syntax) einer Programmiersprache reicht nicht aus um es zu „können“. Man kann dadurch den Code höchstens lesen.
Um eine Programmiersprache zu beherrschen („können“), sind daher weitere Kenntnisse unbedingt erforderlich:

  • Paradigmen und Konzepte (Heap vs. Stack, Class vs. Struct, Copy-by-Value, Copy-by-Reference, Immutable Types, OOP Design Patterns, Garbage-Collector/-Collection, Exception-Handling, Generizität, statischer vs. dynamischer Datentyp einer Variable,…)
  • Compiler (Was, Wie und Wo wird optimiert? Was wird während Compilierung und was während Runtime (Laufzeit) übersetzt, geprüft, ausgeführt?
    Z. B. findet in Java (ab Vers. 1.5 = Java 5) die Typ-Prüfung bei generische Typen erst zur Laufzeit (Runtime), weshalb der Compiler (da Java Type-Safety garantieren möchte) während Compilierung „Warning“ ausgibt.
    Bei C# jedoch findet die Typ-Prüfung bei generische Typen während Compilierung statt, und sollte Type-Safety nicht gegeben sein, gibt der C#-Compiler „Error“ aus. Siehe und Vergleiche auch Just-In-Time sowie Ahead-Of-Time Compiler!
    Zusätzlich: C# ermöglicht direkten Zugriff und Manipulation auf Speicher und dessen Inhalt (nur wenn der Code-Block mit „unsafe“ Schlüsselwort, sowie die Assembly als „Unsafe“ markiert wird), was in C++ normal/business as usual ist und Java gar nicht anbietet!
  • Frameworks
  • Events bzw. Nachrichten-Schleife
  • Parallelität