所有东西都是一个X

2020-11-14 16:57:52

“一切都是X”是一种非常高级的模式,你可以看到它应用于许多系统的设计中,包括编程语言和用户界面。它有很多优点,但也有一些缺点。我将讨论其中的一些,然后看一些例子,这些例子对于理解我真正在说什么是必要的。

当我们在这里说“一切”时,我们说的是非常松散的--事实上,系统中的许多东西不是“X”的实例,而是一些更低级别的东西,或者只是完全不同的东西。“Everything is a X”的真正意思是“这个系统中有令人惊讶的数量的东西都是X”。

这使得API的工作方式具有一定的统一性,这往往会减少您在学习新的API库时必须做的工作量。

就元级别而言,Java没有那么多。它有一些反射能力,允许将类表示为运行时对象,尽管它提供的内容不是很深入(对比下面的Python)。

然而,用户有限的能力对编译器编写人员来说无疑是有用的--由于Java语言的局限性(同样,下面对比一下Python),您可以在Java中获得出色的性能。

Java打破了自己将所有东西都建立在带有“primitivetype”的类上的模式,这意味着你还必须处理装箱、自动装箱等问题。Javascript在Number方面也有类似的问题。

请注意,这与Java版本的“一切都是类/对象”有很大不同--更多的东西实际上是Python中的运行时对象,包括函数、方法、类型/类和模块,以及类的实例。这使得参数化成为了Python中一种非常强大和通用的模式。

所以元类编程只是普通编程。它可以在REPL中完成,也可以使用您已经学习过的任何其他技术来完成。使用元课程当然需要学习新的东西,但事情仍然以非常熟悉的方式运作。Python给人的感觉就像是从Python一直往下做的。

我们也看到了不利之处。例如,Python整数是完全的PythonObjects,与紧凑的表示形式(比如C将使用的,或者Numpy使用的)相比,这是非常浪费内存的。此外,它们是不可变的(有充分的理由),所以进行简单的加法可能会导致内存分配。从效率的角度来看,这是相当可怕的!

[修正取决于实现;CPython缓存-5到255之间的整数,并进行了一些其他优化,但在对象大小方面仍有很大开销]。

例如,没有if语句,而是一个if表达式。赋值实际上也是表达式--例如,let语句是定义一些局部值并返回主体的值的表达式。

例外:顶层分配和类型签名。至少在哈斯克尔,类型系统感觉相当独立。正因为如此,AFAICS在Haskell中缺少元级别。Haskell的“超能力”来自一系列不同的特性,比如派生和模板化Haskell,以及类型级编程,特别是使用各种语言扩展。这些都是很酷的功能,但它们必须单独学习,我认为这就是哈斯克尔给人一种庞大而令人生畏的语言的感觉。

与Haskell不同的是,它走得更远,包括最高级别的声明。这种统一的语法对编写宏非常有帮助,这可能是Lisp引以为豪的最大元能力。

这是Emacs的一个重要想法--它几乎没有什么不同的用户界面元素,因为几乎所有的东西都出现在一个缓冲区中。除了要编辑的文件文本外,您还需要:

搜索结果(这是我记住上下文的递归搜索工作流程的重要组成部分)。

一旦你学会了如何导航和使用缓冲区,你就知道如何导航这些东西了。

当然,还有其他的用户界面元素,比如工具栏和菜单栏,让Emacs对新用户来说不那么可怕。但这些往往会被有经验的用户拒之门外--它们不是很有用,因为…。他们不是缓冲器!

你也获得了元能力:所有缓冲区的列表当然是一个缓冲区,你可以使用正常的机制来操作缓冲区-缓冲区(例如,删除行可以杀死一个缓冲区)。

在PostgreSQL等一些实现中,以及您创建的普通关系中,内部结构也以关系的形式呈现,包括表/关系/索引的列表,以及运行时信息。

还有很多其他的东西。这些功能得益于SELECT的所有常见功能,如联接、过滤、排序等。

如果扩展了元能力,可以通过在“表”中插入/删除表来创建/删除表,并通过操作“列表”来类似地添加/删除/更改列。然后,你的模式就变成了数据,你的力量就变成了超能力。我不知道是否有数据库实现了这一点,或者它的优点是否真的比普通的DDL更有吸引力。

在某种程度上,这似乎比PostgreSQL在给你元能力和坚持模式方面走得更远。除了正常的数据报表外,还有:

我喜欢Visidata的强大功能,它基本上就是“Excel作为文本用户界面”,我意识到它的很多功能都来自于它的不足。

在Excel中,您可以在一个工作表中包含多个表,并将它们放在您喜欢的任何位置。你可以有页眉,也可以没有页眉,你可以为每个单元格设置不同的格式或数据类型等。在Visidata中,每个工作表只有一个表格,你必须有标题,每列只有一种数据类型等等。“一切都是工作表(并且工作表有严格定义的结构)”的强制一致性实际上是使Visidata在许多任务上比Excel更好的关键--没有它,大多数界面快捷方式和元功能都不会失败。

系统中的所有东西都是“资源”的想法,你可以用几个容易理解的动词(GET、PUT、DELETE等)来操纵。是真正吸引人的休息的一部分。

它附带了一些元功能--像OpenAPI这样的东西,资源列表通常也是作为一种资源来服务的。

相对频繁地使用REST,我觉得我遇到了“不合适”的缺点。将某些操作建模为“操纵资源”非常奇怪,您真正想要的只是一个RPC(例如,使用“克隆/复制/移动”操作,其中有一些您也希望处理的隐藏属性)。

这是一个相当成功的抽象,但它确实泄露了一些信息-例如,stdout和stdin都是“文件”,但当它们是终端时除外,您通常希望将它们作为特例,因为当它们有人类坐在它们前面时,它们实际上并不太像文件。而且,事实证明,文件比你想象的要难得多,甚至在你开始把不是文件的东西当作文件之前也是如此。在某些情况下,您可能希望处理文件,就好像它们不是文件,而是内存一样(Mmap)。

我相信这种模式的例子还有很多很多,我只是触及了皮毛。例如,c2.com上的EverythingIsa有一个更长的名单,但没有太多的分析。你最喜欢的例子是什么?有没有这样做效果很好的例子--或者非常糟糕的例子?有没有其他我没有错过的优点/缺点?