Liskov principle: violation by type-hinting
Posted
by
Elias Van Ootegem
on Programmers
See other posts from Programmers
or by Elias Van Ootegem
Published on 2013-11-12T09:51:48Z
Indexed on
2013/11/12
10:20 UTC
Read the original article
Hit count: 316
According to the Liskov principle, a construction like the one below is invalid, as it strengthens a pre-condition.
I know the example is pointless/nonsense, but when I last asked a question like this, and used a more elaborate code sample, it seemed to distract people too much from the actual question.
//Data models
abstract class Argument
{
protected $value = null;
public function getValue()
{
return $this->value;
}
abstract public function setValue($val);
}
class Numeric extends Argument
{
public function setValue($val)
{
$this->value = $val + 0;//coerce to number
return $this;
}
}
//used here:
abstract class Output
{
public function printValue(Argument $arg)
{
echo $this->format($arg);
return $this;
}
abstract public function format(Argument $arg);
}
class OutputNumeric extends Output
{
public function format(Numeric $arg)//<-- VIOLATION!
{
$format = is_float($arg->getValue()) ? '%.3f' : '%d';
return sprintf($format, $arg->getValue());
}
}
My question is this:
Why would this kind of "violation" be considered harmful? So much so that some languages, like the one I used in this example (PHP), don't even allow this?
I'm not allowed to strengthen the type-hint of an abstract method but, by overriding the printValue
method, I am allowed to write:
class OutputNumeric extends Output
{
final public function printValue(Numeric $arg)
{
echo $this->format($arg);
}
public function format(Argument $arg)
{
$format = is_float($arg->getValue()) ? '%.3f' : '%d';
return sprintf($format, $arg->getValue());
}
}
But this would imply repeating myself for each and every child of Output
, and makes my objects harder to reuse.
I understand why the Liskov principle exists, don't get me wrong, but I find it somewhat difficult to fathom why the signature of an abstract method in an abstract class has to be adhered to so much stricter than a non-abstract method.
Could someone explain to me why I'm not allowed to hind at a child class, in a child class?
The way I see it, the child class OutputNumeric
is a specific use-case of Output
, and thus might need a specific instance of Argument
, namely Numeric
. Is it really so wrong of me to write code like this?
© Programmers or respective owner