Question

Je pense que static if de D'est une caractéristique de langue intéressante. Ma question qui demande: Y at-il d'autres exemples de langages compilés dans lequel le compilateur a une forte notion de code et il y a des langues facilités pour leur accès

Par exemple, ce code fournit quelque chose de similaire à repr de 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);
  }
}

Je pense que c'est cool est parce qu'il permet une approche différente et plus générale de ce que fait la surcharge, ce qui est un peu un intérieur pour rendre le code plus dynamique, par rapport aux caractéristiques de ce genre. Par exemple, le compilateur sait combien de champs ma classe a, mais il n'y a aucun moyen pour mon code pour accéder à ces informations au moment de la compilation dans la plupart des langues.

OPPOSITION: Ce dernier paragraphe avait des opinions en elle, mais je veux dire juste pour fournir une motivation et des éclaircissements à ma question, ne pas susciter la controverse. Je veux juste savoir si d'autres langages compilés ont de telles caractéristiques.

Était-ce utile?

La solution

Toutes les langues avec des macros réelles a une forme de statique si. Par exemple Lisp et Nemerle vous permettent de construire le code qu'une macro se développe à l'aide de constructions de programmation comme « si » et -boucles. Ce sont essentiellement la compilation des décisions et vous permettent de faire quelque chose de similaire à l'électricité statique, si. Dans le cas de macros Nemerle sont essentiellement plug-ins pour le compilateur qui sont exécutées au moment de la compilation.

En C ++, il y a stimuler MPL bibliothèque qui a un href="http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual/if.html" type de statique si qui peut être utilisé pour choisir entre deux types. Vous pouvez mettre un code à l'intérieur des deux types dans un membre run () et obtenir quelque chose un peu similaire, mais avec une syntaxe très lourde.

Par exemple avec MPL Boost vous pourriez faire quelque chose comme ceci:

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();

Dans D qui SERAIS:

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

Autres conseils

Pour une « conscience de la langue du code », il n'y a pas de meilleur que j'ai vu que Lisp et son installation macro - spécifiquement, Common Lisp. Mais le commerce, il est que la plupart du temps type d'un objet est inconnu au moment de la compilation ou le temps de macroexpansion. Pour littéraux, les types sont connus, vous pouvez trouver des exemples de macros agressives qui font l'essai pour voir si un objet est un littéral et, le cas échéant, traiter d'une façon - peut-être en fonction de son type - et préparer des la variable détectée pour l'inspection du type d'exécution.

Voici un exemple que j'adapté du CLLIB bibliothèque (partie du CLOCC bibliothèque) il y a plusieurs années. L'objectif est de fournir des fonctions qui coupera une chaîne de préfixe au large d'une autre chaîne avec un préfixe correspondant. Le préfixe peut être connu au moment de macroexpansion ou il ne peut pas. Dans ce cas, nous pouvons une optimisation: Calculons d'abord et intégrons la longueur du préfixe comme un littéral, de sorte que ce n'est pas recalculé sur chaque appel à la fonction générée. La macro est intimidant au début, mais le code généré réel est faible.

(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))

Voir le formulaire

(if (stringp prefix)

au milieu? C'est inspectant le premier argument au moment de macroexpansion et, selon que l'argument est un littéral ou d'un symbole, son type peut ou peut ne pas être connu. Si le type est un symbole, nous Supposons que nous devrions attendre de l'exécution pour un nouvel examen comme variable pointant à une autre valeur.

Voici l'expansion de la forme (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))))

Notez que la #:PREFIX-LENGTH-5343 variable est liée à la longueur calculée de FOO, lié ici pour #:PREFIX-5342 variable.

Maintenant, regardez l'expansion de la forme (after-prefix "foo" bar), où le préfixe est maintenant une chaîne de caractères:

(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)))

Maintenant, il n'y a pas de calcul de la longueur de « foo »; il est inline que 3.

Il peut sembler trop de travail dans cet exemple, mais être capable de faire de telles choses est un bon pouvoir d'avoir, en tant que votre question opine.

static_if a été proposé pour la prochaine version de C ++ (C ++ 1y). Il a été initialement proposé pour 11 C ++, mais a apparemment été retardée.

Voir la proposition ici . Fait intéressant, l'un des auteurs est Walter lumineux, le créateur de D.

En outre, il est possible de faux hacks statique si l'aide actuelle compilateur C ++ .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top