Gattungsbegriff gesucht: std::ignore, all/any, _, _1



  • In vielen Sprachen kann man Ausdrücke formen, in denen anstelle eines Wertes ein Platzhaltersymbol eingefügt wird. Allerdings empfinde ich den Begriff Platzhalter als unzureichend und überspezifisch. Ich suche einen Überbegriff, unter dem man die verschiedenen platzhalterartigen Entitäten zusammenfassen kann.

    Beispiele:

    int i, j;
    std::tie(i, j, std::ignore) = threesome();
    
    button1.Click += (_,_) => Logger.Log("Button clicked");
    

    Die discards sind tatsächlich Platzhalter in dem Sinne, daß an ihrer Stelle auch ein Wert stehen könnte, ohne daß sich die Semantik des Programmes änderte.

    (Mit "Wert" meine ich nicht einen Zahlenwert, sondern einen Wert im Sinne des fraglichen Ausdrucks; je nach Art des Ausdrucks wäre das ein Typ, ein Bezeichner oder eine r-value expression. Man merkt, mir fehlt hier das Vokabular.)

    std::string subs = s.substr(42, std::string::npos);
    
    array.checkStrides({ 1, anyStride });
    

    Diese würde ich eher als tag values bezeichnen, d.h. sie stehen nicht anstelle eines gültigen Werts, sondern sie sind ein gültiger Wert, allerdings mit spezifischer Bedeutung. Auch Nullzeiger werden (leider) oft als tag value verwendet.

    auto inchToCmFunc = std::bind(std::multiplies<double>(), 2.54, _1);
    
    // wie std::bind(), aber anderes Interface
    auto inchToCmFunc = partial(std::multiplies<double>(), 2.54, arg<0>);
    
    // mit positionsbhängigen Argumenten wie in der mathematischen Notation, g = f(2.54,·)
    auto inchToCmFunc = partial(std::multiplies<double>(), 2.54, arg<>);
    
    auto inchToCmFunc = partial(std::multiplies<double>(), arg<0>=2.54);
    

    _1 , ..., _N werden in C++ als placeholders bezeichnet (jedenfalls leben sie in std::placeholders ), aber ich finde, das trifft es nicht recht, weil sie eine semantische Bedeutung tragen. Eine sinntragende Bezeichnung wäre argument forwarders; vielleicht könnte man sie auch im obigen Sinn als tag values einordnen. Aber was ist mit arg<i>=value ?

    auto plane = cube.subarray(all, all, 42);
    
    // anstatt "arg<0>, arg<1>, ..., arg<N-1>" können wir einfach "all" schreiben
    auto boundMemberFunctionPointer = partial(memberFunctionPointer, instanceRef, all);
    

    Für dieses all finde ich keine passende Bezeichnung. Es ist kein tag value, weil cube.subarray(all, all, all) einen anderen Typ hat als cube.subarray(all, all, 42) ( Array<T, 3> vs. Array<T, 2> ). Und in partial() steht es stellvertretend für alle argument forwarders.

    Gibt es einen schönen übergeordneten Begriff, der all solche Entitäten einbezieht? Oder kennt jemand zumindest Begriffe für die Entitäten, für die ich keine passenden Namen finden konnte?


  • Mod

    Wie wäre es mit Abklappergaul oder Erledigungsagent?
    oder vielleicht discret List-Comprehension-Overdrive-Optimizer oder so...
    schau dich ein wenig in der Haskellwelt um, eventuell bzw. mit guter Wahrscheinlichkeit findest du dort eine nette Anregung.



  • Suchst du explizit nach einem deutschen Ausdruck?

    MfG SideWinder



  • SideWinder schrieb:

    Suchst du explizit nach einem deutschen Ausdruck?

    Nein.


  • Mod

    Ich finde den Begriff argument forwarders ganz gut, allerdings trifft er den Begriff "all" nicht gut.

    Wenn man einen Schritt zurückgeht, kann man "argument-forwarder" Symbole ganz ähnlich wie bei Regular Expressions sammeln und abstufen.

    Du landest dann angefangen bei einzelnen Elementen wie i++ (+ bool-Operatoren), Hardware- und Software-Zählregistern (Cx, Graf Zahl) bis kunstvoll verschachtelte Schleifen und komplexen Funktionen oder auch Sprachelementen wie "Manipulatoren" oder "Iteratoren" usw.

    Bei Haskell und Lisp könnte man noch sagen, "List-Processing" - aber da ist ja alles "Listprocessing", eine komplette Sprach und Betrachtungsphilosophie.

    Ich hatte mal im Internet eine Diskussion (zur Sprachentwicklung von Haskell) gesehen, da ging es um die List-Comprehensions bzw. ihre formale Gestaltung. Man hatte auch eine Variante mit Überladung, die aufgrund von Einfachheitsgründen abgewählt wurde.
    Frag mich jetzt aber nicht wo..
    (aber https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/guide-to-ghc-extensions/list-and-comprehension-extensions bietet Hinweise, die sind nicht so schwer zu verstehen (auch der Parallelgedanke spielt hier mit)

    Du kannst aber auch (zum besseren Verständnis!) ein wenig mit den Datentypenmöglichkeiten in Haskell herumspielen ->
    http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html



  • audacia schrieb:

    SideWinder schrieb:

    Suchst du explizit nach einem deutschen Ausdruck?

    Nein.

    Wir nutzen als Begriff "ignored arguments", nicht sehr "sophisticated" aber immerhin...

    MfG SideWinder



  • SideWinder schrieb:

    Wir nutzen als Begriff "ignored arguments"

    Aber nur für die discards, nehme ich an? Bei meinen anderen Beispielen ( all , _1 , string::npos) sähe ich keinen inhaltlichen Bezug. Ich suche ja einen Überbegriff, der alles umfaßt.

    (Falls mir jemand erklären kann, warum die oben aufgeführten Dinge nicht, wie es mir vorkommt, eine einen Überbegriff rechtfertigende Gemeinsamkeit haben, so bin ichs auch zufrieden.)



  • audacia schrieb:

    Für dieses all finde ich keine passende Bezeichnung. Es ist kein tag value, weil cube.subarray(all, all, all) einen anderen Typ hat als cube.subarray(all, all, 42) ( Array<T, 3> vs. Array<T, 2> ). Und in partial() steht es stellvertretend für alle argument forwarders.

    Mittlerweile fiel mir auf, daß man dieses all wohl ein wildcard nennen könnte.

    Einen Überbegriff suche ich trotzdem noch.



  • discard tag
    forwarding tag/argument tag
    wildcard tag

    => tag?

    alternativ: token



  • Wenn du keinen Namen für deine Basisklasse finden kannst, ist vielleicht
    deine Klassenarchitektur falsch 😉 (ich nehme an darum gehts hier, oder
    schreibst du ein Buch?)

    audacia schrieb:

    Beispiele:

    int i, j;
    std::tie(i, j, std::ignore) = threesome();
    
    button1.Click += (_,_) => Logger.Log("Button clicked");
    

    ignore ist hier für mich ein Platzhalter für die Variable X, die es
    nicht gibt.

    std::string subs = s.substr(42, std::string::npos);
    
    array.checkStrides({ 1, anyStride });
    

    Verstehe nicht ganz was du meinst. 42, npos und 1 (als Array-Element?
    bin nicht so c++-modern) sind Argumente. anyStride ist an der Stelle
    auch ein Argument, und allgemein wohl ein Predikat.

    auto inchToCmFunc = std::bind(std::multiplies<double>(), 2.54, _1);
    
    // wie std::bind(), aber anderes Interface
    auto inchToCmFunc = partial(std::multiplies<double>(), 2.54, arg<0>);
    
    // mit positionsbhängigen Argumenten wie in der mathematischen Notation, g = f(2.54,·)
    auto inchToCmFunc = partial(std::multiplies<double>(), 2.54, arg<>);
    
    auto inchToCmFunc = partial(std::multiplies<double>(), arg<0>=2.54);
    

    _1 , ..., _N werden in C++ als placeholders
    bezeichnet (jedenfalls leben sie in std::placeholders ), aber ich
    finde, das trifft es nicht recht, weil sie eine semantische Bedeutung
    tragen.

    Semantische Bedeutung? 😕 _1 und arg<> sind Platzhalter für
    Argumente. Ich finde die offizielle Bezeichnung schon zutreffend.

    auto plane = cube.subarray(all, all, 42);
    
    // anstatt "arg<0>, arg<1>, ..., arg<N-1>" können wir einfach "all" schreiben
    auto boundMemberFunctionPointer = partial(memberFunctionPointer, instanceRef, all);
    

    ich kenne diese Funktionen nicht. Ich nehme an 'all' bedeutet hier sowas
    wie '...'. In dem Fall wäre das ein Platzhalter für variable
    Argumentlisten.



  • mammal.layEgg(); schrieb:

    Wenn du keinen Namen für deine Basisklasse finden kannst, ist vielleicht
    deine Klassenarchitektur falsch 😉 (ich nehme an darum gehts hier, oder
    schreibst du ein Buch?)

    Weder noch 🙂 Als ich den Thread aufmachte, war ich auf der Suche nach einem Namen für eine Headerdatei, die nun aus verschiedenen Gründen "types.hpp" heißt. Die Frage war aber aus allgemeinem Interesse gestellt.

    Es stimmt wohl, daß man die meisten dieser Symbole unter dem Begriff "tag" zusammenfassen könnte. Mit Bauchschmerzen vielleicht sogar unter "Platzhalter". Vielleicht habe ich auch die falsche Frage gestellt: was mich beschäftigt, ist die Beobachtung, daß diese Symbole gewisse Gemeinsamkeiten besitzen (ihre "Platzhalterartigkeit"), sich aber in anderen, für mich nicht leicht zu benennenden Aspekten kategorisch unterscheiden. Und mich macht es nervös, wenn ich für einen wahrgenommenen Zusammenhang keine Worte finde, weil das darauf hindeutet, daß ich ihn noch nicht richtig verstanden habe.

    Daß du manche der Funktionen nicht kennst, könnte daran liegen, daß ich sie zu illustrativen Zwecken erfunden habe 🙂 Ich hoffe, die Namensgebung macht die jeweils intendierte Bedeutung offensichtlich.

    Kurzer Versuch einer Typologie der Platzhalterartigen:

    • discards ( std::ignore in C++, _ in C# u. a.):
      - Auswirkung auf den Wert/Effekt des enthaltenden Ausdrucks: keine. Man hätte stattdessen auch eine benannte Variable (C++) bzw. einen gültigen Bezeichner (C#) einsetzen und dann ignorieren können, das Programm ändert sich dadurch nicht.
      - Auswirkung auf den Typ des enthaltenden Ausdrucks: keine in C# (Sprachmittel), keine beobachtbaren in C++ (temporäres Proxyobjekt)
    • magic numbers (allgemein) oder (als Spezialfall davon) pattern-matching wild cards ( std::string::npos , anyStride in Array<>::checkStrides() , '?' oder * in Globs):
      - Auswirkung auf den Wert/Effekt des enthaltenden Ausdrucks: in einem pattern matching-Kontext wächst die Menge der Werte mit match an; für magic numbers kann sich jede beliebige Änderung ergeben
      - Auswirkung auf den Typ des enthaltenden Ausdrucks (also der initializer-list in Array<>::checkStrides() oder den Suchstring, der '?' oder * enthält): keine
    • forwarding tags ( _1 , arg<i> , arg<> ) in std::bind() oder partial :
      - Auswirkung auf den Wert/Effekt des enthaltenden Ausdrucks: die gebundene Funktion wird mit anderen Werten aufgerufen
      - Auswirkung auf den Typ des enthaltenden Ausdrucks: bei std::bind() oder partial ändert sich die Arität der Funktion, wenn ein forwarding tag statt eines Wertes angegeben wird
    • argument binders ( arg<0> = 2.54 in partial() ):
      das ist das Gegenstück zu den forwarding tags
    • insertion/expansion wildcard ( all in Array::subarray() und partial() , oder ebenso die parameter pack expansion ... bei variadic templates):
      - Auswirkung auf den Wert/Effekt des enthaltenden Ausdrucks: tja; hier vielleicht die falsche Frage?
      - Auswirkung auf den Typ des enthaltenden Ausdrucks: bei partial und variadic templates ändert sich die Arität der Funktion/der Typliste/der Wertliste, wenn ein insertion/expansion wildcard statt eines Wertes oder eines forwarding tag angegeben wird

    Angesichts dieser Unterschiede finde ich es schwierig zu behaupten, es gebe spezifische Gemeinsamkeiten unter diesen Dingen, und also noch schwieriger, sie alle gleichermaßen als "Platzhalter" zu bezeichnen. (Dann eher noch "tag", was aber sehr unspezifisch ist.) Andererseits sagt mir die Intuition, daß es eine semantische Gemeinsamkeit geben muß, die ich aber eben nicht besser benennen kann als mit "Platzhalterartigkeit".



  • Die einzige Gemeinsamkeit die ich erkennen kann, ist dass es "spezielle" Dinger sind die an stelle von anderen, "normalen" Dingern stehen können, und halt ne spezielle Bedeutung haben.
    Also vielleicht "special tokens"?


Log in to reply