LSP说
如果q(x)是关于类型T的对象x可证明的属性,那么对于类型S的对象y,q(y)应该为真,其中S是T的子类型。
我可以改写如下:
对于T =>的任何x,q(x)为真。 q(y)对于T 的任何子类型的任何y都为真
那么另一个声明呢?
对于T的任何x,q(x)为真,对于S =>的任何y,q(y)为真。 S是T 的子类型
有意义吗?我们可以将其用作subtype
的定义吗?
答案 0 :(得分:3)
q(x) is true for any x of T and q(y) is true for any y of S => S is a subtype of T
答案是否。表达式的含义是可以定义S和T的共同超类型R,然后LSP(对该名称如何成为主流的耻辱)将适用于T-> R和S-> R。
在打字理论中,存在包含语义的类型,并且存在遵循语义的类型的实现,可能通过继承实现。
实际上,指定类型语义(q(x)
部分)的唯一合理方法是通过实现,因此我们留下了接口形式的无语义签名,和类继承用于实现目的,并实现他们喜欢的接口,无法检查它们是否正确执行。
研究已经尝试定义形式语言来指定类型,因此工具可以检查实现是否遵循类型定义,但是工作量太大以至于它可以很好地编译正式语言到可执行代码。这是 Catch-22 的情况,我认为永远不会解决。
回到原来的问题,在今天被称为“Duck Typing”的语言中,答案是不可判定的,因为任何类型的对象都可以传递给任何函数,如果正确的签名是正确的,那么输入是正确的。实施,结果是正确的。让我解释一下......
使用Eiffel之类的语言,您可以在List.append()
上设置后置条件,List.length()
必须在操作后增加{{1}}。这不是像Perl,JavaScript,Python甚至Java这样的语言的工作方式。缺乏类型严格性允许比更严格的类型定义更简洁的代码。
答案 1 :(得分:2)
没有意义;使用and
的语句在S和T中是对称的。
但我想你想说的是以下
如果对于任何命题q都是这样的情况,q(x)对于类型
x
的所有T
是可证明的,那么对于所有y:类型,q(y)也是可证明的S
,我们可能会考虑S
T
的子类型。
我更喜欢使用数学逻辑而不是非正式的英语,但如果我的定义正确,那就是行为子类型,这些日子通常被称为“鸭子打字”。这是一个非常好的子类型原则,并且再次导致这样的想法:在任何需要类型T
的值的上下文中,您可以提供类型为S
的值,并且它可以,因为类型的值S
保证满足上下文所期望的所有属性。
答案 2 :(得分:1)
我认为不,你不能用它作为定义。此外,如果q(x)对于任何x的T都为真,则q(y)对于S的任何y都为真 它也可能意味着T是S的子类型。
要确定哪个子类型是哪个(假设您知道它们之间存在继承关系),您还必须知道哪些更“通用” 或者哪个比另一个更“专业化”。