Is a List of Dogs a List of Animals? And I mean actually, like if you had a physical list
that you wrote with pen and paper in hand of the list of all the good Dogs in your neighborhood,
and you gave that list to someone and asked them, “What is this?” and they say
“That’s a list of animals”, would they be correct?
And you might immediately think, why yes of course! Yes, a List of Dogs is a List of Animals,
obviously a List of Dogs is a List of Animals. After all, what is a list of anything if it
isn’t defined by the items on the list? A list of X is a List that only contains X.
And so what you can do is go through and read every single item on that list and ask yourself
is this a Dog? Is this a Dog? Is this a Dog? And if the answer is yes for all items on that list,
then you indeed have a list of dogs. Now let’s do this again for list of animals.
Let’s look at this list and ask, Is this an animal? Yes. How about this? Yes. And
this? Yes yes and yes. They’re all animals, therefore, they must be a list of animals!
However, consider that perhaps a list isn’t defined by what’s already on the list,
but what is allowed on the list. Instead of saying a List of X is a list where you only have X,
you could instead say a List of X is a list where you are only allowed to add X.
Say I have a list of Dogs that need to be brought to the Vet. And someone somewhere decides,
as a prank, to add me, a human being to that list. I mean, if it were a list of dogs you wouldn’t be
able to because only dogs are allowed on the list of dogs, but if you truly believe that a List of
Dogs is indeed a List of Animals, and Humans are animals, since I am a Human I am an animal and
therefore allowed on this list of Animals, then it is perfectly permissible for me to be on this
list. And then you eventually bring me to the Vet where the Vet takes one look at me and realizes
they have no idea how to treat me because excuse me sir, we treat Dogs here, this is a human.
Okay pause. Why are we talking like this? Obviously in the real world you can add whatever
you want to whatever list. You can add dogs to your cat list, you can add trees to your cat list,
you can draw pictures of monkeys on your lists. So what’s with the weird talk?
Why are we insisting on all these rules that say “all dogs this” or “all humans that”. Perhaps the
notion that anything is anything is nonsense? Maybe you can add a Human to a List of Dogs but
the instant you do it ceases to be a List of Dogs. Who knows and also who cares? Why do we do this?
The answer is simple: Simplicity. See in the realm of computer science, and math, and
well, actually, most things, talking in these very simple, generalized, abstract rules will
usually make things easier to manage. Remember, computers are fast but they don’t handle nuance
particularly well, so the role of a programmer is to describe the world as a series of simple rules
that the computer can use to do its job. Breaking down the set of things that you
want to represent into different Types can be a helpful feature in a programming language.
And by Types I mean, for example, Dog can be a Type and Book can be a type. Dogs have tails
and books have pages, so it doesn’t exactly make sense to say wag a book’s tail or turn to page
314 of your dog. In fact if you left a note to your dog sitter asking them to do exactly that,
they will leave, because they will have no idea what you’re talking about.
Computers are the same way. You can tell your computer to turn to the 314th page of this thing,
and it’ll work fine if that thing is a book, but it will implode if it’s a dog. Actually,
the best case scenario is implosion. The worst case scenario: it starts “doing its best” and you
don’t realize what’s happening until like 5 thousand lines later in your code when
what you thought you had was a book turned to the 314th page, and instead all you really have is a
really old dog. And now you’re confused as to why your program doesn’t work and
you gotta comb through the last 5,000 lines of code to figure out what’s actually going on.
Soooo programming languages have types to basically prevent you from using
the wrong “type” of data for the wrong purpose. So then your program can stop
execution or sometimes not even start execution if it notices that you’re trying to pass your dog
into a page-turning function, and say “HEY! You said we want to turn the page of this book,
but it’s not a book, it’s a dog, please fix your spaghetti code”.
And of course you can do all sorts of sophisticated things with types, depending on what
programming language you use. Like we can have types that are organized relationally, describing
how some types are subsets of (or subtypes) of others. A cat is an Animal, a Dog is an Animal.
Dogs, Cats, and Animals are Types. If this stuff sounds familiar to those of you who know object
oriented programming languages, that’s for a good reason, and I’m sure we’ll discuss another time.
And so you may also imagine wanting types that include other types,
for example a List of X, where X can be any type. These are what we call in programming languages,
“Generic Types” because X can be really anything you want it to be. You can have
a list of Dogs or a List of Trees. And you can also make your own generic types as well. You
could have a Tutor of X where X can be Math or Science or English or whatever.
So let’s talk about an example: If you have a bot that you are programming to feed your pets,
and you have a List of Dogs, you could imagine writing a function that goes through a list of
Dogs and feeds everything on that list some kibble. But in order for this to not be a
disaster, you need to be sure that you’re not adding any Cats to this list. Cats eat catnip,
Dogs eat kibble. But if a List of Dogs is indeed a List of Animals,
and I can add a Cat to the List of Animals (because a cat is an animal), this bot is
probably going to try and feed Dog food to a CAT, and that’s probably not what you want!
So for the question of “Is a List of Dogs a List of Animals”, the answer is it probably
shouldn’t be? So long as you can both add things to this list and iterate over the list,
you’re going to run into problems. And so a programming language like Java or C# will say,
no, A List of Dogs is not a List of Animals.
But WAIT, what if we had a list, or some construct that you could iterate over and get every element
in, but you can’t add to it... That would solve this problem. And some languages allow you to
declare generic types that only allows you to read its generic elements, but not to write them.
C#’s IEnumerable is very similar to a list in that you can go through every single element of it,
but notably you can’t really do anything else with it, specifically you can’t add things to it,
and so in C#, an IEnumerable of Dog is INDEED and IEnumerable of Animal.
See, the key here is that IEnumerables in C# are read only. All of its actions,
its functions and methods only OUTPUT the type we’re talking about, whether it’s dogs or animals,
there’s no way to WRITE to an IEnumerable, there’s no method that takes IN an Animal
or a Dog or anything like that and stores it somewhere for future use.
A LIST on the other hand allows you do GET everything in the list,
OUTPUTs items from the list but ALSO at the same time, allows you to WRITE to the list too,
methods that allow you to ADD ITEMS, to INPUT things to the list.
This concept, where a Dog is an Animal therefore a List of Dogs is a List of Animals, or more
generically A is a B therefore generic of A is a Generic of B, is called Covariance. Some languages
like C# support it and allow you to declare types as covariant, basically saying that you only have
methods and fields that get data from this Type. Languages like Java don’t do this specifically,
but takes a different approach: basically allowing you to say that an item is covariant on a case
by case basis. And sure, it looks a little clunky, but if you want to iterate over this
weird looking list as if everything in it were an animal, it does exactly what you want it to do.
In some cases, although generally less common, you can have it be the opposite way
as well. Instead of covariance where a Cat is an Animal therefore a Generic of Cat is a Generic of
Animal, there are instances of contravariance, where this relationship is flipped. For example,
A Cat is an Animal therefore a Generic of ANIMAL is a Generic of Cat.
For example, let’s talk about an Animation Robot that is really good at animating things of Type X.
Remember Fish are a Type, Eagles are a Type and both Fish and Eagles are Animals.
So you could imagine a Fish Animator would make a very nice animation of a Fish Waving their fins,
while an Eagle animator would make very nice animations of an Eagle flapping its wings.
Note that a Fish Animator can’t work on an Eagle because Eagles don’t have fins
and vice versa because Fish don’t have wings.
However, if you had an Animal animator that takes in any animal and outputs a nice animation of the
animal nodding its head, this would work for all animals, and so it makes sense to say that
since an Eagle is an Animal, therefore an Animal Animator is an Eagle Animator.
Actually... not all animals have heads... But it’s okay,
let’s just say in my animation program all animals have heads.
Anyways, this concept, where an A is a B so a generic of B is a Generic of A (see how it’s
switched?), is called contravariance, and like in our animation example,
it only works when the generic thing, the Fish or the Eagle or whatever is passed in
as an INPUT. We don’t produce any Fish, we merely take existing Fish and animate them.
So is a List of Dogs a List of Animals? I guess, kinda no, but depending on how you use it,
namely if your list is something that you can read from but not write to,
and your programming language supports it, then, kinda yeah!
Thanks for bearing with me here, especially if this is your second time watching this video!
We want to create the highest quality content here so thank you to those who help me do that
And one last thing: If your programming language doesn’t support a feature you like,
just write your own.