Author: claresudbery

Liskov Substitution Principle

Some notes I made on the Liskov Substitution Principle (LSP) – which is the L in SOLID.

I can never remember the details of Liskov, which is why I made these notes.

These notes are also visible on my new personal wiki site, where I briefly describe the S, O, I and D in SOLID as well.

  • “objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.” See also design by contract.
  • Code that uses a base class must be able to substitute a subclass without knowing it
  • The specific functionality of the subclass may be different but must conform to the expected behaviour of the base class.
  • EXAMPLE:
    • So, I can call FemaleMammal.GiveBirth and I can substitute a cow into that – Cow.GiveBirth without breaking anything
    • No matter which version I choose, I should be confident that I will end up with a baby animal. Even though the specifics might be slightly different.
  • These are the principles which must be adhered to:
    • Contravariance with parameters
      • There should be contravariance between parameters of the base class’s methods and the matching parameters in subclasses. This means that the parameters in subclasses must either be the same types as those in the base class or must be less restrictive.
      • Parameters in subclasses are either the same or have more / add extra functionality
      • EXAMPLE:
        • FemaleMammal.GiveBirth(Mammal mothersBestFriend)
        • Cow.GiveBirth(Animal mothersBestFriend)
      • See Covariance and Contravariance
    • Covariance with return values
      • There must be covariance between method return values in the base class and its subclasses. This specifies that the subclass’ return types must be the same as, or more restrictive than, the base class’ return types.
      • Return values in subclasses are either the same or have less functionality
      • EXAMPLE:
        • Mammal baby = FemaleMammal.GiveBirth();
        • Bovine baby = Cow.GiveBirth();
      • See Covariance and Contravariance
    • Preconditions
      • The preconditions of a base class must not be strengthened by a subclass
      • A precondition of a class is a rule that must be in place before an action can be taken.
      • EXAMPLE:
        • FemaleMammal must not be a virgin and must never have had a Caesarian before giving birth
        • Cow must not be a virgin before giving birth
    • Postconditions
      • Postconditions cannot be weakened in subclasses.
      • Postconditions describe the state of objects after a process is completed.
      • EXAMPLE:
        • After female mammal gives birth, it must have an associated baby that is a mammal
        • After cow gives birth, it must have an associated baby that is a bovine (this is fine)
        • After cow gives birth, it must have an associated baby that is any kind of animal (this would not be fine)
    • Invariants
      • The invariants of a base class must not be changed by a subclass.
      • An invariant describes a condition of a process that is true before the process begins and remains true afterwards.
      • EXAMPLE:
        • FemaleMammal is female both before and after birth
        • Cow is female both before and after birth
    • History
      • New or modified members should not modify the state of an object in a manner that would not be permitted by the base class
      • EXAMPLE:
        • FemaleMammal gains a newly populated Baby property and the baby has a head
        • Cow gains a newly populated Baby property (this is fine)
        • Cow gains a newly populated CowUdders property (this is not fine)
    • Exceptions
      • A subclass should not throw exceptions that are not thrown by the base class unless they are subtypes of exceptions that may be thrown by the base class
      • EXAMPLE:
        • FemaleMammal.GiveBirth throws a BreachedBaby exception
        • Cow.GiveBirth throws a BreachedBabyCow exception (this is fine)
        • Cow.GiveBirth throws a NotEnoughGrass exception (this is not fine)
  • For instance, if you want a read-only file type, it should not inherit from File – and File should not have a Save method. Rather, the base File type has a Load method, and it has a subclass – WriteableFile – which has a Save method. Thus the base class cannot be saved. (otherwise you would have ReadOnlyFile which was not able to implement the Save method on its parent, and also left the object in a different state after calling Save than what you would expect – particularly if its Save method threw an exception which was not thrown by the base class)

What to do when you get stuck in a Vim editor

Anybody using Git straight out of the box on the command line is likely to have found themselves suddenly stuck in a Vim editor. If you’re not used to Vim, this can be a highly discombobulating experience. Here’s how to escape!

  • Quick Guide:
    • Type i to get into insert mode
      • (no need for colon)
      • (if it’s worked, you’ll see “– INSERT –” at bottom of screen
    • Type your commit message
    • Click Esc
    • Type :wq to save and quit
      • Or type :q! to quit without saving
    • Hit Enter

Changing your Default Git Editor

  • You don’t have to have Vim as your default editor! You can change to an editor of your choice (eg Notepad)
  • Note that these instructions were written for Windows. I don’t know about other operating systems but I’m guessing it’ll be similar
    • Find and open your .gitconfig file
      • (probably here: C:\Users\[user-name])
    • Add this section to the bottom:
      • [core]
      • editor = ‘C:/Program Files (x86)/Notepad++/notepad++.exe’
    • Save and close the file.
    • When you’re committing with git, just write git commit and press Enter. It will pop open Notepad++.
    • Write your commit message at the top of the file, and save and close the file. Done!
      • …but it doesn’t always work like that, in which case you might have to go back to VIM and just learn the VIM basics
  • More here: http://stackoverflow.com/questions/2596805/how-do-i-make-git-use-the-editor-of-my-choice-for-commits

Searching and search / replace in Vim

(Note that this was written after I spent a few months learning Vim. If you’re just stuck in Vim and want to get out, see What to do when you get stuck in a Vim editor).

I’m publishing my notes on the things that are useful in Vim but that I keep forgetting. My notes are split into four sections, so I’ll publish four posts:

This is the fourth post, and it’s about searching  and search / replace in Vim.

Search for term in file

  • Like this: /[search term – regex]
  • Type n to get next search result
  • Type N to get previous search result
  • For case insensitive search, add \c to the command (either at start or end)
  • If you then get highlighting which won’t go away, type :noh

Search and replace

  • Like this: :%s/[search term]/[replacement]/g
    • %s means whole file, /g means every occurrence on every line
    • If you want it to ask you for confirmation on every replacement, add c as well: :%s/foo/bar/gc
    • More here: https://vim.fandom.com/wiki/Search_and_replace
    • And here: https://www.linux.com/learn/vim-tips-basics-search-and-replace
    • If your strings contain forward slashes, then you can replace the forward slashes in the command with any other character!
    • For case insensitive search, add \c to the command (either at start or end)
    • To do it on whole words only: :%s/\<word\>/newword/g – you have to delimit the word with \< and \>

Find character on this line

  • f – find character on this line
    • Add a number to do multiple
    • Eg 2f_ will find the second underscore character on this line

Find the word under the cursor

  • This: *
    • This works on words containing underscores
    • By default it won’t work on words containing hyphens
      • You can change this by adding set iskeyword+=- to .vimrc
      • Or just type :set isk+=- in Vim

Find whatever text you have highlighted (in visual mode)

Navigating files, lines and blocks in Vim

(Note that this was written after I spent a few months learning Vim. If you’re just stuck in Vim and want to get out, see What to do when you get stuck in a Vim editor).

I’m publishing my notes on the things that are useful in Vim but that I keep forgetting. My notes are split into four sections, so I’ll publish four posts:

This is the third post, and it’s about navigating files, lines and blocks in Vim.

Navigating lines

Navigating files

  • Go to top of file: gg
  • Go to end of file: shift + g
  • Go to line number: line-number + shift + g
  • Navigation within chars / lines: j = down, k = up, h = left, l = right

Navigating blocks delineated by {}, (), [], <> or “”

  • The diff between % and [{ always confuses me cos it’s not explained well in Vim Adventures:
    • % will take you to the matching bracket if you are already ON a bracket. It only works on {}, () and [] (not <>)
    • [{ will search backwards for the enclosing { if you are already IN a {} block – so it takes you to the start of your current scope
      • ]} will move forwards and take you to the end of your current scope
      • ]{ is meaningless (I think)
      • [( and )] will also work in the same way
      • [< does not work, [“ does not work, and [[ does something totally different
      • If you want to move back to blocks that enclose your current block, use numbers
        • So for instance, 3[{ will take you to the beginning of this snippet of code if your cursor is in the innermost scope:
        • {
          • {
            • {I am here}
          • }
        • }
      • In Vim Adventures type :help [{

If you want to navigate inside a block delineated by [], <> or “”

  • You can use % to find the matching brace if you are on [ or ] but not < or >
  • You can use visual mode to select the contents of {}, [], (), <> or “”
    • Use a to select the contents AND the delineators
    • Use i to select the inner contents (ie without the delineators)
    • Use the OPENING delineator to indicate what your scope is
    • These are all the possible commands: va{, vi{, va[, vi[, va(, vi(, va<, vi<, va”, vi”
    • If you want to select blocks that enclose your current block, use numbers
      • So for instance, v3a{ will select this whole snippet of code if your cursor is in the innermost scope:
      • {
        • {
          • {I am here}
        • }
      • }
    • Once you’re in visual mode you can use commands like i, p, c, a, s
    • In Vim Adventures type :help a{ or help i{
      • You can use c to select the contents of {}, [], (), <> or “” and then it will put you into Insert mode to replace what was there
        • Same principles as with v (see above)
        • These are all the possible commands: ca{, ci{, ca[, ci[, ca(, ci(, ca<, ci<, ca”, ci”
        • As with v you can use numbers to select multiple enclosing blocks (see above) but the number comes BEFORE c, like this: 3ca{
        • (There are others too, like caw and ciw for words – in Vim Adventures type :help aw and :help iw)