`
edge
  • 浏览: 66771 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Scala概述(六)合成(2)

阅读更多

 

成员(Membership

如前所示,Iter 类从StringIteratorRichIterator 同时继承了类成员(members )。简单而言,一个类从以混入合成方式继承Cn with … with C1 ,将会继承其中所有类的成员,同时还可以自定义新的成员。由于Scala 保留了JavaC# 的静态重载机制,因此可能从父类继承同名的方法,也可以再定义同名的方法[1] 。为了判断类C 的一个方法到底是覆盖父类中的同名方法,还是这两个方法并存——即重载的关系,Scala 采用了匹配(matching )法,这也是从JavaC# 中类似的概念衍生来的:简单地说,如果两个类成员同名,并且具有相同的参数类型(如果两个都是方法),就称之为相匹配。

一个类的成员总共两种类型:具体和抽象的,每种类型分别对应一个判定规则:(注:下面几段是说明Scala 语言判断类成员属性的内部机制,不关心这方面细节的可以忽略)

一个类C 的具体成员是指其或其父类的所有具体声明M ,除非在其某个父类(也就是在L(C) )中已有一个匹配的具体成员。

一个类C 的抽象成员是指其或其父类的所有抽象声明M ,除非在C 中已有一个匹配的具体成员,或者其某个父类(也就是在L(C) )中有一个匹配的抽象成员。

这些规则同样决定了一个类C 与其父类之间匹配成员的覆盖关系。首先,具体成员一定覆盖抽象成员。其次,如果MM’ 同为具体成员或抽象成员,且MC 的全序化当中出现在M’ 之前,则M 覆盖M’

 

父类调用(Super Calls

我们考虑设计一个同步迭代器,也就是其操作在多线程之间是互斥的。

trait SyncIterator[T] extends AbsIterator[T] {

abstract override def hasNext: boolean =

synchronized(super .hasNext)

abstract override def next: T =

synchronized(super .next)

}

想要构造一个针对StringRich 、同步迭代器,可以用这三个类进行合成:

StringIterator(someString) with RichIterator[char]

with SyncIterator[char]

这个合成类从SynchIterator 继承了hasNextNext ,这两个方法都是对其父类的相应方法调用加了一个sychronized() 包装。

由于RichIteratorSyncIterator 定义的方法相互不重合(注:原文是RichIteratorStringIterator ,应该有误),因此它们出现在mixin 中的顺序没有影响,即上例写成这样也是等价的:

StringIterator(someString) with SyncIterator[char]

with RichIterator[char]

 

但是,这里有一个小细节要注意:在SyncIterator 中的super 这个调用并不是静态地绑定到其父类AbsIterator 上,因为显然这是毫无意义的,AbsIterator 定义的nexthasNext 都是抽象方法。实际上,这个super 调用实际上指向这个mixin 合成中的superclassStringIterator 的相应方法。从这个意义上讲,一个mixin 合成的superclass 覆盖了其各个mixin 当中静态声明的超类。这也就意味着super 调用在一个类当中无法被静态解析,必须延迟到一个类被实例化或被继承的时候才能解析出来。这一概念有如下精确定义:

假设CD 的父类,在C 当中的表达式super .M 应该能够静态解析为C 的某个父类当中的成员M ,这样才能保证类型正确。而在D 的语境中(context ,我将其翻译为语境,而不是通常人们翻译的“上下文”。这个问题说来话长,有机会的话会变成一篇文章甚至一本书——译者在这里顺便贩卖一下私货),这个表达式应该表示一个与M 相匹配的M’ ,这个成员应该在D 的全序当中位于C 之后的某个类里定义。

最后注意一点:在JavaC# 等语言中,上述SyncIterator 当中的这种super 调用明显是不合法的,因为它会被指派为父类当中的抽象成员(方法)。如同我们在上面看到的,这种构造在scala 中是合法的,只要保证一个前提,那就是这个类所出现的语境当中,其super 调用所访问的父类成员必须是具体定义了的。这一点是由SyncIterator 当中的abstractoverride 这两个关键字保证的。在scala 中,abstract override 这两个关键字成对出现在方法定义中,表明这个方法并没有获得完全的定义,因为它覆盖(并使用)了其父类当中的抽象成员。一个类如果有非完整定义的成员,它自身必须是抽象类,其子类必须将这些非完整定义的成员重新定义,才能进行实例化。

super 的调用可以是级联的,因此要遵从类的全序化(这是 Scala 的混入合成方式与多重继承方式之间最主要的差异)。例如,考虑另一个与 SyncIterator 类似的类,它将其返回的每个元素都打印到标准输出上:

trait LoggedIterator[T] extends AbsIterator[T] {

abstract override def next: T = {

val x = super .next; System.out.println(x); x

}

}

我们可以将这两种迭代子( sychronized logged )通过 mixin 组合在一起:

class Iter2 extends StringIterator(someString)

with SyncIterator[char]

with LoggedIterator[char]

在这里, Iter2 的全序化是:

{ Iter2, LoggedIterator, SyncIterator,

StringIterator, AbsIterator, AnyRef, Any }

这样一来, Iter2 next 方法继承自 LoggedIterator ,而该方法中的 super.next 则指向 SyncIterator next 方法,而后者当中的 super.next 则最终引用 StringIterator next 方法。

如果想对记录日志的动作进行同步,仅需要把两个 mixin 的顺序反过来即可实现:

class Iter2 extends StringIterator(someString)

with LoggedIterator[char]

with SyncIterator[char]

无论哪种情况, Iter2 next 方法当中 super 的调用都遵循其全序当中的父类顺序。



[1] 有人可能反对这种设计方式,认为这样太复杂,但是为了保证互操作性,这样做是必须的,例如一个 Scala 类继承一个 Java Swing 类的时候。

分享到:
评论
4 楼 bneliao 2009-08-06  

不知道martin引入self type和super的初衷是为了解决什么问题?

感觉用了self type和super以后,this和super的使用很不确定;不是很直观,有些难以理解
3 楼 edge 2009-08-03  
dcaoyuan 写道
引用
全序的引入固然使之在语法上的精确性得到保证,但对于编程者而言,在某些时刻如果不计算出全序的结果,甚至不知道到底继承了哪个方法。

好在Scala对方法本身的静态类型定义和检查,在IDE中,你可以Mouse over或Click调用的方法名,马上得知哪个方法被引用。

引用
反之,你写下一个可以被继承的方法时,甚至可能要考虑到如何被人继承才有更好效果/更不容易出现问题。

对Trait的使用,目前还需要更多的实际应用来判断适合的情景。以我观察Martin本人在Scala的API编程中,trait首先被当作Java中的interface使用,其次,在compiler库中,大部分情况下,trait中很少包含方法,而是被用做mixin class/object的容器,就是说,包含的是子类和Object。


嗯,没错,其实这个问题我表达的不太精确,应当主要是针对trait的。我这两句话一起说,就是针对文章当中这个例子。可以看到在trait当中如果还要包含super.XXX这类逻辑,在trait本身的design time是无法知道super的具体引用的,反之他被如何继承也无法知晓。因此是否应该在trait当中包含这样的逻辑,或者说具体应该包含什么逻辑,是存在着最佳实践的概念的,也就是还需要实践和摸索。

dcaoyuan 写道
当然,我们首先强调,复杂的手段应该主要由API的设计者使用。


这就是我后面的担忧中说的问题了,语言的设计者固然可以有这样的初衷或者(头脑中隐含的)限制,但是对于使用者而言,要他们时刻想着“应该在构建组件时使用一些复杂手段,解决普通编程需要时使用一些内建的便捷特性”,很容易造成一定程度的困惑,最终会导致这种语言的使用者被人为地(其实是自然地)划分为不同的群体,无法构成一个非常良好的社区。在我看来C++的现状就是这样形成的,对于语言的设计者而言有种悲哀的味道。
2 楼 dcaoyuan 2009-08-03  
引用
全序的引入固然使之在语法上的精确性得到保证,但对于编程者而言,在某些时刻如果不计算出全序的结果,甚至不知道到底继承了哪个方法。

好在Scala对方法本身的静态类型定义和检查,在IDE中,你可以Mouse over或Click调用的方法名,马上得知哪个方法被引用。

引用
反之,你写下一个可以被继承的方法时,甚至可能要考虑到如何被人继承才有更好效果/更不容易出现问题。

对Trait的使用,目前还需要更多的实际应用来判断适合的情景。以我观察Martin本人在Scala的API编程中,trait首先被当作Java中的interface使用,其次,在compiler库中,大部分情况下,trait中很少包含方法,而是被用做mixin class/object的容器,就是说,包含的是子类和Object。

当然,我们首先强调,复杂的手段应该主要由API的设计者使用。
1 楼 edge 2009-08-02  
Scala在对象体系方面的语法,到这里基本上完全展开了,大家可以看到其复杂性的特点以及其发明者这样设计的一些初衷。迄今为止的内容可以看到,scala的很多语法特性确实符合其创造者的预期,那就是它非常适合于编写精心设计的模块/组件,然后让别人去使用或者扩展。这一点上次和草原也深入讨论过,他也在考虑用scala写一些DSL性质的东西,与我的观点算是殊途同归吧。

我感觉这样的一个语法体系,其利弊尚难准确评判。举个例子而言:Scala中的继承这一概念,完全超出了直观的范畴,全序的引入固然使之在语法上的精确性得到保证,但对于编程者而言,在某些时刻如果不计算出全序的结果,甚至不知道到底继承了哪个方法。反之,你写下一个可以被继承的方法时,甚至可能要考虑到如何被人继承才有更好效果/更不容易出现问题。

不仅如此,scala的语法在不同的角度/维度体现出的特性,也存在着隐忧。比如说其scriptable的性质,也是很为martin所“炫耀”,但与前述这些对象体系并没有什么特别必然的内在联系。这不由得让我想起了BS所宣扬的C++的宗旨:multi paradigm programming,而C++的现状,也皆源于此。这样看起来,scala快要变成VM模型下的C++了,其前景也因此变得难于预测。

相关推荐

    Scala 概述(瑞士洛桑联邦理工)

    Scala 概述(瑞士洛桑联邦理工) Scala 概述(瑞士洛桑联邦理工)

    Scala程序设计第2版

    Scala程序设计第2版 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。

    scala课件.zip

    Scala概述.pptx 变量.pptx 运算符.pptx 程序流程控制.pptx 函数式编程基础.pptx 面向对象编程(基础部分).pptx 面向对象编程(中级部分).pptx 面向对象编程(高级特性).pptx 隐式转换和隐式参数.pptx 集合(上)-基本使用...

    scala netbeans 插件(2)

    scala netbeans 插件(2)scala netbeans 插件(2)scala netbeans 插件(2)

    m2e-scala.zip

    Eclipse Scala环境的配置 https://yanxml.blog.csdn.net/article/details/89250222 配套的下载资源. http://alchim31.free.fr/m2e-scala/update-site/ 这个地址被墙了.上传,方便大家离线安装`m2e-scala`.

    Scala函数式编程

    2 scala很多库在设计的时候,不理解原因,包括Option,Collection的很多看似有冗余的地方 3 很多scala的默认写法,不理解 4 多态的具体化,尤其是协变的意义所在 5 各种重载的符号使用 之前读过 programming in...

    scala sdk scala-2.12.3

    scala-2.12.3 scala-2.12.3 scala-2.12.3 scala-2.12.3

    Programming in Scala 2nd Edition 英文版

    《Scala编程》介绍了一种新的编程语言,它把面向对象和函数式编程概念有机地结合为整体,从而形成一种完整统一、语义丰富的新思维体系。《Scala编程》循序渐进,由浅入深,经作者精心组织、仔细编排,将语言中的各种...

    Programming in Scala 2nd Edition

    Programming in Scala 2nd Edition

    Scala for Machine Learning(2nd)_Code 源码

    Scala for Machine Learning(2nd)_Code 源码 第2版 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    mainecoon, 在 Scala 中,变换并合成tagless最终编码代数.zip

    mainecoon, 在 Scala 中,变换并合成tagless最终编码代数 Mainecoon是一个小型库,用于转换和编写tagless最终编码代数。安装Mainecoon在 Scala 2.11,2.12和scalajs上可用。 宏注释使用 scalameta插件开发,因此在你...

    scala-sbt-scala编译工具

    scala 编译工具 sbt 安装包。 Little or no configuration required for simple projects Scala-based build definition that can use the full flexibility of Scala code Accurate incremental recompilation ...

    Scala 程序设计(第2版)

    Scala 程序设计(第2版)

    Scala编程实战.zip

    此文档是讲解实战Scala,希望对喜欢大数据的同学有所帮助!!! 学习Scala语言,不仅仅意味着熟悉新的API,更重要的是一种思维方式的转变。从原有的面向对象编程(OO)到函数式编程(FP)的思想。本书面向实际的使用场景...

    scala2.12.1Windows镜像包

    scala2.12.1Windows镜像包

    scala3 scala3 scala3 scala3 scala3

    scala3 scala3 scala3 scala3 scala3

    scala编程中文pdf

    scala编程 33章 中文pdf Scala编程实战 目录 第1章字符串. 11 第2章数值39 第3章控制结构.60 第4章类和属性.103 第5章方法147 第6章对象170 第7章包和导入.190 第8章特质200 第9章函数式编程214 第10 章集合242 第...

    scala五本经典资料集合

    scala是一个经典的语言,Scala代表了一个新的语言品种,它抹平了这些人为划分的界限。但是现在scala的相关学习资料不多,因此,本人总结了几篇写的较好的scala学习资料,包含<ScalaQuery_Commerzbank_2011><twitter-...

Global site tag (gtag.js) - Google Analytics