1

I kind of ran into this when messing around with FlashPunk, and I'm going to use it as an example.

Essentially the main sprite class is pretty much class Entity. Entity's constructor has four parameters, each with a default value. One of them is graphic, whose default value is null.

Entity is designed to be inherited from, with many such subclasses providing their own graphic within their own internal workings. Normally these subclasses would not have graphic in their constructor's parameter lists, but would simply pick something internally and go with it.

However I was looking into possibly still adhering to the Liskov Substitution Principal, which led me to the following example:

package com.blank.graphics 
{
    import net.flashpunk.*;
    import net.flashpunk.graphics.Image;

    public class SpaceGraphic extends Entity
    {
        [Embed(source = "../../../../../../assets/spaces/blank.png")]
        private const BLANK_SPACE:Class;

        public function SpaceGraphic(x:Number = 0, y:Number = 0, graphic:Graphic = null,
                mask:Mask = null)
        {
            super(x, y, graphic ? graphic : new Image(BLANK_SPACE), mask);
        }
    }
}

Alright, so now there's a parameter list in the constructor that perfectly matches the one in the super class's constructor. But if the default value for graphic is used, it'll exhibit two different behaviors, depending on whether you're using the subclass or the superclass. In the superclass, there won't be a graphic, but in the subclass, it'll choose the default graphic.

Is this a violation of the Liskov Substitution Principal? Does the fact that subclasses are almost intended to use different parameter lists have any bearing on this? Would minimizing the parameter list violate it in a case like this? Thanks.

gnat
  • 21,442
  • 29
  • 112
  • 288
Panzercrisis
  • 3,145
  • 4
  • 19
  • 34

1 Answers1

6

No, it is not a violation of the LSP. The LSP says that instances of a subtype should be safely substitutable for instances of the parent type (i.e. after construction). It doesn't matter how they get constructed.

nobody
  • 848
  • 7
  • 12
  • Saw somewhere else afterwards where somebody was mentioning that objects aren't considered to exist until after they're constructed. Is this fairly universal? Because you can usually do a lot with `this` inside a constructor. – Panzercrisis Jun 13 '14 at 13:11
  • 2
    @Panzercrisis: inside a constructor, `this` is always of the type the constructor belongs to, it will be never of a different type, so the question of substitutibility never arises there. – Doc Brown Jun 13 '14 at 14:45
  • @DocBrown Are you saying that, because compared to normal instance methods, constructors syntactically stay in their own little box, even when invoked from subclasses' constructors, outside code that invokes a constructor doesn't have to worry about subclasses messing it up internally? And that difference in signature is not significant enough on its own specifically at the point of construction, so LSP isn't violated? – Panzercrisis Jun 13 '14 at 15:07
  • I can kind of see what everybody's saying, but I'm just trying to close some gaps in what I'm able to see. – Panzercrisis Jun 13 '14 at 15:09
  • 2
    @Panzercrisis: a ctor cannot be overloaded, thus not substituted - this is true even when a superclasses ctor is called from a subclasses ctor. So when there is no substitutibility, how should the LSP be violated? – Doc Brown Jun 13 '14 at 15:20
  • @DocBrown Ah, I think I see now. Thanks. Earlier I was thinking of changing the constructor that was called as simply a part of changing the type itself, but I guess what everybody's looking at is that it's still a brand new method. – Panzercrisis Jun 13 '14 at 15:56