Domanda

Penso che D static if è una caratteristica linguistica interessante.Ciò fa sorgere la mia domanda:Esistono altri esempi di linguaggi compilati in cui il compilatore ha una forte nozione del codice e ci sono funzionalità linguistiche per accedervi?

Ad esempio, questo codice fornisce qualcosa di simile a repr da 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);
  }
}

Penso che sia interessante perché consente un approccio diverso e più generale a ciò che fa l'overload, che è una specie di modo rovesciato per rendere il codice più dinamico, rispetto a funzionalità come questa.Ad esempio, il compilatore sa quanti campi ha la mia classe, ma non c'è modo per il mio codice di accedere a tali informazioni in fase di compilazione nella maggior parte dei linguaggi.

AVVERTIMENTO:L'ultimo paragrafo conteneva opinioni, ma intendo solo fornire motivazione e chiarimenti alla mia domanda, non suscitare polemiche.Voglio solo scoprire se altri linguaggi compilati hanno tali caratteristiche.

È stato utile?

Soluzione

Ogni lingua con le macro reali ha una forma di statico se. Per esempio Lisp e Nemerle consentono di costruire il codice che una macro si espande ad usare costrutti di programmazione come 'se' e per -loops. Quelli sono sostanzialmente in fase di compilazione decisioni e consentono di fare qualcosa di simile a statico se. Nel caso di macro Nemerle sono fondamentalmente plug-in per il compilatore che vengono eseguiti a tempo di compilazione.

In C ++ c'è aumentare MPL biblioteca, che ha un di statico se che può essere utilizzato per scegliere tra due tipi. Si potrebbe mettere un po 'di codice all'interno dei due tipi in un membro run () e ottenere qualcosa di un pò simile, ma con una sintassi molto ingombrante.

Ad esempio con Boost MPL si potrebbe fare qualcosa di simile:

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 che sarebbe:

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

Altri suggerimenti

Per una "consapevolezza del codice da parte del linguaggio", non ho visto nulla di meglio del Lisp e della sua funzionalità macro, in particolare del Common Lisp.Ma il problema è che la maggior parte delle volte il tipo di un oggetto non è noto in fase di compilazione o in fase di macroespansione.Per i valori letterali, i tipi sono noti, quindi puoi trovare esempi di macro aggressive che testano per vedere se un oggetto è un valore letterale e, in tal caso, trattalo in un modo, magari in base al suo tipo, e altrimenti prepara la variabile rilevata per l'ispezione del tipo in fase di esecuzione.

Ecco un esempio che ho adattato da CLIB biblioteca (parte del CLOCC biblioteca) diversi anni fa.L'obiettivo è fornire funzioni che taglieranno una stringa di prefisso da qualche altra stringa con un prefisso corrispondente.Il prefisso potrebbe essere noto al momento della macroespansione oppure no.Se lo è, possiamo un'ottimizzazione:calcola prima la lunghezza del prefisso e incorporalo come valore letterale, in modo che non venga ricalcolato a ogni chiamata alla funzione generata.All'inizio la macro è scoraggiante, ma il codice effettivamente generato è piccolo.

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

Vedi il modulo

(if (stringp prefix)

nel mezzo?Si tratta di ispezionare il primo argomento al momento della macroespansione e, a seconda che l'argomento sia un letterale o un simbolo, il suo tipo può essere noto o meno.Se il tipo è un simbolo, noi assumere che dovremmo aspettare fino al momento dell'esecuzione per riconsiderarlo come una variabile che punta a qualche altro valore.

Ecco l'espansione del modulo (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))))

Tieni presente che la variabile #:PREFIX-LENGTH-5343 è vincolato al lunghezza calcolata Di FOO, legato qui a variabile #:PREFIX-5342.

Ora guarda l'espansione del modulo (after-prefix "foo" bar), dove il prefisso ora è una stringa letterale:

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

Ora non è più possibile calcolare la lunghezza di "foo";è in linea come 3.

Può sembrare troppo lavoro in questo esempio, ma essere in grado di fare queste cose è un buon potere da avere, come suggerisce la tua domanda.

static_if è stato proposto per la prossima versione di C ++ (C ++ 1A). E 'stato originariamente proposto per C ++ 11, ma a quanto pare è stata ritardata.

Si veda la proposta qui . È interessante notare che uno degli autori è Walter Bright, il creatore di D.

Inoltre, è possibile falsi che utilizzano hack statici, se in corrente C ++ Compiler .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top