

不要轻易使用元编程
source link: https://lotabout.me/2018/think-twice-before-utilizing-meta-programming/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

元编程就像核弹,自己梦寐以求,却不希望别人拥有。
一般说元编程分为两类,一类是宏,在编译时期生成代码;另一类是运行时修改代码的行为。而不论是哪一类,我的建议是在决定使用之前要慎重考虑。元编程能让我们扩展语言本身,是十足的黑魔法;但用好不易,容易造成团队/社区在意见是实现上的分裂。(另外这篇文章里主要是对元编程的一些吐糟,并不包含基础知识的介绍。)
光明与黑暗
一上来,我们先看 Common Lisp 里的 loop
宏就。一方面,它体现了宏的强大;另一方面,它展现了宏能给我们带来的复杂。
熟悉 C/Java 语言都知道循环是语言本身提供的关键字,一般是 for
。但 Lisp 语言特别精简,它认为循环只是递归的一个特殊形式,语言本身也不包含任何的循环关键字。于是有人用宏实现了 loop
,它让我们能以近乎英语的方式在 Lisp 里写循环语句,这里从 这里 摘抄一个例子:
(loop for x in '(a b c d e)
for y from 1
if (> y 1)
do (format t ", ~A" x)
else do (format t "~A" x)
)
你不需要了解这段代码的含义,重要的是了解像 for .. in ..
, if ... do ... else ... do
这样的语法并不是 Lisp 提供的,而是 loop 宏实现的,这些语法离开了
loop
也就不再合法。
我们看到 loop 宏让我们能在 Lisp 语言不支持的情况下享受到近乎现代语言中才包含的
for ... in ...
语法。要知道在 Java 中有两种 for 语句:
for (int i=0; i < array.length; i++) {
System.out.println("Element: " + array[i]);
}
for (String element : array) {
System.out.println("Element: " + element);
}
而第二种直到 JDK 1.5 才加入。在这之前,广大的 Java 程序员即使已经认识到了第二种写法的优越性,却也只能无奈等到语言支持才行。而 Lisp 程序员很快就能通过宏来实现自己理想中的语法。
然而光明与黑暗共生,宏给我们带来极大自由的同时,也意味着分裂。每个程序员心中理想的语法各不相同,这就意味着一千个程序员会有一千种语法。在 Lisp 中宏是非常容易编写的(不代表容易正确编写),意味着真的会存在一千种语法,大家谁也不服谁,因此造成分裂;但在 C/Java 中,没有宏的支持,虽然有一千种想法,但大家都写不出编译器,于是只能集中讨论,统一语法了,再靠大牛们实现了。
而现实就是如此,Common Lisp 尝试标准化 Lisp,但依旧有人不认同这种理念,例如
Scheme,Common Lisp 标准化的 loop
宏在 Scheme 中就被抛弃了。
前车之鉴,后事之师。Lisp 强大的功能,反面导致了语言的分裂,最终使 Lisp 也慢慢退出历史舞台(主流地位),这也被称为 The Lisp Curse。而现实中我们也常常会被元编程的强大和便捷诱惑,我认为使用元编程之前最好考虑会不会造成更多的分裂。最基本的就是不应该自己造语法(DSL)。
当然,我的出发点是多人团队,较大的项目,考虑的是整体的发展。如果是个人学习,或者小团队等,元编程或许能成为你出众的秘密武器。但大的项目讲求的是合作,DSL 造成的分裂实在是得不偿失,尤其是作者离开后,维护的工作经常后继无人。
近两年接触到的 rust 也是提供了宏的支持,虽然不像 Lisp 宏一样容易编写,但从功能的角度上依旧特别强大,而且模板宏写起来也很容易,于是有人想写一个类似 Python 的 dict 语法:
let x = dict!(
"hello" => "world"
,"hello2" => "world2"
);
但我个人并不喜欢这种语法,我认为 Clojure 似的语法更简洁 dict!("hello": "world")
。那在团队里引入这两个宏就会引起代码的分裂,后来人在看代码时就会很困惑。不利于团队的建设。
最后分享在 知乎 上看到的引用:
Hygienic Macros and Compile-Time Evaluation: A first-class macro system, or support for compile-time code execution in general, is something we may consider in future releases. We don’t want the existence of a macro system to be a workaround that reduces the incentive for making the core language great.
https://github.com/apple/swift-evolution/tree/104cdde1c374a95a7eaf4768960578db3b9971b7
Swift 表示不希望用宏来解决语言本身的缺陷。
而我的理解是当我们希望用宏(或其它元编程手段)时,很可能是我们使用的语言缺少了某些特性,例如 Java 的 lombok 提供的 @Getter/@Setter
等注解,就是因为 Java
没有相应的语言层面的支持,看看 Kotlin 的支持你就会明白的。
但即便有了宏(或元编程)的支持,你有信心能做出让整个团队都信服的设计吗?如果没有,最好还是慎重为之。
虽然是吐糟,但这篇之间重写了三次。想表达的内容很多,最终还是把其它的东西删去, Lisp curse 还是我想真正表达的东西吧,其它的基础知识,有缘人自然会从其它地方学会。
年轻人容易崇拜力量,我们也别忘了阳光还有影子。
Recommend
-
133
各位老板,不要招聘订阅咪蒙职场课的员工11月18日,咪蒙在位于北京的品牌发布会上,宣布了自己准备在喜马拉雅FM上线音频课程《咪蒙教你月薪五万》的消息。一个音频课程本不该引爆社交媒体,然而几乎所有好事者在发布该消息时,都自觉将该课程最重要...
-
114
Linus Torvalds 谈内核加固——不要伤害
-
75
OKR到底是什么,在使用OKR的时候也有哪些注意点,在没弄清楚这些事情,可不要轻易使用。 OKR大概在2013年传入中国,开始主要是一些有硅谷背景的初创企业在推行,现在OKR逐步受到IT、互联网、高科技企业的追捧,开始变得流行起来,国内知名的互联网公司豌豆荚、
-
20
EventPromise npm install e-promise # or yarn add e-promise 它可以做什么? 在 Node 中,我们经常需要连接数据库、Redis、Mq、Socket、Rpc等等,它们都是基于回调通知是否连接成功,在连接成功的时候才能进...
-
61
本系列文章将分为三个部分: 第一部分着重介绍多阶段构建(multi-stage builds),因为这是镜像精简之路至关重要的一环。在这部分内容中,我会解释静态链接和动态链接的区别,它们对镜像带来的影响,以及如何避免那些不好的影响。中间会穿...
-
13
引子 对于计算机从业者而言不论你的母语是什么语言,中文,英语或是法语,西班牙语等,你的第一工作语言都是编程语言,你一定听说过那句话 “talk is cheap show me the code"。所以,快速学习和掌握编程语言一直以来都是每一个工程师梦最想要拥有的...
-
10
如本 RVT 智能示教器:让每个人都可以轻易使用机器人!发布于 09-11 · 2083 次播放写下你的评论...
-
8
为什么不要轻易使用 Chrome 复制的 XPath? 发表于 2021-0...
-
8
印度国家支付公司澄清与Coinbase的合作:未有加密货币交易使用其UPI • 1 天前...
-
8
高亮便携易使用冲破黑暗有能量:凯瑞兹G15 V2_原创_新浪众测 ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK