Pregunta

Creo que D static if es una característica interesante del lenguaje.Eso genera mi pregunta:¿Existen otros ejemplos de lenguajes compilados en los que el compilador tenga una sólida noción del código y existan facilidades de lenguaje para acceder a ellos?

Por ejemplo, este código proporciona algo similar a 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);
  }
}

Creo que esto es genial porque permite un enfoque diferente y más general de lo que hace la sobrecarga, que es una forma de hacer que el código sea más dinámico, en comparación con características como esta.Por ejemplo, el compilador sabe cuántos campos tiene mi clase, pero no hay forma de que mi código acceda a esa información en tiempo de compilación en la mayoría de los lenguajes.

ADVERTENCIA:Ese último párrafo contenía opiniones, pero solo pretendo brindar cierta motivación y aclaración a mi pregunta, no generar controversia.Sólo quiero saber si algún otro lenguaje compilado tiene tales características.

¿Fue útil?

Solución

Cualquier lenguaje con macros reales tiene una forma de estática si. Por ejemplo Lisp y Nemerle le permiten construir el código que una macro se expande a la utilización de construcciones de programación como 'si' y para -loops. Esos son esencialmente las decisiones en tiempo de compilación y le permiten hacer algo similar a la estática si. En el caso de las macros Nemerle son básicamente plug-ins para el compilador que se ejecutan en tiempo de compilación.

En C ++ hay impulsar MPL biblioteca que tiene una estática si que puede ser utilizado para elegir entre dos tipos. Se podría poner un poco de código dentro de los dos tipos en un miembro de run () y conseguir algo un poco similar, pero con una sintaxis muy engorroso.

Por ejemplo, con MPL Boost se podría hacer algo como esto:

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

En D que serías:

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

Otros consejos

Para el "conocimiento del código del lenguaje", no he visto nada mejor que Lisp y su función de macros, específicamente, Common Lisp.Pero la cuestión es que la mayoría de las veces el tipo de objeto no se conoce en el momento de la compilación o en el momento de la macroexpansión.Para los literales, los tipos son conocidos, por lo que puede encontrar ejemplos de macros agresivas que prueban para ver si un objeto es un literal y, de ser así, lo tratan de una manera (tal vez según su tipo) y, de lo contrario, preparan la variable detectada. para inspección de tipo en tiempo de ejecución.

Aquí hay un ejemplo que adapté del CLIB biblioteca (parte de la CLOCC biblioteca) hace varios años.El objetivo es proporcionar funciones que corten una cadena de prefijo de otra cadena con un prefijo coincidente.El prefijo puede ser conocido en el momento de la macroexpansión o no.Si es así, podemos realizar una optimización:primero calcule la longitud del prefijo e incrústelo como un literal, de modo que no se vuelva a calcular en cada llamada a la función generada.La macro resulta desalentadora al principio, pero el código generado real es pequeño.

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

ver el formulario

(if (stringp prefix)

¿en el centro?Eso es inspeccionar el primer argumento en el momento de la macroexpansión y, dependiendo de si el argumento es un literal o un símbolo, su tipo puede conocerse o no.Si el tipo es un símbolo, asumir que deberíamos esperar hasta el tiempo de ejecución para reconsiderarla como una variable que apunta a algún otro valor.

Aquí está la expansión del formulario. (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))))

Tenga en cuenta que la variable #:PREFIX-LENGTH-5343 está obligado a la longitud calculada de FOO, vinculado aquí a la variable #:PREFIX-5342.

Ahora mira la expansión del formulario. (after-prefix "foo" bar), donde el prefijo ahora es una cadena literal:

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

Ahora no se puede calcular la longitud de "foo";está alineado como 3.

Puede parecer demasiado trabajo en este ejemplo, pero poder hacer esas cosas es un buen poder, como lo opina su pregunta.

static_if se ha propuesto para la próxima versión de C ++ (C ++ 1y). Se propuso originalmente para C ++ 11, pero al parecer se retrasó.

Vea la propuesta aquí . Curiosamente, uno de los autores es Walter Bright, el creador de D.

Además, es posible utilizando los cortes a la electricidad estática si falsos en C ++ compilador actual .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top