2009-11-11 104 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.

在这个例子中看起来像是太多的工作,但能够做这样的事情是一个很好的能力,因为你的问题被视为。

相关问题