1unitedpower: PHP: Vorerst keine Union-Types.

Das sind keine aktuellen News, aber ich habe es erst jetzt durch einen Zufall erfahren. Die PHP-Entwickler haben sich gegen ein Proposal entschieden, das das Typsystem um Union-Types erweitern wollte. Kurzum handelt es sich dabei um eine Möglichkeit, neue Typen durch die Veroderung bereits bekannter Typen einzuführen. Damit dürfte auch das Schicksal des Proposals für Intersection-Types (eine Und-Verknüpfung auf Typen) besiegelt sein.

Die Proposals waren nach meiner bescheidenen Einschätzung eine erstklassige Gelegenheit sich aus dem konservativen C/Java-Lager zu verabschieden und zu modernen highlevel Sprachen aufzuschließen. Die Entscheidung überrascht mich um so mehr, da man sich damit auch von dem PHP-Ableger Hack weiter distanziert.

https://wiki.php.net/rfc/union_types

  1. ein Proposal

    ein Vorschlag

    Die Entscheidung überrascht mich um so mehr, da man sich damit auch von dem PHP-Ableger Hack weiter distanziert.

    Äh. Das kann man anders sehen: "Der Ableger distanziert sich vom Original." Das liegt so irgendwie in der Natur der Dinge.

    Ich zitiere und übersetze mal von php.net:

    PHP ist eine beliebte Allzweck-Skriptsprache, die vor allem für die Web-Entwicklung geeignet ist. Schnell, flexibel und pragmatisch

    Das ist sowas wie eine Grundsatzerklärung welche die Ziele der PHP-Entwickler vorgegibt.

    Mag sein das "hack" ("hhvm") PHP in einigen Fragen "abhängt", aber überbordende Funktionserweiterungen sind so manchem EDV-Projekt nicht gut bekommen. Schlagwort: Mozilla. Andere Sprachen habe recht heftige Veränderungen hinter sich (Python 2.x zu 3.x) die denen nicht wirklich gut bekommen sind, weil in bestehenden Skripten selbst etwas Simples und Elementares wie die Ausgabe mit der neueren Version nicht mehr funktionierte.

    PHP ist zu dem eine sehr anwendernahe Sprache, es wird offensichtlich Wert auf einfache Nutzbarkeit gelegt, was man z.B. an den "password_*"-Funktionen gut sehen kann.

    Die Entscheidung überrascht mich um so mehr,

    Andere werden gute Gründe dafür sehen, die Sprache nicht wegen eher äußerst selten genutzter Funktionen zu verkomplizieren. Ich vermute auf die entscheidende Frage "Und? Wer braucht das?" gab es keine Antwort die den erwarteten Aufwand rechtfertigte. Das muss dann ja auch noch einer pflegen und ich weiß nicht wie tief der notwendige Eingriff in bestehenden, erprobten und als sicher geltenden Code wäre vermutlich erheblich. Im Gegensatz dazu sollten sich die wenigen und eher seltenen, durch den Vorschlag lösbaren Programmier-Probleme wohl auch durch den einen oder anderen, in PHP geschriebenen "Fünfzeiler" lösen lassen.

    1. PHP ist eine beliebte Allzweck-Skriptsprache, die vor allem für die Web-Entwicklung geeignet ist. Schnell, flexibel und pragmatisch

      Das ist sowas wie eine Grundsatzerklärung welche die Ziele der PHP-Entwickler vorgegibt.

      Und ein algebraisches Typsystem passt da deiner Meinung nach nicht hinein, wieso? Mal abgesehen von dem kompliziert anmutendem Namen.

      Mag sein das "hack" ("hhvm") PHP in einigen Fragen "abhängt", aber überbordende Funktionserweiterungen sind so manchem EDV-Projekt nicht gut bekommen.

      Die Befürchtung lässt sich leicht beilegen. Das Proposal enthielt keine Abwärtsinkompatibilitäten. Es hätte also niemanden daran gehindert, der das Feature nicht nutzen wollte, von PHP 7.0 auf 7.1 zu wechseln.

      PHP ist zu dem eine sehr anwendernahe Sprache, es wird offensichtlich Wert auf einfache Nutzbarkeit gelegt, was man z.B. an den "password_*"-Funktionen gut sehen kann.

      Da passen algebraische Datentypen doch perfekt hinein. Die zusätzlichen Typannotationen hätten Code-Editoren eine neue Werkzeug-Palette ermöglicht, die beim Aufspüren von Fehlern, beim Analysieren großer Codebasen und beim Schreiben selbst reichhaltige Unterstützung garantieren.

      Andere werden gute Gründe dafür sehen, die Sprache nicht wegen eher äußerst selten genutzter Funktionen zu verkomplizieren.

      Das wird so sein, aber dass der Seltenheitswert in der Begründung eine Rolle spielt bezweifle ich. Algebraische Datentypen sind längst Mainstream: Swift, Rust, TypeScript.

      Ich vermute auf die entscheidende Frage "Und? Wer braucht das?" gab es keine Antwort die den erwarteten Aufwand rechtfertigte.

      Deine Vermutung beruht worauf?

      Das muss dann ja auch noch einer pflegen und ich weiß nicht wie tief der notwendige Eingriff in bestehenden, erprobten und als sicher geltenden Code wäre vermutlich erheblich.

      Diese Fragen muss man für jedes neue Feature beantworten. Im Falle dieses Proposals wäre der Aufwand angemessen gewesen, ein Pull-Request lag ihm bereits bei.

      Im Gegensatz dazu sollten sich die wenigen und eher seltenen, durch den Vorschlag lösbaren Programmier-Probleme wohl auch durch den einen oder anderen, in PHP geschriebenen "Fünfzeiler" lösen lassen.

      Das Proposal hätte neue statische Typchecks ermöglicht. Dadurch hätten eine ganze Menge mehr Programmierfehler bereits zur Entwicklungszeit ausgeschlossen werden können. Die Werkzeuge, die ich oben bereits erwähnt habe, können auch nicht einfach substituiert werden.

      1. Ich vermute auf die entscheidende Frage "Und? Wer braucht das?" gab es keine Antwort die den erwarteten Aufwand rechtfertigte.

        Deine Vermutung beruht worauf?

        Auf der Vermutung, dass an der PHP-Entwicklung viele PHP-Nutzer beteiligt sind. Freilich kenne ich den Entscheidungsprozess nicht.

      2. PHP ist traditionell eine deklarationsarme Sprache, in PHP 5 kamen die Type-Hints und in 7 die MÖGLICHKEIT zur Typdeklaration mit strikter Prüfung hinzu. Algebraische Typen sind für die Maintainer von PHP vermutlich noch weit weg. Ob die strikten Typen, die PHP 7 kennt, den Compiler dazu bewegen, weniger Laufzeitprüfungen auf korrekte Wertetypen durchzuführen, wäre auch erstmal zu betrachten. Jedenfalls nicht mit dem Standard PHP-to-OpCode Compiler auf eine ZEND Engine. Hack mit HHVM hat einen JIT, der strikte Typisierung besser ausnutzen kann. Ich weiß nicht womit ZEND Geld verdient und ob es ihnen gut geht, aber eine JIT-fähige Engine, die auch noch multiplatform funktioniert, ist aufwändig.

        Andererseits, wenn ich mir den Proposal anschaue, ist der vorgeschlagene Anwendungszweck zumindest teilweise schrecklich. Es gibt Funktionen, die geben ein Objekt zurück oder FALSE im Fall eines Errors. Das können sie nur, weil Variablen in PHP prinzipiell ungetypt sind. Es kennt zwar Wertetypen, aber Variablen können erstmal alles speichern. Eine Funktion, die je nach Ergebnis einen anderen Wertetyp liefert, ist aus meiner Sicht der komplette Horror. Dazu noch mit der automatischen truthy/falsy Interpretation von non-boolean Werten, und dem Zwang, zwischen der Rückgabe eines falsy-Wertes und echtem FALSE unterscheiden zu müssen. Solche Funktionen gehören auf den Misthaufen der Geschichte, und sie gehören nicht dadurch konserviert, dass man ihre Rückgaben mittels Union-Typisierung veredelt. Ein Rückgabetyp "int | false" ist meiner Meinung nach ein Designfehler. Eine Typisierung "ClassXYZ | null" ist auch nicht viel besser. Was fehlt, ist ein klarer Mechanismus zur Rückgabe von zwei Werten, und der Möglichkeit, das auch deklarieren zu können.

        ($result, $success) = function($blah);
        

        Etwas ähnliches kann ich PHP zwar bauen:

        list($result, $success) = function($blah);
        

        und ich gebe ARRAY(1, true) aus der Funktion zurück, aber es ist eben handgemacht und vom Compiler nicht überprüfbar. Wenn ich schreiben könnte:

        function blah(int $fasel) : (ClassXYZ, boolean) 
        {
           return (new ClassXYZ($fasel), true);
        }
        

        das wär mal was. Aber sowas geht nicht und es gibt nicht mal einen RfC dafür. Oder übersehe ich etwas, außer Referenz-Parametern als Ersatz für out-Parameter?

        Das, was algebraische Typen sein KÖNNEN - soweit ich das aus dem englischen Wikipedia-Artikel herauslese - ist etwas ganz anderes. Ob das für PHP machbar ist, ohne Compiler und Runtime komplett neu zu schreiben, wäre erstmal zu überlegen. Von daher: 100% dafür, die Idee in dieser Formulierung abzulehnen.

        Gruß
        Rolf

        1. PHP ist traditionell eine deklarationsarme Sprache, in PHP 5 kamen die Type-Hints und in 7 die MÖGLICHKEIT zur Typdeklaration mit strikter Prüfung hinzu.

          Außerdem kamen in PHP 7 Typehints für primitive Datentypen, und nullable und iterable Types, wie Sven schon sagte. Man hat schon viel für die Typechecking-Community getan - das ist auch PHP-Tradition.

          Ob die strikten Typen, die PHP 7 kennt, den Compiler dazu bewegen, weniger Laufzeitprüfungen auf korrekte Wertetypen durchzuführen, wäre auch erstmal zu betrachten.

          Das wäre für mich nur nebensächlich. Ich mag Typsysteme für die Hilfestellungen, die sie dem Programmierer bieten. Aber wenn dabei Performance-Boosts abspringen, ist das natürlich nett.

          Andererseits, wenn ich mir den Proposal anschaue, ist der vorgeschlagene Anwendungszweck zumindest teilweise schrecklich. Es gibt Funktionen, die geben ein Objekt zurück oder FALSE im Fall eines Errors. Das können sie nur, weil Variablen in PHP prinzipiell ungetypt sind.

          Ich stimme dir was die Beispiele angeht voll und ganz zu. Dein letzter Satz ist aber ein Fehlschluss. PHP ist typsicher, und deswegen hat jede Variable zur Laufzeit immer auch einen assoziierten Typen - das ist einfach der Typ des Wertes, den die Variable angenommen hat. Man kann diese Typen nicht selber für Variablen festlegen, aber man kann sie mittels Typinferenz herausfinden und mit einem Typchecker gewisse Invarianten für sie überprüfen. Mit Union-Types könnte man schließlich noch mehr Invarianten testen.

          Es kennt zwar Wertetypen, aber Variablen können erstmal alles speichern. Eine Funktion, die je nach Ergebnis einen anderen Wertetyp liefert, ist aus meiner Sicht der komplette Horror.

          Die Alternative ist oft noch viel schlimmer. Ich möchte mal selber ein Beispiel bringen, das für mich sehr gut funktioniert.

          function divide (int $a, int $b) : float {
             return $a / $b;
          }
          

          Die Funktion teilt zwei Zahlen. Die Division durch 0 stellt eine Ausnahmefall da, den es nun zu behandeln gilt. Im obigen Code würde PHP Laufzeit-Fehler produzieren, wenn die Funktion aufgerufen wird. Das hat zur Folge, dass der Anwender der Funktion den Fehler abfangen muss. Das Üble dabei ist, dass die Funktions-Signatur das nicht ausdrückt, und ein Editor den Anwender auch nicht durch statische Codeanalyse darauf hinweise kann. Man überträgt dem Anwender der Funktion also auch gleich die Verantwortung Fehlerfälle zu behandeln.

          Es wäre schöner, könnte man den Fehler schon innerhalb der Funktion bearbeiten. Dann stellt sich aber die Frage, was man nun im Fehlerfall zurück geben kann und da sind durch den Rückgabetypen float Grenzen gesetzt. Einfach eine willkürliche Zahl zurückgeben kann nicht die Lösung sein:

          function divide (int $a, int $b) : float {
             if ($b === 0) {
                return 42; // Meh
             } else {
                return $a / $b;
             }
          }
          

          Die häufig auftretende Vorgehensweise in PHP ist, den Rückgabetypen der Funktion unspezifiziert zu lassen und bei Fehlschlag der Operation false zurück zu geben.

          function divide (int $a, int $b) {
             if ($b === 0) {
                return false; // Meh
             } else {
                return $a / $b;
             }
          }
          

          Dann muss der Anwender der Funktion trotzdem noch überall zwei Fälle behandeln und die Editor-Unterstützung fehlt weiterhin für den Fehlerfall und nun auch noch für den positiven Fall. Mit Union-Types könnte man erzwingen, dass immer alle Fälle bei der Weiterverarbeitung abgedeckt sind. Und der Editor könnte beim Tippen der Funktion dem Anwender sofort eine Liste mit allen Fällen anbieten.

          function divide (int $a, int $b) : float | bool {
             if ($b === 0) {
                return false;
             } else {
                return $a / $b;
             }
          }
          

          Das löst die Probleme. Das ließe sich noch schöner modellieren, wenn man auch komplexe Typen für Union-Types verwenden könnte.

          function divide (int $a, int $b) : Success | Fail {
             if ($b === 0) {
                return new Fail('Division by zero');
             } else {
                return new Success($a / $b);
             }
          }
          

          Wie Sven richtig herausgestellt hat, wäre letzteres auch nicht mit der Akzeptanz des RFCs möglich geworden. Hier teile ich Svens Kritik.

          Dazu noch mit der automatischen truthy/falsy Interpretation von non-boolean Werten, und dem Zwang, zwischen der Rückgabe eines falsy-Wertes und echtem FALSE unterscheiden zu müssen.

          Typecoercing ist ein anderes Thema.

          Solche Funktionen gehören auf den Misthaufen der Geschichte, und sie gehören nicht dadurch konserviert, dass man ihre Rückgaben mittels Union-Typisierung veredelt.

          Gehen wir mal von der Hypothese aus, dass solche Funktionen, wie meine divide-Funktion dort oben, mit Union-Types in PHP möglich wären. Welche Gefahr siehst du von ihnen ausgehen? Und wie würdest du die divide-Methode heute ohne Union-Types modellieren?

          Ein Rückgabetyp "int | false" ist meiner Meinung nach ein Designfehler. Eine Typisierung "ClassXYZ | null" ist auch nicht viel besser. Was fehlt, ist ein klarer Mechanismus zur Rückgabe von zwei Werten, und der Möglichkeit, das auch deklarieren zu können. Aber sowas geht nicht und es gibt nicht mal einen RfC dafür. Oder übersehe ich etwas, außer Referenz-Parametern als Ersatz für out-Parameter?

          Du verlangst zwei Dinge: Tupel-Typen und Destructuring für Tupel-Typen. Für beides hast du mein Votum.

          Das, was algebraische Typen sein KÖNNEN - soweit ich das aus dem englischen Wikipedia-Artikel herauslese - ist etwas ganz anderes.

          Die Beispiele im Artikel sind alle in Haskell, das lässt es sehr unterschiedlich erscheinen. Konzeptionell geht es aber um das selbe. Die Beispiele lassen sich relativ simple in PHP übersetzen:

          data List a = Nil | Cons a (List a)
          
          class Nil {}
          class Cons {
             protected $head;
             protected $tail; 
             public function __construct($value, Nil | Cons $tail) {
                $this->head = $value;
                $this->tail = $tail;
             }
          }
          
          data Tree = Empty
                    | Leaf Int
                    | Node Tree Tree
          
          class Empty {}
          class Leaf {
              protected $value;
              public function __construct(int $value) {
                  $this->value = $value;
              }
          }
          class Node {
              protected $left;
              protected $right;
              public function __construct(Empty | Node | Leaf $left, Empty | Node | Leaf $right) {
                  $this->left = $left;
                  $this->right = $right;
              }
          }
          

          Mit generics, die ebenfalls proposed sind, könnte man auch den parametrischen Polymorphmus von Haskell in der PHP-Übersetzung unterbringen.

          Ob das für PHP machbar ist, ohne Compiler und Runtime komplett neu zu schreiben, wäre erstmal zu überlegen. Von daher: 100% dafür, die Idee in dieser Formulierung abzulehnen.

          Ein Pull-Request hat dem RFC beigelegen.

          1. Hi,

            function divide (int $a, int $b) : float {
               if ($b === 0) {
                  return 42; // Meh
               } else {
                  return $a / $b;
               }
            }
            

            Nur mal so als Hinweis: das else ist überflüssig:

            function divide (int $a, int $b) : float {
               if ($b === 0) {
                  return 42; // Meh
               } 
               return $a / $b;
            }
            

            cu,
            Andreas a/k/a MudGuard

            1. Hallo MudGuard,

              Nur mal so als Hinweis: das else ist überflüssig:

              Ja. Macht es aber lesbarer. Und ich meine es gab auch Interpreter (alte Turbopascals iirc), die sowas angemeckert haben, weil der Rückgabewert nicht eindeutig ist.

              https://wiki.selfhtml.org/wiki/Glossar:Syntaktischer_Zucker

              Bis demnächst
              Matthias

              --
              Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
              1. Hi,

                Ja. Macht es aber lesbarer.

                Ansichtssache.

                Und ich meine es gab auch Interpreter (alte Turbopascals iirc), die sowas angemeckert haben, weil der Rückgabewert nicht eindeutig ist.

                Dann wäre der Interpreter fehlerhaft, denn der Rückgabewert ist ja eindeutig. Das zweite return bleibt ja. Nur das else {} soll ja weg.

                cu,
                Andreas a/k/a MudGuard

                1. Scheint, als ob die PHP Doku inkonsistent ist. Unter "Type Hinting" im OOP Bereich findet man noch, dass skalare Hints nicht möglich seine. Unter "Type Declarations" bei den Funktionsargumenten steht, dass es geht.

                  Wenn schon, dann doch bitte so:

                  function error_free_divide(int $a, int $b) : float|bool {
                     return $b === 0 ? false : $a / $b;
                  }
                  

                  Aber hier ist wieder mal ein typischer PHP Fall aus der Mottenkiste: Weil es vor PHP 5.1 keine Exceptions gab, hat man sich behelfen müssen und diese Typensuppe gekocht. KORREKT im Sinne von sauberer Programmierung wäre im Falle unserer Divide-Funktion eine Exception gewesen. Die SPL bietet ein paar an, wie InvalidArgument, Overflow oder UnexpectedValue, auch wenn die nicht richtig passen. Eine DivideByZeroException wäre korrekt. Aber scheinbar sieht der ZEND Coding Standard das ja anders.

                  Im Falle der MYSQLI-Funktionen wie mysqli::query, die ein Objekt oder false zurückgeben, hätte man eine SqlException definieren müssen. Das bricht nur allen alten Code, deshalb tut man es nicht. Aus Sicht eines sauberen Designs ist ein mixed Returntype trotzdem Unfug.

                  Wenn es wie in Haskell geschieht und ich einen Union-Typ nutze, um z.B. bei einem Baum einen Knoten oder ein Blatt zurückzugeben (was in C++, C# oder Java ein ITreeNode Interfacetyp wäre), ist das was ganz anderes.

                  BTW:

                  (...) weil Variablen in PHP prinzipiell ungetypt sind. <1unitedpower> (Das) ist aber ein Fehlschluss.

                  Nein. Du verwechselst nur Variablentyp mit Wertetyp. Ich kann in einer PHP Variable jeden Wert speichern. Natürlich hat der WERT dann einen Typ. Aber die Variable ist nicht auf einen Typ beschränkt. D.h. die ZEND Engine muss zur Laufzeit prüfen, welcher Typ nun wirklich vorliegt. Auch Type Declarations einer Funktion oder Methode können erst zur Laufzeit geprüft werden. Eigentümlich finde ich, dass auf der RfC Seite von PHP kein Mensch daran denkt, getypte Variablen einzuführen.

                  Rolf

                  1. Scheint, als ob die PHP Doku inkonsistent ist. Unter "Type Hinting" im OOP Bereich findet man noch, dass skalare Hints nicht möglich seine. Unter "Type Declarations" bei den Funktionsargumenten steht, dass es geht.

                    Ja sieht so aus. Die englische Dokumentation verweist an der Stelle "Type Hinting" indes auf "Type Declarations".

                    Wenn schon, dann doch bitte so:

                    function error_free_divide(int $a, int $b) : float|bool {
                       return $b === 0 ? false : $a / $b;
                    }
                    

                    Aber hier ist wieder mal ein typischer PHP Fall aus der Mottenkiste: Weil es vor PHP 5.1 keine Exceptions gab, hat man sich behelfen müssen und diese Typensuppe gekocht. KORREKT im Sinne von sauberer Programmierung wäre im Falle unserer Divide-Funktion eine Exception gewesen. Die SPL bietet ein paar an, wie InvalidArgument, Overflow oder UnexpectedValue, auch wenn die nicht richtig passen. Eine DivideByZeroException wäre korrekt. Aber scheinbar sieht der ZEND Coding Standard das ja anders.

                    Wieso wären Exceptions sauberer? Exceptions werden zur Laufzeit geworfen, typannotierte Ausdrücke können mit statischer Programmanalyse zur Entwicklungszeit auf Typfehler überprüft werden. Das hat ein paar Voteile:

                    • Das Programm ist zuverlässiger. Eine Exception die nicht behandelt wird, kann zum Programmabsturz führen. Ein falsch getyptes Programm wird vom Typchecker zurückgewiesen.
                    • Statische Programmanalyse ermöglicht einen nennenswerten Anteil an Programmierhilfen in Editoren.
                    • Library-Autoren können die Fehelbehandlung selbst vornehmen und müssen diese Verantwortung nicht dem Anwender übtertragen. Siehe mein Beispiel.
                    • Typen sind auch eine Form der Dokumentation. Sie sollten freilich nicht die einzige Art der Dokumentation sein.
                    • Man erhält potenzielle Performance-Boosts durch Einsparung von Laufzeit-Checks. Ob dieses Potenzial ausgeschöpft wird ist eine andere Frage, es eröffnet auf jeden Fall die Möglichkeit für neue Optimierungen.

                    Wenn es wie in Haskell geschieht und ich einen Union-Typ nutze, um z.B. bei einem Baum einen Knoten oder ein Blatt zurückzugeben (was in C++, C# oder Java ein ITreeNode Interfacetyp wäre), ist das was ganz anderes.

                    Inwiefern anders?

                    (...) weil Variablen in PHP prinzipiell ungetypt sind. <1unitedpower> (Das) ist aber ein Fehlschluss.

                    Nein. Du verwechselst nur Variablentyp mit Wertetyp. Ich kann in einer PHP Variable jeden Wert speichern.

                    Nein tue ich nicht. Unter einem Variablentypen verstehst du offenbar den durch eine Typannotation festgelegten Typ einer Variablen. Unter Wertetyp verstehst du den ermittelten Typen eines Wertes. Den ermittelten Typen eines Wertes mit der Typannotation auf Kompatibilität zu überprüfen ist Aufgabe eines Typcheckers.

                    Und gerade hier liegt der Mehrwert von Union-Types: Sie ermöglichen neue Typannotationen und dadurch mehr statische Typchecks. Keine Notwendigkeit für Exceptions.

                    Natürlich hat der WERT dann einen Typ. Aber die Variable ist nicht auf einen Typ beschränkt.

                    Das ist nur die halbe Wahrheit. Für Parameter lassen sich Typannotationen angeben, für andere Variablen-Deklarationen aber nicht.

                    1. Tach!

                      Wieso wären Exceptions sauberer? Exceptions werden zur Laufzeit geworfen, typannotierte Ausdrücke können mit statischer Programmanalyse zur Entwicklungszeit auf Typfehler überprüft werden.

                      Das ist so ungefähr das einzige Feature in Java, das ich anderswo vermisse. Wenn man eine Exception aus seiner Funktion/Methode sozusagen rauswerfen möchte, muss man das deklarieren. Und der aufrufende Code muss sie fangen oder ebenfalls weiterdeklarieren. Dabei kann auch bereits der Compiler potentiell ungefangene Exceptions monieren.

                      dedlfix.

                    2. Dito @ dedlfichs, das sehe ich auch als eine der besseren Ideen von Java und würde mich in C# oder PHP drüber freuen.

                      1unitedpower, komm mir nicht mit den Vorteilen von statischen Typchecks, oder ich gebe Dir augenblicklich recht. Die Union Types sind vielleicht auch Geschmacks- oder Gewöhnungssache. Ich kenne sie nicht und tue mich vielleicht deshalb schwer damit.

                      Die Beispiele mit mixed-Ergebnissen sind alle darauf ausgelegt, das Ergebnis von Fehlerabfragen in der Funktion nach außen zu reichen. Die Frage ist nur, was der Aufrufer dann damit macht. Im Falle unserer Division durch 0 liegt ein Algorithmusfehler vor. Im Falle von z.B. mysqli::query bedeutet FALSE "Failure", ohne dass die Doku spezifziert, was damit gemeint ist. Es könnte eine abgebrochene DB-Verbindung sein, ein SQL Syntaxfehler, oder wer weiß was. Würde eine SqlException oder eine NetworkException geworfen, könnte ich das das entsprechend catchen und behandeln. Und im NORMALFALL kommen diese Situationen nicht vor, warum soll ich also den Code für meine DB-Abfrage durch ständiges Abfragen von Fehlerergebnissen bloaten. Out-of-line im Catch-Block sind sie viel besser aufgehoben.

                      Anders ist es, wenn ein Fehler "normal" sein kann, z.B. ein nicht gefundener Treffer in einer Suche. Dafür ist eine Exception falsch und es ist Tradition, spezielle Ergebniswerte zurückzugeben. Das ist sicher nicht der Weisheit letzter Schluss und ein Union Type könnte es besser handhabbar machen. Man kann es nur nicht durchgängig einführen, oder müsste alle APIs, die Sonderwerte nutzen, deprecaten und Alternativ-APIs mit Union Type API einführen. Möglicherweise hat man den Aufwand gescheut, die Union Types nach Einführung als Sprachelement dann auch in die Breite zu bringen.

                      Ich möchte mich jetzt aus der Diskussion zurückziehen, es kostet mich zu viel Zeit und ich glaube auch nicht, dass wir auf einen Nenner kommen. Unsere Meinungen haben wir dargelegt :)

                      Gruß
                      Rolf

              2. Hallo Matthias,

                Nur mal so als Hinweis: das else ist überflüssig:

                Ja. Macht es aber lesbarer.

                Im Gegenteil. Early exit ist ein gängiges Konzept, und man erkennt es direkt beim scannen des Codes. Das else dagegen erzeugt einen kognitiven Overhead.

                Und ich meine es gab auch Interpreter (alte Turbopascals iirc), die sowas angemeckert haben, weil der Rückgabewert nicht eindeutig ist.

                Umgekehrt. Ein hinter if ... else verstecktes return hat bei alten Compilern zu einer warning geführt, weil die Code-Analyse noch nicht so weit war zu verstehen, dass hier immer ein Rückgabewert vorliegt.

                LG,
                CK

                1. Tach!

                  Nur mal so als Hinweis: das else ist überflüssig:

                  Ja. Macht es aber lesbarer.

                  Im Gegenteil. Early exit ist ein gängiges Konzept, und man erkennt es direkt beim scannen des Codes. Das else dagegen erzeugt einen kognitiven Overhead.

                  Es gibt Hilfssysteme in großen IDEs, die schlagen sogar noch eine Menge mehr Umarbeitungen vor, als man eigentlich sonst tun würde. Zum Beispiel wenn ein if-Block am Ende einer Funktion steht, wird eine Negation der Bedingung zusammen mit einem return vorgeschlagen. Dadurch kann der sonst eigentlich im Block stehende Code mit einer Verschachtlungstiefe weniger geschrieben werden. Das ergibt als Nebenwirkung weniger Platzbedarf nach rechts und weniger Umbrüche an der magischen 80er (oder bei mir mittlerweile 120er) Zeichengrenze.

                  dedlfix.

  2. Moin!

    Das sind keine aktuellen News, aber ich habe es erst jetzt durch einen Zufall erfahren. Die PHP-Entwickler haben sich gegen ein Proposal entschieden, das das Typsystem um Union-Types erweitern wollte. Kurzum handelt es sich dabei um eine Möglichkeit, neue Typen durch die Veroderung bereits bekannter Typen einzuführen. Damit dürfte auch das Schicksal des Proposals für Intersection-Types (eine Und-Verknüpfung auf Typen) besiegelt sein.

    Sicherlich nicht. Proposals scheitern oder sind erfolgreich je nachdem, wie gut sie vorbereitet sind und natürlich auch, inwieweit sie Weitsicht in Bezug auf mögliche Seiteneffekte zeigen.

    Dieses Proposal hat sich vor allem in den Beispielen NUR mit der Möglichkeit von Skalartypen beschäftigt, also mit einer Konkretisierung von "mixed".

    Was ist mit Klassen? Könnte ich als Parameter einer Funktion vielleicht eine von zwei unterschiedlichen Klassen hineingeben? Wie sollte sowas praktisch funktionieren? Und was sagt das über die Codebasis aus? Denn normalerweise wäre in solchen Fällen ein Interface oder eine abstrakte Basisklasse angesagt.

    Die Proposals waren nach meiner bescheidenen Einschätzung eine erstklassige Gelegenheit sich aus dem konservativen C/Java-Lager zu verabschieden und zu modernen highlevel Sprachen aufzuschließen. Die Entscheidung überrascht mich um so mehr, da man sich damit auch von dem PHP-Ableger Hack weiter distanziert.

    Es gibt das Proposal für Nullable Types: https://wiki.php.net/rfc/nullable_types - erfolgreich angenommen.
    Außerdem gibts das Proposal für Iterable: https://wiki.php.net/rfc/iterable - ebenfalls erfolgreich angenommen.

    Somit sind zwei Vorschläge mit sehr konkretem Scope in der Implementierung für PHP 7.1, die sich mit den real auftretenden Einschränkungen der bisherigen Sprache beschäftigen:

    1. Das Problem der Übergabe oder Rückgabe von "nichts" war bislang für die Übergabe nur mit einem Default-Wert "null" zu lösen, für die Rückgabe gar nicht.
    2. Das Problem der Übergabe von nativen Arrays oder alternativ Traversable-implementierenden Objekten war bislang nur komplett ohne Typehint lösbar und hat entsprechende Fehlerbehandlung im Code erforderlich gemacht.

    Grüße Sven

    1. Sicherlich nicht. Proposals scheitern oder sind erfolgreich je nachdem, wie gut sie vorbereitet sind und natürlich auch, inwieweit sie Weitsicht in Bezug auf mögliche Seiteneffekte zeigen.

      Ich hoffe du behälst recht.

      Dieses Proposal hat sich vor allem in den Beispielen NUR mit der Möglichkeit von Skalartypen beschäftigt, also mit einer Konkretisierung von "mixed".

      Was ist mit Klassen? Könnte ich als Parameter einer Funktion vielleicht eine von zwei unterschiedlichen Klassen hineingeben? Wie sollte sowas praktisch funktionieren?

      Ich habe mir den RFC nochmal durchgelesen, zwar spricht dort niemand ausdrücklich über Union-Types von Klassen, aber es wird auch keine Ausnahme für sie geregelt. In den Beispielen tauchen solche Typannotationen auf.

      Und was sagt das über die Codebasis aus? Denn normalerweise wäre in solchen Fällen ein Interface oder eine abstrakte Basisklasse angesagt.

      Das ist eine Modellierungsentscheidung, natürlich wären Union-Types keine Substitution für andere Typfeatures.

      Die Proposals waren nach meiner bescheidenen Einschätzung eine erstklassige Gelegenheit sich aus dem konservativen C/Java-Lager zu verabschieden und zu modernen highlevel Sprachen aufzuschließen. Die Entscheidung überrascht mich um so mehr, da man sich damit auch von dem PHP-Ableger Hack weiter distanziert.

      Es gibt das Proposal für Nullable Types: https://wiki.php.net/rfc/nullable_types - erfolgreich angenommen.
      Außerdem gibts das Proposal für Iterable: https://wiki.php.net/rfc/iterable - ebenfalls erfolgreich angenommen.

      :) Und das Votum für generics steht auch noch aus: https://wiki.php.net/rfc/generics

      PS: PHPDoc hat Unterstützng für Union-Types, das tröstet mich gerade. https://www.phpdoc.org/docs/latest/guides/types.html