[Dart翻译]在Mirror里寻求Closure

原文地址:gbracha.blogspot.com/2012/07/see…

原文作者:gbracha.blogspot.com/

发布时间:2012年7月23日

在过去的博客讲座中,我曾多次讨论过基于镜像的反射。当然我也不是唯一的一个–你可以阅读Alan Wirf-Brock关于Javascript中的镜子的帖子。在这篇文章中,我想关注一种特殊的镜子,它没有得到很多关注。在我深入了解细节之前,先说说背景。

你无法了解一个函数的内部结构:你只能把它应用于各种参数,看看它是如何反应的。这有时被称为程序性抽象。在其他方面,它是基于对象的封装的基础。

大多数自称为面向对象的语言实际上并不支持基于对象的封装。尽管有这个缺陷,他们的方法之一是直接依赖程序性抽象。这方面最明显的例子也许是Javascript。在Javascript中封装任何东西的唯一方法是把它放在一个函数中。精心设计的模式利用Javascript的闭包来提供封装。

你可以从上面看到,程序性抽象是绝对的基础。在有些情况下,我们可能还是希望突破程序性抽象的防线。

考虑以LINQ、Ruby on Rails或Glorp的风格实现一个数据库接口。底层模型是数据库由集合组成,这些集合通过标准的功能操作(如filter、map、reduce等)被访问。 这些操作的参数包括闭包。例如,你可以写一个查询,如。

cities.filter(function(city){return city.name = ‘Paris’;});
复制代码

并得到一个包括巴黎、德克萨斯以及其他一些城市的答案集合。为了在数据库上实现这个接口,你可能想把这段代码转换成SQL查询。 要做到这一点,你需要理解闭包的作用。例如,在.Net中,类型系统被设计为将字面闭包强制转化为代表其内部表达式的抽象语法树,然后可以将其编译为SQL。

当然,你可能根本无法合理地将代码编译成SQL查询。 我们将假设系统允许在任何它认为太难的情况下失败,但我们希望能尽可能多地应对各种情况。

LINQ的方法依赖于静态类型,但这并不是必须的,而且事实上还有缺点。
例如,静态方法排除了以下情况。

query(f) {return cities.filter(f);}
复制代码

一个更普遍的选择是动态地推导出闭包体的AST。不管怎么说,我似乎需要一种方法来获取闭包的AST(或者至少是源)–程序性抽象当然是为了排除这种情况。

即使我可以得到源码或AST,这也不一定够。假设我想写

var cityNames = [‘Paris’, ‘London’, ‘New York’];
cities.filter(function(city){
    return cityNames.contains(city.name)
});
复制代码

我需要cityNames的值,以便执行查询。 一般来说,我需要获取执行中的闭包的范围。

Smalltalk和它的亲戚允许你这样做。它们是如何绕过程序性抽象的呢?好吧,就闭包而言,它们基本上把程序性抽象扔到了门外。每个Smalltalk闭包都会很乐意为你提供它的上下文,也就是一个统一的范围,它可以让你找到闭包中使用的所有变量。

很明显,这不是一个非常安全的解决方案。我们通常可以通过镜像来调和安全和反射,这也是这篇文章的重点。 给定一个能够完全访问闭包对象表示的对象镜像,你应该能够得到你需要的所有信息。 这仍然有一个缺点,即闭包的表示法是作为公共API暴露的。

在这种情况下,我们需要一个ClosureMirror。从本质上讲,需要有一个具有神奇能力的对象来观察闭包,克服程序性的抽象。 闭包本身不允许这样做;它必须是不可穿透的。观察内部的能力必须是一个独立的对象,可以独立地分发或扣留(给读者的练习:找到另一种方法来解决这个问题)。

具体来说,ClosureMirror需要能够提供它所反映的闭包的源代码以及描述闭包当前范围的从标识符到值的映射。

另一种闭包镜像会很方便的情况是序列化。如果你需要序列化一个包含闭包的对象,你同样需要访问闭包的范围。

我没有看到其他地方讨论过封闭镜像。据我所知,唯一的实现是作为Newspeak到Javascript编译器的一部分。我们也在考虑在Dart镜像系统的背景下实现它。 Newspeak-on-Javascript对封闭镜像的实现是相当天真和低效的。 这种低效的原因之一是Javascript没有提供任何支持来做这种事情。无论如何,这个想法是新的,几乎没有经过测试,但我认为它有潜力。

作者:Gilad Bracha 发表于10:17 PM
标签。新闻语言, 反思


www.deepl.com 翻译

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享