2009-11-11 107 views
13

我認爲D的static if是一個有趣的語言功能。這提示了我的問題:編譯語言是否還有其他編譯器具有強大代碼概念的示例,並且有語言工具可以訪問它們?除D之外還有其他語言是否有靜態if?

例如,下面的代碼提供類似於repr東西在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); 
    } 
} 

我覺得這是很酷的,因爲它允許不同的,更全面的方法來所做的超載,這是一種內部的讓代碼更具動態性,與此類功能相比。例如,編譯器知道我的類有多少個字段,但是我的代碼無法在大多數語言的編譯時訪問這些信息。 CAVEAT:最後一段有意見,但我的意思是爲我的問題提供一些動機和澄清,不引起爭議。我只想知道其他編譯語言是否有這樣的功能。

+1

如果'if'中的表達式可以在編譯時確定,許多C和C++編譯器將刪除未使用的代碼。不知道這是否完全回答你的問題。 – 2009-11-11 20:57:30

+0

否 - 上面的例子不會編譯,因爲某些靜態代碼塊中的代碼無效。例如。如果T是int類型,則值.__ repr __()將是編譯錯誤。 – Grumdrig 2009-11-11 21:03:44

+1

您需要爲上述內容編譯「靜態if(is(typeof(value .__ repr__)))」。或者「static if(__ traits(compiles,value .__ repr__))」。 – Baxissimo 2009-11-11 21:35:05

回答

10

任何具有實型宏的語言都有一個靜態if形式。比如Lisp和Nemerle可以讓你構造一個宏擴展到使用編程結構如'if'和for-loops的代碼。這些本質上是編譯時決定,並讓你做類似於靜態的東西。在Nemerle宏的情況下,基本上插件是編譯時執行的編譯器。

在C++中有boost MPL庫,其中有一個kind of static if可以用來選擇兩種類型。你可以在run()成員中放入兩種類型的代碼,並得到類似的東西,但語法非常繁瑣。

例如與升壓MPL你可以做這樣的事情:

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

在d那會是:

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

美麗。 Nemerle對我來說很新鮮,非常有趣。期待探索它。我應該想到的Lisp宏。 – Grumdrig 2009-11-11 22:52:17

2

對於「語言的代碼意識」,有沒有更好的我比Lisp和它的宏觀設施 - 特別是Common Lisp更加明顯。但是大多數情況下,在編譯時或宏擴展時,對象的類型是未知的。對於文字,這些類型是已知的,所以你可以找到侵略性宏的例子,它們測試一個對象是否是一個文字,如果是,就以一種方式處理它 - 也許根據它的類型 - 然後準備檢測到的變量用於運行時型檢測。

這是我幾年前從CLLIB庫(CLOCC庫的一部分)改編的一個示例。我們的目標是提供將前綴字符串從其他字符串中剔除並且匹配前綴的函數。前綴可能在宏擴展時已知,或者可能不是。如果是,我們可以進行優化:首先計算前綴的長度並將其嵌入爲文字,以便在每次調用生成的函數時不重新計算它。宏開始令人生畏,但實際生成的代碼很小。

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

見表格

(if (stringp prefix) 
中間

?這是在宏展開時檢查第一個參數,並且根據參數是文字還是符號,其類型可能已知也可能不知道。如果類型是一個符號,我們假設,我們應該等到運行時重新考慮它作爲指向其他值的變量。

下面是形式(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)))) 

注意,變量#:PREFIX-LENGTH-5343被綁定到計算長度FOO,這裏結合到可變#:PREFIX-5342

現在看看擴張形式(after-prefix "foo" bar),現在在哪裏前綴是一個字符串文字:

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

現在有沒有計算的「富」的長度;它被內聯爲3.

在這個例子中看起來像是太多的工作,但能夠做這樣的事情是一個很好的能力,因爲你的問題被視爲。

相關問題