Verstehe ich richtig, dass das Liskov-Substitutionsprinzip in Sprachen, in denen sich Objekte selbst inspizieren können, nicht eingehalten werden kann, wie es in Sprachen mit Ententyp üblich ist?
Zum Beispiel in Ruby, wenn eine Klasse B
erbt von einer Klasse A
, dann für jedes Objekt x
von A
, x.class
nach Rückkehr geht A
, aber wenn x
ein Gegenstand ist B
, x.class
wird nicht zurückkehren A
.
Hier ist eine Aussage von LSP:
Sei q (x) eine Eigenschaft, die für Objekte x vom Typ T beweisbar ist . Dann sollte q (y) für Objekte y vom Typ S beweisbar sein, wobei S ein Subtyp von T ist .
So zum Beispiel in Ruby
class T; end
class S < T; end
LSP in dieser Form verletzen, wie die Eigenschaft q (x) = zeigtx.class.name == 'T'
Zusatz. Wenn die Antwort "Ja" lautet (LSP nicht kompatibel mit Selbstbeobachtung), dann wäre meine andere Frage: Gibt es eine modifizierte "schwache" Form von LSP, die möglicherweise für eine dynamische Sprache gelten kann, möglicherweise unter bestimmten Bedingungen und nur mit speziellen Typen von Eigenschaften .
Aktualisieren. Als Referenz ist hier eine andere Formulierung von LSP, die ich im Web gefunden habe:
Funktionen, die Zeiger oder Verweise auf Basisklassen verwenden, müssen Objekte abgeleiteter Klassen verwenden können, ohne es zu wissen.
Und ein anderer:
Wenn S ein deklarierter Subtyp von T ist, sollten sich Objekte vom Typ S so verhalten, wie sich Objekte vom Typ T voraussichtlich verhalten, wenn sie als Objekte vom Typ T behandelt werden.
Der letzte ist kommentiert mit:
Beachten Sie, dass es beim LSP ausschließlich um das erwartete Verhalten von Objekten geht. Man kann dem LSP nur folgen, wenn man sich über das erwartete Verhalten von Objekten im Klaren ist.
Dies scheint schwächer zu sein als das ursprüngliche und könnte beobachtet werden, aber ich würde es gerne formalisieren, insbesondere erklären, wer über das erwartete Verhalten entscheidet.
Ist LSP dann nicht eine Eigenschaft eines Klassenpaars in einer Programmiersprache, sondern eines Klassenpaares zusammen mit einem bestimmten Satz von Eigenschaften, die von der Vorgängerklasse erfüllt werden? Würde dies praktisch bedeuten, dass alle möglichen Verwendungen der Ahnenklasse bekannt sein müssen, um eine Unterklasse (Nachkommenklasse) zu erstellen, die LSP respektiert? Laut LSP soll die Ahnenklasse durch eine Nachkommenklasse ersetzt werden können, oder?
Aktualisieren. Ich habe die Antwort bereits akzeptiert, möchte aber noch ein konkretes Beispiel von Ruby hinzufügen, um die Frage zu veranschaulichen. In Ruby ist jede Klasse ein Modul in dem Sinne, dass die Class
Klasse ein Nachkomme der Module
Klasse ist. Jedoch:
class C; end
C.is_a?(Module) # => true
C.class # => Class
Class.superclass # => Module
module M; end
M.class # => Module
o = Object.new
o.extend(M) # ok
o.extend(C) # => TypeError: wrong argument type Class (expected Module)