动态类型+面向对象 = shit
1.动态类型
动态类型语言,属于看起来方便,用后麻烦的东西,我不喜欢它们。除非不需要考虑软件工程场合——如作为脚本语言。
动态类型+高阶函数,使得Scheme定义的op非常强大,如同酒驾的司机,非常狂野。
(define (op a b how-op)
( how-op a b) )
op可以对两个参数a,b进行“某种”how-op操作后返回一个值。然而,如果不看op的实现,应用程序员就不可能知道how-op应该是什么样的函数,也不知道op将返回什么结果。在当前实现下,应用程序员仅仅知道how-op有两个参数,how-op的返回值即op的返回值。
如果op实现如下
(define (op a b how-op)
(and (how-op a) (how-op b) ) )
那么,应用程序员仅仅知道,how-op有一个参数,返回值为布尔值,op的返回值也为布尔值。可以应用如下:
(op 1 3 (lambda(x)(> x 0))) ;;
(op #t #t (lambda(x) x)) ;;;
Scheme定义的函数,应用程序员无法脱离实现而仅仅了解其接口,或者说,Scheme程序不可能遵循接口与实现分离。【也就是说,用户看到一个函数,理论上,需要了解函数的实现。这是讨厌的事情。】
类似的Python语言,不可能出现针对接口进行抽象的、类似Java抽象方法或C++的纯虚函数的概念,也就不会有抽象类型。【因此,动态类型语言,在理论上就 不支持抽象函数——你无法脱离实现定义接口。】如果一门面向对象的语言,不支持抽象类型,除了称之为shit,没有其他的描述。
鸭子类型(duck typing)
“如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。”
动态类型语言不支持接口与实现分离,对于这种动态类型的面向对象语言,它很容易实现所谓的鸭子类型——因为该语言的参数不管类型。
function( duck ){
1+ duck.quack() ;
}
按照设计者的原意,function( duck )的参数是Duck类型,但是不管什么类型,周黑鸭也好,只要——按照上面的实现——某东西有quack(),并且返回值能够与1相加,就可以作为实参。
如果那一天Duck类型将duck.quack()修改了——反正Duck类型的quack()返回值类型也是不定的,也就是说仅仅修改了function( duck ):
function( duck ){
duck.quack() and true ;
}
或者duck.quack()改成了duck.jiao()
周黑鸭就需要修改其 quack()的返回值类型或函数名。你不要怪Duck类型的设计者的重构,别人凭什么通知你个死鸭子。常言道:动态类型一时爽,代码重构火葬场。