静态类型系统如何影响基于原型的语言的设计?


15

基于原型的语言维基百科文章包含以下内容:

几乎所有基于原型的系统都基于解释型和动态类型化的语言。但是,基于静态类型语言的系统在技术上是可行的。

静态类型系统以什么方式对基于原型的语言施加限制或引入复杂性,为什么会有更多动态类型的原型语言?


2
+1和最喜欢:我已经思考了很长时间,并且没有发现结构类型系统存在任何异常困难的问题。实际上,这让我感到非常困扰,以至于我想继续前进,并尝试创建一种基于静态类型的基于原型的语言,只是为了看看存在什么问题……

我刚刚出于同样的原因开始自己的过程:)

Answers:


6

基本类型和对象之间的边界是模糊的,通常是人为引入的。例如,在C中,结构只是一堆记录,只是一个派生的非对象类型。在C ++中,结构是具有所有公共字段(一个对象)的类。尽管如此,C ++几乎完全与C向后兼容...这里的边界确实很柔和。

对于基于原型的编程,您需要在运行时使对象可变。它们必须是软类型的,因为每种类型都会在运行时更改,一种类型的类会更改为另一种类型-它的类型也会更改。

您可以将基本和派生的非对象类型保持为静态。但这引入了怪异的差异,对象是软类型的,非对象是静态类型的,并且必须在两者之间建立硬屏障。您应该能够变形结构吗?弦吗?Number应该是一个类或基本类型,还是一组基本类型,例如int / float / bignum / etc?

统一,所有类型都是可变的或在运行时没有类型是可变的,这是更自然,更容易学习,使用和编写的。如果您只声明一种类型(对象)是可变的,那么您将面临着两个世界的头痛和麻烦。

静态类型为:

  • 易于实施
  • 更快/更高效
  • 更安全
  • 由于抽象,易于维护/记录大型系统。

动态类型为:

  • 写得更快
  • 更简洁
  • 语言更容易学习
  • 更宽容的设计错误。

通过将两者融合在一起,您可以牺牲很多。

  • 实施变得比前两个困难。
  • 速度取决于您是否使用软类型...如果您使用软类型,则速度很慢;如果您不使用软类型,为什么还要选择语言?
  • 对于所有对象类型,类型安全性是不可用的。
  • 跟踪一种类型如何转变为另一种类型是一项非常艰巨的任务。记录它-非常困难。
  • 您仍然需要使用基本类型进行所有簿记,这会破坏简洁性和书写速度
  • 语言复杂度比任何“特定”语言都更高(更难学习),
  • 动态类型的“宽容”被趋向于在属性类型不匹配时出现一些非常棘手的错误。

1
介意提供一个示例,说明为什么对象需要“可变”的(我假设您的意思是添加和删除属性,而不是更改属性,因为这通常与键入无关)。

@delnan:并非如此,在基于原型的编程中,您可以根据实际实例对对象和方法进行适当的挖掘,删除,添加,替换,覆盖,从而挖掘对象的内胆。这就是重点,它是通过经典继承的严格规则来修改对象的非常方便,灵活的替代方法。如果一种语言将类用作类型,则如果类型不是软类型,则不能即时修改其结构。
SF。

1
我不这么认为。按照同样的逻辑,人们可能会说基于类的编程需要与基于动态的基于类的语言所允许的自由度相同的自由。不可以,具有结构类型系统的静态原型会使用其成员列表并递归地注释对象,并通过要求所有成员在创建对象时给出所有成员或存在于对象中来静态检查这些成员是否存在(并具有正确的类型)。原型,只是不包括删除成员的方法。在我看来,结果仍然是相当不错的原型,并确保每个成员始终存在。

@delnan:您刚刚通过合成描述了经典继承。是的,它看起来很原始,并且是一种(非常讨厌)用经典继承模型语言进行基于原型的编程的方法。它只会剥夺pb.p的90%的乐趣,从而扼杀了其最大的优势(同时消除了最大的危险)。是的,按照以前的脚踏射击类比,功能齐全的pb.p可以帮助您用茶匙拍打双腿。如果您不喜欢这种功能,则最好坚持经典继承。
SF。

1
您将“动态”与“原型”混淆了。这些无法与静态类型系统很好地融合在一起的自由并不是原型的特征,而是动态性的特征。当然,添加静态类型可以阻止它们,但是它们不是原型的一部分(IMGO主要缺少类,而倾向于克隆对象以充当父类)。这种动力与原型正交。所有流行的原型语言都碰巧包括了它们,但是它们独立于原型,如前所述。考虑以下虚构语言的片段:pastebin.com/9pLuAu9F。它不是原型吗?

3

看到的困难非常简单:将对象视为方法的字典或响应消息的事物,请注意以下有关常见的静态类型的OO语言的内容:

  • 通常,所有字典键/消息都是使用静态声明的标识符预先声明的。

  • 预先声明了某些消息集,并且将对象与这些集合关联以确定它们响应的消息。

  • 一组消息是另一组消息的子集的包含关系被静态且显式声明;未声明,但逻辑子集无效。

  • 类型检查尝试确保所有消息仅发送给响应它们的对象。

这些冲突中的每一个在某种程度上都与基于原型的系统冲突:

  • 可以预先声明消息名称,形式为“原子”,插入字符串或其他形式,仅此而已;对象的可塑性意味着将类型分配给方法很麻烦。

  • 可以说,这是基于原型的系统的基本功能,即消息集是由对象的响应定义的,而不是相反的。在编译时将别名分配给特定组合是合理的,但是在运行时确定的消息集必须是可能的。

  • 以上两个因素的真正影响在于包含关系,其中显式声明是完全不可行的。静态,名义子类型意义上的继承与基于原型的系统相反。

这给我们带来了最后一点,我们并不真的想改变。我们仍然希望确保仅将消息发送到响应它们的对象。然而:

  • 我们不能静态地知道哪些消息可以组合在一起。
  • 我们不知道哪些分组是其他分组的子集。
  • 我们不知道可以进行哪些分组。
  • 我们甚至无法指定将哪种类型的参数与一条消息一起发送。
  • 基本上,我们发现在完全普通的情况下根本无法指定任何内容。

那么如何解决呢?要么以某种方式限制全部通用性(这是令人不愉快的,并且可以首先扼杀使用基于原型的系统的任何好处),要么使类型系统更加灵活并表达约束而不是确切的类型

基于约束的类型系统很快导致了结构子类型的概念,在非常宽松的意义上,可以将其视为“鸭子类型”的静态等效项。这里最大的障碍是这种系统的类型检查要复杂得多,并且知名度也较低(这意味着很少要研究的工作)。

总结:有可能,它比标称静态类型系统或基于运行时元数据的动态系统难做,因此很少有人在意。


1

我相信实现静态类型的,基于原型的语言的一种方法是使该语言基于“模板和概念”。

概念曾经是C ++ 0x的计划功能。实际上,C ++模板中的通用代码已经是“静态鸭子式的”。Concepts的想法是能够说出有关所需成员和类型特征的一些信息,而无需或暗示该关系所基于的类继承模型(因为它必须与已经“静态转换为鸭子”的现有模板代码一起使用) )。

使用完全基于模板和概念的语言,这将是基于原型的概念,并且模板将使您不必担心任何可能用于或可能不用于实现值类型的类模型。

除了使用分阶段编译使该语言成为其自身元语言的技巧外,这些概念的原型派生一旦创建就必然是不可变的。但是,反对不是基于原型的说法是“红色鲱鱼”。它只是一种功能语言。至少已经尝试了一种具有动态功能且基于原型的语言。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.