5 月 29 日,由极客邦旗下 InfoQ 中国主办的全球软件开发大会 QCon 2021 北京站正式拉开帷幕。大会为期三天,华为编程语言实验室架构师徐潇作为其中“软件研发方法”专题的出品人,于今日联合多位讲师为大家带来软件开发技术和编程语言技术相关的精彩议题。

徐潇 华为编程语言首席架构师,领域编程语言高级专家,拥有软件领域十余年工作经验。当前主要担任编程语言 eDSL 相关能力的设计工作。

以下为徐潇分享的“领域特定编程语言的设计探索”原文:
领域特定编程语言,简称 DSL,作为在软件开发中不可或缺的一环,在很多领域都承担了很重要的作用。当前出现一个趋势,DSL 的一个分类 —— 内部 DSL(简称 eDSL)—— 在某些领域取代了原有的外部 DSL 或者通用语言,其背后一个客观因素是,现代编程语言的发展,有意识的设计用于实现内部 DSL 的特性,使开发者可以构建面向特定领域的扩展。
我们今天来介绍在内部 DSL 设计上的一些探索和发现,主要分以下三部分:首先我们会介绍 DSL 和内部 DSL 的定义,同时讨论一下实现内部 DSL 有哪些惯用的“套路”;然后我们从三个业界案例出发,看看他们背后的动机以及是实现方案;最后我们有一些下一步的思考。
目录
DSL 的介绍/Introduction of DSL
# 什么是 DSL
DSL 是一种针对特定问题的编程语言,它含有建模所需的语法和语义,在与问题域相同的抽象层次上进行建模。如何理解这个定义呢?我们知道与 DSL 相对的是GPL(General Purpose Language,即通用编程语言),GPL 与 DSL 的对比,我喜欢用这两张与建筑材料有关的图来类比:GPL 就像水泥,用水泥可以构建出任意形状的建筑物或中间件,圆的,方的,直的,弯的;而 DSL 像是提前用水泥做好的“预制件”,我们可以直接使用“预制件”,而不用每次都从“搅拌水泥”开始,但“预制件”的用途的特定的,比如像图中的“预制件”更适合做管道,而无法比如做个楼板。

所以 DSL 具有以下特征:
-
有限的表达能力,你只能用它解决特定领域的问题
-
使用它提供的抽象,而不需关心底层细节
-
提供充分的表达能力,可以使不懂编程的用户理解程序的意图
从实现方式上,DSL 分为内部 DSL 和外部 DSL,我们今天主要关注内部 DSL,即 eDSL。
# 什么是 eDSL
即 embedded DSL,它将一种现有的通用编程语言作为宿主语言,基于宿主语言的基础设施(比如语法,编译器,工具等)建立专门面向特定领域的语义;相比之下,外部 DSL 具有完全独立的语法设计、编译器实现,以及工具配套。
eDSL 的优点是:
-
可复用宿主语言的语言特性,表达力强
-
可复用宿主语言配套设施(库生态,编译工具,开发环境等),构建门槛低
-
无缝嵌入到宿主语言工程中,可以方便的穿越 “Domain” 进行交互
在后面介绍的案例里我们会看到这些优点的具体呈现。这里只说一个“反面的”案例,曾经做过一个项目,选择外部 DSL 的方案,基本上站在这 3 点的对立面,我们在人力短缺的情况下,花了几个月时间才勉强把语言的编译器的基础框架搭起来,而这段时间我们本该用于结合客户需求更好的打磨我们提供的语法和抽象,另外由于其缺乏一些周边能力的配套,导致虽然我们设计的 DSL 有一些亮点,但无法支持真正的商用。当然语言工作台(Language workbench)可以帮助你更快的构建 DSL,但是那种方案有很多局限性,不在这里展开。
当然 eDSL 也有缺点:
-
语法设计受宿主语言能力的约束,可能会有“噪音”
噪音可以简单理解为,站在对问题描述或者建模的角度,某些语法是没有领域意义的,但为了遵守宿主语言的语法规范,使代码可以通过编译器的编译,而必须写的代码,通常是一些标点符号,关键字之类
-
DSL 的运行环境需要支持宿主语言的运行
在软件开发中(如下图所示),通常是库/框架/平台的开发者会定义 eDSL,面向下游用户提供的开发方式更具有领域特征,更友好,使用门槛更低;同时我们也看到,当下游开发者的开发方式混合了 DSL 与 GPL 的使用,就是说不能单纯的使用 DSL 来完成其业务实现时,采用 eDSL 方案是一个合理的选择。

从 DSL 实现角度,与外部 DSL 相比,其相同点是都要构建面向领域的语义模型,我把它理解为 DSL 的“灵魂”;而不同点是,外部 DSL 需要实现一个解析器,而内部 DSL 主要依赖宿主语言提供的语法和特性,这篇文章我们主要关注点是宿主语言的能力如何支撑我们去构建一门 eDSL。大家都是各自领域的专家,站在各自领域的角度可以去构建出语义模型,那么剩下的问题是,宿主语言通常提供什么公共的能力,让我们可以利用去描述我们的语义模型。

# 语言的“工具箱”
我们先看看工具箱里有什么工具可以用呢?(包括但不限于)
-
链式调用
-
命名参数/默认参数
-
宏
-
注解
-
语法“糖”
-
操作符重载
-
自定义操作符
-
属性机制
-
类型推导
-
面向对象OO
-
类型扩展
-
Collection literals
通常在构建一门 eD

本文探讨了领域特定编程语言(DSL)的设计,尤其是内部DSL(eDSL)的实现和优势。通过案例分析,如Pulumi、Chisel和SwiftUI,展示了DSL如何在基础设施代码、硬件构造和声明式UI中提高效率。文章指出,eDSL利用宿主语言特性,如链式调用、宏和注解,实现领域特定的抽象和语法,但也需要平衡与宿主语言的边界,控制语法设计。作者提出,DSL的设计不仅涉及API美化,还涉及开发约束和领域信息的提取,同时强调了在设计中考虑工具支持和学习曲线的重要性。
最低0.47元/天 解锁文章
577

被折叠的 条评论
为什么被折叠?



