• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

2 Liskov substitution principle questions

 
Ranch Hand
Posts: 145
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First, they present the Square subclassing Rectangle problem:



Then they don't provide a solution anywhere.
From what I read since Square is-like-a Rectangle not is-a Rectangle, the solution would be probably Interface Segregation?
Otherwise I don't see how I can construct a Rectangle and treat it as a Square when we getArea(), because if we override getArea() in Square and throw an exception saying sides are not equal, that also breaks LSP.





Two, consider this snip from wikipedia:


If these assignments were encapsulated we could say we have behavior (IMO assignment is an action, to which the asignee "responds", even if enforced by the underlying platform - a third party, thus having a behavior), and we would have:
set(Object o, int index) {
b[index] = o;
}
According to LSP wouldn't this be a violation?
Since the supertype can be a substitute for the subtype, shouldn't then the supertype be oblivious to the subtypes?
But doesn't this also mean that Strong Typing is a violation of LSP, unlike Weak Typing?

THIS WIKIPEDIA ARTICLE further imposes this:

Liskov's principle imposes some standard requirements on signatures that have been adopted in newer object-oriented programming languages (usually at the level of classes rather than types; see nominal vs. structural subtyping for the distinction):

* Contravariance of method arguments in the subtype.
* Covariance of return types in the subtype.
* No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.

 
Greenhorn
Posts: 27
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Whilst LSP is often debated and adopted within OO circles - it is often argued that Java does not obey LSP - as I think was demo'd by your second example.

Google Java and LSP and you will get the idea:

http://my-dev.blogspot.com/2011/04/does-overriding-violate-liskov.html

http://alblue.bandlem.com/2004/07/java-liskov-substution-principle-does.html

 
Tudor Raneti
Ranch Hand
Posts: 145
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Upon further inspection I realized this example does not break LSP:



because while String and Integer extends Object, Integer doesn't extend String so it can't use its properties
or
because LSP refers to object inheritance within the same inheritance branch only
or
does not specify a reciprocal relation (if S inherits T, T can't inherit S ... with the exception of Fry's nasty in the pasty)
or
while the properties of object T must hold according to LSP if I use them from a substitute or subclass (S1, S2 etc.) it does not mean that the properties of S1 must hold when it's being used as a substitute for T (inheritance has no reciprocity), so, when I use a property from a substituent for T, it can only hold if that property is a common denominator of both subtypes.

In conclusion the whole shmeer (the hypothesis that LSP is broken here) breaks down because T doesn't have common denominator properties for its offspring branches to leverage off, meaning a value field and duck typing in this case, which is a good thing!
If it was like that, imagine you could've put "1a" in the value field, then try to use it as an Integer, then you would've definitely have had a necessity to throw an exception for not being able to parse it as an Integer, and break LSP for throwing a new exception.
Duck typing is for the birds in conclusion, not for OOP languages.

Liskov_substitution_principle

in a computer program if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may be substitutes for objects of type T), without altering any of the desirable properties of that program (correctness, task performed, etc.).







Solution to the Square LSP problem:

1. WIKIPEDIA sais:

Mutability is a key issue here. If Square and Rectangle had only getter methods (i.e. they were immutable objects), then no violation of LSP could occur.



2. Introduce a field called "side" and do not work with rectangle height and width fields (make them private), in which case make another method called getSquareArea(), or in case the subtype is in a different package than the supertype, make the supertype
getArea() access modifier default (or none), and create a getArea() in the subtype, where because it can't see the getArea() from the supertype, it will also not collide with it needing overriding (being in fact a new method which doesn't have the pre/postconditions restrictions, or a new method with the same signature).
This however implies that if Square has nothing in common with Rectangle in its interface, they should be separate interfaces according to interface segregation principle, or at least they should both implement an interface called Shape or something that
declares getArea() and other common denominator properties, and let each subclass implement its own specifics.





As for the links:

http://my-dev.blogspot.com/2011/04/does-overriding-violate-liskov.html


Overriding does not violate LSP, it needs help from the developer.

http://alblue.bandlem.com/2004/07/java-liskov-substution-principle-does.html


This blogger does not understand LSP (or Polymorphism in consequence), conclusion drawn from the fact that all his (superficial) arguments contradict his conclusion that "LSP does not hold in Java".

Now that I somewhat understand LSP I can see it implemented all over in standard Java design.





As a final topic, I would like to discuss a problem I was presented with at an interview a while ago. As I remember the problem presented by the interviewer was a class Properties that was implementing Map and was overriding put(), within which it would throw an exception if the key wasn't a String. At the time not knowing of LSP, I didn't know what to think, except that I do not see the point of throwing an Exception and only accepting Strings in a key.
The interviewer explained that it's a violation of LSP by throwing a new exception that's not defined in the supertype. Can you spot the problem with this?

Let's review the Liskov standard requirements :

Liskov's principle imposes some standard requirements on signatures that have been adopted in newer object-oriented programming languages (usually at the level of classes rather than types; see nominal vs. structural subtyping for the distinction):
[...]
* No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.



The problem in my opinion is that the interviewer used an interface in his example as a supertype. LSP only talks of types or classes, and defines a principle for good programming practice along the lines of inheritance object relationship, or, types or classes extending another type or class and how should this system be designed .

Arguments:
- you can't define behaviour in interfaces thus you can't speak of overriding behaviour, or throwing a new exception in a method definition as opposed to overriden definition, when there wasn't a previous definition of the method to start with; neither can you talk of pre and post conditions, invariants etc.
- you can't instantiate interfaces (using new InterfaceName() {...} is instantiating an anonymous inner class that implements InterfaceName, or a compiler artifice, is not an interface instance), you implement interfaces; an interface describes an object by declaring its properties, it is something that an object is guaranteed to implement, it is a contract.

Conclusion:
LSP doesn't apply on interfaces because it talks of types and derived types, that you can instantiate and have behaviour respectively that present pre/post conditions, invariants etc. The class that you can define in an interface does not belong to the class implementing the interface, that construct works like a namespace for the class within the interface, and you need to either prepend that class in the interface with the interface name when instantiating it, or use import keyword.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic