Frage

Ich denke D's's static if ist eine interessante Sprachfunktion. Das fordert meine Frage auf: Gibt es andere Beispiele für kompilierte Sprachen, in denen der Compiler einen starken Begriff des Codes hat und es Sprachen gibt, die auf sie zugreifen können?

Zum Beispiel bietet dieser Code etwas Ähnliches wie repr Von Python:

char[] repr(T)(T value) {
  static if (is(typeof(value.__repr__))) { // class T provides a "repr()" method
    return value.__repr__();  
  } else static if (is(T:string)) {
    return `"` ~ value ~ `"`;
  // ...other cases...
  } else {
    return toString(value);
  }
}

Ich denke, das ist cool, weil es einen anderen und allgemeineren Ansatz für das Überladen ermöglicht, was eine Art Innenausfuhr ist, um Code dynamischer zu gestalten, als bei Funktionen wie diesen. Zum Beispiel weiß der Compiler, wie viele Felder meine Klasse hat, aber es gibt keine Möglichkeit, dass mein Code in den meisten Sprachen zu kompilieren Zeitpunkten zugänglich ist.

Vorbehalt: Dieser letzte Absatz hatte Meinungen darin, aber ich meine nur, motivierte und klärung für meine frage zu liefern und keine kontroverse zu entstehen. Ich möchte nur herausfinden, ob andere kompilierte Sprachen solche Funktionen haben.

War es hilfreich?

Lösung

Jede Sprache mit echtem Makros hat eine Form von statischer, wenn. Zum Beispiel Lisp und Nemerle Mit dem Code, den ein Makro auf Programmierkonstrukte wie "if" und für die Schleife erweitert, konstruieren Sie den Code. Dies sind im Wesentlichen Kompilierungs-Zeit-Entscheidungen und lassen Sie Sie etwas Ähnliches wie statisch tun, wenn. Im Fall von Nemerle sind Makros im Grunde genommen Plug-Ins für den Compiler, der zur Kompilierungszeit ausgeführt wird.

In C ++ gibt es Boost Mpl Bibliothek mit a Art von statischer wenn Das kann verwendet werden, um zwischen zwei Typen zu wählen. Sie könnten einen Code in den beiden Typen in einem Run () -Mitglied einfügen und etwas Ähnliches erhalten, aber mit sehr umständlicher Syntax.

Zum Beispiel mit Boost MPL könnten Sie so etwas tun:

struct float_impl { 
    static void run() { /* float case code */ }
}
struct int_impl { 
    static void run() { /* int case code */ }
}

typedef typename if_<
          is_same<T, float>
        , float_impl
        , int_impl
        >::type impl_t;
impl_t::run();

In D wäre das:

static if(is(T == float)) {
     /* float code */
}
else {
     /* int code */
}

Andere Tipps

Für das Bewusstsein einer "Sprache für Code" gibt es kein Besseres, das ich gesehen habe als Lisp und seine Makroanlage - insbesondere gemeinsames Lisp. Der Handel dort ist jedoch, dass der Typ eines Objekts in der Kompilierung Zeit oder Makroexpansionszeit nicht bekannt ist. Für Literale sind die Typen bekannt, sodass Sie Beispiele für aggressive Makros finden, die testen, ob ein Objekt wörtlich ist, und wenn ja, behandeln Für die Laufzeitprüfung.

Hier ist ein Beispiel, das ich an die angepasst habe Cllib Bibliothek (Teil der Clocc Bibliothek) vor einigen Jahren. Ziel ist es, Funktionen bereitzustellen, die eine Präfix -Zeichenfolge von einer anderen Zeichenfolge mit einem passenden Präfix abhacken. Das Präfix kann zur Makroexpansionszeit bekannt sein oder nicht. Wenn dies der Fall ist, können wir eine Optimierung: Berechnen Sie zuerst die Länge des Präfixs und setzen Sie sie als wörtlich ein, damit sie bei jedem Aufruf nicht in die generierte Funktion neu berechnet wird. Das Makro ist zunächst entmutigend, aber der tatsächliche generierte Code ist klein.

(defmacro after-prefix-core (comparison-op prefix string &optional length)
  "Similar to cllib:string-beg-with-cs."
  (flet ((chop (prefix prefix-length string string-length)
           `(when (and (>= ,string-length ,prefix-length)
                       (,comparison-op ,prefix ,string :end2 ,prefix-length))
              (subseq ,string ,prefix-length ,string-length))))
    (let* ((gstring (gensym "STRING-"))
           (gstring-length (gensym "STRING-LENGTH-")))
      `(let* ((,gstring ,string)
              (,gstring-length ,(or length `(length ,gstring))))
         ,(if (stringp prefix)
              ;; Constant -- length known at expansion time.
              (let ((prefix-length (length prefix)))
                (chop prefix prefix-length gstring gstring-length))
              ;; Other form -- length not known at expansion time.
              (let ((gprefix (gensym "PREFIX-"))
                    (gprefix-length (gensym "PREFIX-LENGTH-")))
                `(let* ((,gprefix ,prefix)
                        (,gprefix-length (length ,gprefix)))
                   ,(chop gprefix gprefix-length gstring gstring-length))))))))


(defmacro after-prefix (prefix string &optional length)
  "Similar to cllib:string-beg-with."
  `(after-prefix-core string-equal ,prefix ,string ,length))


(defmacro after-prefix-cs (prefix string &optional length)
  "Similar to cllib:string-beg-with-cs."
  `(after-prefix-core string= ,prefix ,string ,length))

Siehe die Form

(if (stringp prefix)

mitten drin? Dies inspiziert das erste Argument zur Makroexpansionszeit und je nachdem, ob das Argument ein wörtliches oder ein Symbol ist, kann sein Typ bekannt sein oder nicht. Wenn der Typ ein Symbol ist, wir davon ausgehen Dass wir bis zur Laufzeit warten sollten, um es als eine Variable zu überdenken, die auf einen anderen Wert hinweist.

Hier ist die Erweiterung für die Form (after-prefix foo bar):

(LET* ((#:STRING-5340 BAR) (#:STRING-LENGTH-5341 (LENGTH #:STRING-5340)))
  (LET* ((#:PREFIX-5342 FOO) (#:PREFIX-LENGTH-5343 (LENGTH #:PREFIX-5342)))
    (WHEN
        (AND (>= #:STRING-LENGTH-5341 #:PREFIX-LENGTH-5343)
             (STRING-EQUAL #:PREFIX-5342 #:STRING-5340 :END2 #:PREFIX-LENGTH-5343))
      (SUBSEQ #:STRING-5340 #:PREFIX-LENGTH-5343 #:STRING-LENGTH-5341))))

Beachten Sie, dass die Variable #:PREFIX-LENGTH-5343 ist an die gebunden berechnete Länge von FOO, hier an Variable gebunden #:PREFIX-5342.

Schauen Sie sich nun die Erweiterung für die Form an (after-prefix "foo" bar), wo das Präfix jetzt ein Streicherliteral ist:

(LET* ((#:STRING-5463 BAR) (#:STRING-LENGTH-5464 (LENGTH #:STRING-5463)))
  (WHEN (AND (>= #:STRING-LENGTH-5464 3) (STRING-EQUAL "foo" #:STRING-5463 :END2 3))
    (SUBSEQ #:STRING-5463 3 #:STRING-LENGTH-5464)))

Jetzt gibt es keine Berechnung der Länge von "Foo"; Es ist 3.

Es mag in diesem Beispiel zu viel Arbeit erscheinen, aber es ist eine gute Kraft, solche Dinge zu tun, wie Ihre Frage der Meinung ist.

static_if wurde für die nächste Version von C ++ (C ++ 1y) vorgeschlagen. Es wurde ursprünglich für C ++ 11 vorgeschlagen, wurde jedoch anscheinend verzögert.

Siehe den Vorschlag hier. Interessanterweise ist einer der Autoren Walter Bright, der Schöpfer von D.

Ebenfalls, Es ist möglich, statisch-wenn in aktuellem C ++ mit Compiler-Hacks zu fälschen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top