「翻译」The Expression Problem and its solutions
编程这门技艺几乎总是与不同类型的数据以及作用于这些数据的操作/算法相关联[1]。因此,如何为数据类型和操作设计抽象,“自古以来”就一直是软件工程师和编程语言设计者们苦苦思索的核心问题。 然而,我最近才偶然得知一个我在职业生涯中多次遇到的软件设计问题,它原来是有名字的。这个问题是如此基础,以至于我惊讶于之前竟然从未见过它被命名。下面是一个简要的问题陈述: 想象一下,我们有一组数据类型和一组作用于这些类型的操作。有时,我们需要添加更多操作,并确保它们在所有类型上都能正常工作;有时,我们需要添加更多类型,并确保所有现有操作都能在它们上正常工作。但有时,我们需要同时添加这两者 —— 而问题就出在这里。大多数主流编程语言都没有提供很好的工具,让我们能够在不修改现有代码的情况下,向一个已有系统同时添加新类型和新操作。这被称为「表达式问题」(Expression Problem)。研究这个问题及其可能的解决方案,可以深刻洞察面向对象和函数式编程之间的根本差异,以及接口 (interfaces) 和多重派发 (multiple dispatch) 等概念。 就像我一贯的套路,我的例子来自编译器和解释器领域。不过,我要为自己辩护一下,这也是一些关于「表达式问题」的经典历史文献中所用的例子,正如我在下面历史回顾部分所详述的。 想象一下我们正在设计一个简单的表达式求值器。遵循标准的解释器设计模式,我们有一个由表达式组成的树形结构,以及一些可以对这些树进行的操作。在 C++ 中我们会定义一个接口,表达式树中的每个节点都必须实现它: class Expr { public: virtual…