switch case für einen string


  • Mod

    @hustbaer sagte in switch case für einen string:

    @5cript sagte in switch case für einen string:

    Also, wem zwingen wir jetzt auf das Proposal zu schreiben mit allem drum und dran? 😛

    Ich kann leider gar niemanden zwingen irgendwas zu tun. Aber ich kann ja mal @Columbo hier taggen. Im sehr unwahrscheinlichen Fall dass es ihn ausreichend interessiert und er genug Zeit übrig hat... ich würde ihm auf jeden Fall zutrauen das hinzubekommen.

    https://cplusplus.github.io/EWG/ewg-active.html#71

    Ich denke, die Idee ist sinnvoll. Ich schreib mal den Autor an.



  • @wob sagte in switch case für einen string:

    Hashtable scheint sich doch nur zu lohnen, wenn man richtig viele verschiedene Werte hat - die Hash-Berechnung ist ja schließlich nicht kostenlos und ein == ist häufig recht billig.

    I see your point.

    Für die Performance wäre es vermutlich gut wenn nicht std::hash verwendet würde sondern irgendwas billigeres. Für Strings kannst du z.B. einfach die Länge oder sowas wie size() ^ back() << 16 nehmen. Das ist ausreichend billig zu berechnen und sollte schon einiges bringen. D.h. man bräuchte eine eigenen switch_hash Funktion oder sowas in der Art.

    Und vermutlich wäre es auch gut wenn diese spezielle Switch-Hash Funktion optional wäre, ohne Fallback. D.h. wenn es keine gibt, dann muss der Compiler halt linear-scan machen.

    Man könnte auch überlegen zusätzlich eine switch_id Funktion zu erlauben, mit der Semantik dass switch (x) { case X1: ... gleichbedeutend ist mit switch (switch_id(x)) { case switch_id(X1): .... Das wäre gut für kleine Klassen die komplett & verlustfrei in einen Integer serialisiert werden können. z.B. so Zeugs wie std::chrono::duration.



  • Ich wusste gar nicht, dass das fehlende String-Switch so ein häufiges Problem ist. Ist das wirklich so?
    Vielleicht bin ich nur einfach in der falschen Branche tätig.


  • Mod

    Es waere nicht verkehrt, es als Feature der Sprache zu unterstuetzen. Die Tatsache, dass es noch nicht aufgenommen wurde, bezeugt ja, dass die Nachfrage nicht so riesig ist. Aber ich sehe schon viele Faelle in unserer code base wo wir einen String auf mehrere fixe Werte hin pruefen.



  • @Columbo sagte in switch case für einen string:

    Es waere nicht verkehrt, es als Feature der Sprache zu unterstuetzen. Die Tatsache, dass es noch nicht aufgenommen wurde, bezeugt ja, dass die Nachfrage nicht so riesig ist. Aber ich sehe schon viele Faelle in unserer code base wo wir einen String auf mehrere fixe Werte hin pruefen.

    Sind das dann auch Fälle, wo das wirklich unbedingt nötig ist? Also bei mir ist das Hauptsächlich bei der Auswertung von Konfigurationsdateien der Fall, aber ab da wird im Grunde alles mit enums oder anderweitig behandelt.


  • Mod

    Stringvergleiche sind halt typischerweise Fälle, wo die Werte weder hardcoded sein sollten, noch wo man die Zusatzperformance eines low-level Jumptables bräuchte. Die primäre Semantik von string ist "Zeichenkette mit menschenverständlichem Inhalt", nicht "Sprunglabel". Die primäre Semantik von switch ist "Hochsprachliche Umsetzung dieses speziellen Assemblerkonstrukts, das super-wichtig war, als C neu war", nicht "Mapping von Werten zu Aktionen". Für letzteres ist halt die map das primäre Konstrukt, die auch ganz natürlich mit dynamischen Strings zurecht kommt. Von daher wundert mich nicht, dass das wenig Priorität für die Sprache hat.

    Gewiss wäre der Großteil der Fälle, wo Leute das anwenden möchten, eher Anti-Patterns, die Nutzereingaben mit Codeinterna verknüpfen möchten. Von dem Beispiel hier sehen wir nur sehr wenig, aber allein schon die zwei Zeilen mit dem "male" und "female" riecht danach, als ob hier Business Policy fest in Code gegossen werden soll, was generell eine schlechte Idee ist.



  • Patter matching würde das Problem mit erschlagen.



  • @It0101 sagte in switch case für einen string:

    Ich wusste gar nicht, dass das fehlende String-Switch so ein häufiges Problem ist. Ist das wirklich so?
    Vielleicht bin ich nur einfach in der falschen Branche tätig.

    Ich finde schon, nicht ständigt aber hin und wieder mal. Und ich finde es ist schneller und simpler sichtbar was passiert im Vergleich zu zum Beispiel einer erstellten Datenstruktur wie unordered_map.

    @manni66 sagte in switch case für einen string:

    Patter matching würde das Problem mit erschlagen.

    Interessantes Proposal, die Syntax und das Feature sieht sehr mächtig aus, was mir die Sorge macht dass es sich eher schwerfällig durch den Review Prozess bewegen wird.
    Ich kann mir auch nicht vorstellen, dass die Working Group nicht nochmal über die Syntax diskutiert etc.



  • @SeppJ sagte in switch case für einen string:

    Stringvergleiche sind halt typischerweise Fälle, wo die Werte weder hardcoded sein sollten, noch wo man die Zusatzperformance eines low-level Jumptables bräuchte. Die primäre Semantik von string ist "Zeichenkette mit menschenverständlichem Inhalt", nicht "Sprunglabel". Die primäre Semantik von switch ist "Hochsprachliche Umsetzung dieses speziellen Assemblerkonstrukts, das super-wichtig war, als C neu war", nicht "Mapping von Werten zu Aktionen". Für letzteres ist halt die map das primäre Konstrukt, die auch ganz natürlich mit dynamischen Strings zurecht kommt. Von daher wundert mich nicht, dass das wenig Priorität für die Sprache hat.

    Gewiss wäre der Großteil der Fälle, wo Leute das anwenden möchten, eher Anti-Patterns, die Nutzereingaben mit Codeinterna verknüpfen möchten. Von dem Beispiel hier sehen wir nur sehr wenig, aber allein schon die zwei Zeilen mit dem "male" und "female" riecht danach, als ob hier Business Policy fest in Code gegossen werden soll, was generell eine schlechte Idee ist.

    Amen Bruder! 😀



  • Oder man nimmt Pointer auf Strings. Müssen dann halt auch exakt die selben Pointer sein und nicht unterschiedliche Pointer auf gleiche Strings. Aber wofür gibts String Pooling. 😉



  • @SeppJ sagte in switch case für einen string:

    Stringvergleiche sind halt typischerweise Fälle, wo die Werte weder hardcoded sein sollten, noch wo man die Zusatzperformance eines low-level Jumptables bräuchte.

    Typischerweise vielleicht. Gibt aber auch Leute die Parser schreiben.
    (Und ich glaube in dem Satz fehlt ein "weder". EDIT: Sorry, Brainfart, steht eh da, bloss nicht da wo ich es erwartet hatte.)

    Die primäre Semantik von string ist "Zeichenkette mit menschenverständlichem Inhalt"

    Gewagte Aussage. Davon abgesehen: human_readable impliziert nicht !machine_readable.

    , nicht "Sprunglabel".

    False dichotomy.

    Die primäre Semantik von switch ist "Hochsprachliche Umsetzung dieses speziellen Assemblerkonstrukts, das super-wichtig war, als C neu war", nicht "Mapping von Werten zu Aktionen".

    Ebenso gewagte Aussage. Denn die Semantik von switch ist ganz exakt "Mapping von Werten zu Aktionen". Weil das genau das ist was switch macht. Was willst du sonst nehmen? if-Kaskaden? map<ValueType, std::function<...>>? Bitte nicht.

    Für letzteres ist halt die map das primäre Konstrukt, die auch ganz natürlich mit dynamischen Strings zurecht kommt.

    map soll das primäre Konstrukt sein um Werten auf Aktionen abzubilden? Was soll der Vorteil gegenüber switch sein? Dass man einen Haufen Boilerplatecode schreiben muss? Dass Callstacks unübersichtlicher werden?



  • Außer für enum wüsste ich auch keinen sinnvollen Anwendungsfall für switch...case. Alles andere sehe ich als "Magic Numbers" (bzw. "Magic Literals").
    Es ist für mich eindeutig ein "Code Smell" Funktionen mit langen switch...case-Blöcken zu haben - daher präferiere ich dann auch lieber, wie @SeppJ, Mapping-Datentypen.

    Es widerspricht ja auch gängigen OOP-Prinzipien.

    Ich habe mal ein größeres Projekt (mit ein Dutzend Entwicklern) gesehen, da wurden Debug-Konsolenausgaben in einer Datei (weil nur dort Zugriff auf die "virtuelle" Konsole innerhalb einer 3D-Anwendung war) mithilfe einen großes switch...case-Blocks mit mehreren Hundert Zeilen abgehandelt)...


  • Mod

    @hustbaer sagte in switch case für einen string:

    @SeppJ sagte in switch case für einen string:

    Stringvergleiche sind halt typischerweise Fälle, wo die Werte weder hardcoded sein sollten, noch wo man die Zusatzperformance eines low-level Jumptables bräuchte.

    Typischerweise vielleicht. Gibt aber auch Leute die Parser schreiben.

    Und dann hardcodest du die Sprache überall?

    map soll das primäre Konstrukt sein um Werten auf Aktionen abzubilden? Was soll der Vorteil gegenüber switch sein?

    Offenheit.

    Der Rest ist beinahe beleidigend, wo du anderen vermeintlich(!) schlechte Diskussionsweise unterstellst, und dann selber mit komischen Pseudoargumenten kommst.



  • @SeppJ sagte in switch case für einen string:

    @hustbaer sagte in switch case für einen string:

    @SeppJ sagte in switch case für einen string:

    Stringvergleiche sind halt typischerweise Fälle, wo die Werte weder hardcoded sein sollten, noch wo man die Zusatzperformance eines low-level Jumptables bräuchte.

    Typischerweise vielleicht. Gibt aber auch Leute die Parser schreiben.

    Und dann hardcodest du die Sprache überall?

    Wenn sie klein genug ist, sicher. KISS usw.

    map soll das primäre Konstrukt sein um Werten auf Aktionen abzubilden? Was soll der Vorteil gegenüber switch sein?

    Offenheit.

    Ich hab keine Ahnung was das bedeuten soll. Wenn man was dynamisches braucht (im Sinn von dass man z.B. die "Keys" zur Laufzeit bestimmen kann), klar, dann braucht man was dynamisches und switch ist halt statisch. Ansonsten verstehe ich nicht wie eine map die man mit einem fixen Set an Einträgen erstellt "offener" sein soll als ein switch.

    Der Rest ist beinahe beleidigend, wo du anderen vermeintlich(!) schlechte Diskussionsweise unterstellst, und dann selber mit komischen Pseudoargumenten kommst.

    Also wenn ich sage dass ich deine Argumente nicht akzeptiere weil sie für mich keinen Sinn machen oder etwas in einem falschen Licht darstellen, dann sind das Pseudoargumente. OK.


  • Mod

    @hustbaer sagte in switch case für einen string:

    Der Rest ist beinahe beleidigend, wo du anderen vermeintlich(!) schlechte Diskussionsweise unterstellst, und dann selber mit komischen Pseudoargumenten kommst.

    Also wenn ich sage dass ich deine Argumente nicht akzeptiere weil sie für mich keinen Sinn machen oder etwas in einem falschen Licht darstellen, dann sind das Pseudoargumente. OK.

    Nein. Du wirfst mir so Zeug wie false dichotomy vor (was in dem Zusammenhang gar keinen Sinn macht) und kommst dann selber mit so Zeug wie

    Dass man einen Haufen Boilerplatecode schreiben muss? Dass Callstacks unübersichtlicher werden?

    oder

    Gibt aber auch Leute die Parser schreiben.

    Wo du irgendwelche Szenarien konstruierst, die von fraglicher Relevanz und Korrektheit sind.

    oder

    KISS

    Wo du implizierst, dass die Alternative nicht simple wäre oder gar stupid wäre, oder gar das dein Vorschlag überhaupt simple ist, obwohl alles davon fragwürdig ist.

    @hustbaer sagte in switch case für einen string:

    Offenheit.

    Ich hab keine Ahnung was das bedeuten soll.

    Ja.



  • @SeppJ Ist OK, du bist der beste.



  • Also Fazit, es gibt drei ernstzunehmende Möglichkeiten?

    • std::map, std::unordered_map
    • switch in Verbindung mit Hashfunktion (compile-time für case labels )
    • LLVM's StringSwitch<>, habt ihr das mal angeschaut? Wäre dann auch eine Lösung der Leute, die Parser schreiben.

    Vielleicht lässt sich ja auch gar nicht pauschal sagen, eine Lösung sei immer die sinnvollste.

    Was mir bei switch gefällt ggü. map ist, dass es m. E. leichter ist mehrere Werte zu mappen (also mehrere case labels hintereinander). Bei Map müsste man die Einträge duplizieren. Blödes Beispiel: meine App soll "quit", "exit", "close" und "shutdown" gleichermaßen verstehen...

    Ich mach das mal wie bei den YouTube Kommentaren, ab 10 Upvotes schreibe ich einen Performance-Benchmark für die drei :p


Log in to reply