OOP和函数编程的区别
表格:行是operation,列是variant
函数编程:
每个operation都是一个函数,每个函数都有若干branch,每个branch都对应一个variant
定义datatype,每个variant都对应一个constructor
面向对象编程:
定义一个基类,每个operation是一个类函数,基类中的函数是抽象的
每个variant是一个子类,并且实现所有的抽象函数
问题一:如果有函数带有多种类型的参数?
函数编程:
通过wildcard pattern + helper function + case语句
面向对象编程:
Double Dispatch
Double Dispatch
将需要知道对方的类 转化成 调用对方的函数
第一次分配:variant类应该知道自己如何做一个operation=>如Int类型就应该调用arg.add_int(self)
第二次分配:对方的add_int知道应该如何将自己和int相加
调用栈:
add(a, b)
a.add_values(b)
b.add_A的类型(a自己)
b正确处理
Multiple Dispatch
每个add_values都有自己对应的参数类型,类里会有多个add_values
当调用a.add_values(b),将会在运行时挑选出A中接收B类型的参数的add_values, 直接调用
注意:Java和C++的static overloading虽然也能根据参数类型挑选对应函数,但是是编译期决定的,并不是运行时决定的。
多重继承:可能会在fields和methods上有冲突
C++是支持多重继承的+abstract method
Ruby运行有一个直接的基类和多个mixin
Java支持一个直接的基类和实现多个接口
Mixin
类似接口,类能include mixin, 但是不能直接实例化mixin。
minxin不能有instancevariable
定义:module M … end
使用:class A < B
include M
end
Ruby自带的mixin: Enumerable(实现each方法)和Comparable(实现<=>方法)
Abstract method和high-order function的相同之处:
都可以先定义一个框架,由client实现其中的细节。
Abstract method是通过override函数实现的
High-order function是通过传入函数实现的
Polymorphism:
ML中:parametric polymorphism / generics
Ruby中:subtype polymorphism / subtyping
Generic和Subtyping:
Generic适用于 可以是任何类型的参数,但必须是同一个类型 的情况
Subtyping适用于 有extra fields的对象的代码重用 的情况
Bounded Polymorphism:
Generic + Subtyping
对于depth subtype如List,可以使用List<T extend A>,这样可以修改List的内容,替换成其他的T,但是注意,都是同类型的。
Subtyping:
让一个类型{f1:t1, f2:t2...}也是类型{f2:t2…}。前者是subtype,subtype拥有更多的信息。
t1 <: t2: t1是t2的subtype。
如果e是t1,那么e也是t2。t2可以理解成父类,t1是子类,子类能拥有更多的field,且子类是基类
任何使用t2的地方都可以使用t1(t1是t2,但是t2未必是t1)
Depth subtyping:
如果t1<:t2, 不能让 t3 : {f1:t1} <: t4 : {f1:t2}
原理:如果有函数将x.f1 = t2,那么就会造成t3.f1 = t2。但是如果通过t3.f1去取t1比t2多出来的fields就会报错。
当有赋值的时候,depth subtyping就会出现field丢失的情况。
因此Java禁止赋值一个t1类型的数组内容为t2,但是允许depth subtyping
所有类型都可以看做是Null的subtype,所以Java中也会在运行时检查Null
Function subtyping:不是如何调用函数,而是函数本身的委托
如果 ta <: tb,则函数t->ta <: t->tb。能返回更多fields(promise more)的函数可以替换。return type: covariant(works the same way)
如果 ta <: tb,则函数tb->t <: ta->t。需要更少fields(need less)的函数可以替换。argument type: contravariant(works the oposite way)
除了self/this这个参数,由于实现问题必须是subtype,不能使contravariant的
OOP中的subtype:
因为field能够修改,所以subtype的field类型不能改变(原因参照depth subtyping)
因为methods不能修改,所以subtype的methods能够使用supertype对应函数的subtype
Subclass和subtype不同:
class:定义了对象的行为,子类通过继承并extend/override这些behavior
type:定义了对象的类型和能够响应的消息,子类型是为了替换父类型并且防止发生错误。