[music] Having now seen multiple inheritance and Ruby style mixins, there's
a third comparison we need which are, is with interfaces as you see in languages
like Java and C#. This is an important distinction, even
thought interfaces are really about static typingand Ruby doesn't have static typing.
But Ruby also doesn't have multiple inheritance.
We can learn concepts even if we're not using a language that happens to have that
concept. So since interfaces really don't make
sense in Ruby, I will use Java code in this segment but I'll explain what's going
on and, and it shouldn't be any trouble even if you haven't seen Java before.
But we do need to take a step back and say, wait a minute, static typing, we've
only seen that for ML. What is static typing mean for object
oriented programming? Well it turns out what we're typically
trying to prevent is a method missing error.
We want to use our type system to make sure that we only pass around objects so
that when we call methods on those objects, they actually have those methods
to find. And that's the main thing that a type
checker for an OOP language would do. So how does this work in languages like
Java and C#? Well, each class that you define also
introduces a type. Just like when we had a data type binding
in ML and made a type. Every class in Java is also a type.
And when we declare methods, they have argument types and result types, just like
functions in ML have argument types and result types.
So, for example here in Java, I am asking to them define a Class A.
There's two methods, m1 and m2. I've omitted their bodies that's here in
the dot, dot, dot because I don't care about the bodies of these methods.
Those would be type checked. What I care about is saying that m1 takes
two arguments in e of type example and in s of type string, and it returns, we put
the return type over here on the left, something of type object.
Similarly, class A defines a method m2 that takes three arguments, one of type A,
one of type Boolean, one of type integer And returns an integer.
Now the interesting thing is how subtyping works in these languages.
So we know subclassing, right? We can have a class C that you know, is a
subclass of D. Turns out that when you do that, you also
are a subtype. In fact, no matter.
Even if you're a transitive subclass, like we studied with multiple inheritance.
You're still a subtype of the type for the superclass.
Now the way type checking works, is you can always use a subtype of what's
actually asked for. So if you have something that is a subtype
of a, you can pass that thing for the first argument m2.
Similarly, if you have a subtype of Boolean you can pass that for the second
argument subtype of integer for the third argument.
Anywhere you have something of the subtype it also has the supertype, okay so we can
pass those things along. So, that's your intro to static typing for
OOP. Now what are interfaces?
Interfaces are also types, but they're not classes.
So every class also introduces a type. Every interface introduces a type, but
just like Ruby mixins, you cannot create objects of interfaces.
Unlike a mixin, you can't put method definitions in an interface either.
Instead, the only thing you put in an interface is a, that a method exists,
these are its types of its arguments, and this is the type of its result.
So for example this interface you know, example here has two methods, m1 and m2.
M1 takes in two, ints and returns a void. M2 takes an example and a string and
returns an object, whatever types you want.
I've outlined in red here the semi-colon. There's no method body here.
You're just saying anything that has this type has these methods and the methods
take these argument type and have these result type.
So now what a class can do is implement an interface.
So in Ruby, we can have one super class. We can include any numbers of mixins.
In Java and C#, you can have one superclass, and you can implement any
number of interfaces. If you say you implement an interface,
then you better implement it. You better define, either explicitly or
through inheritance, every method that, that interface requires, and you better do
so with the correct types. In that sense, having multiple interfaces
that you implement is no problem. You just have to provide all the methods
that all of them require you to do so. And then if your class definition does
implement an interface, then the type for that class is a subtype of the interface
type. So for example here, if class a implements
example. The type checker will make sure it
actually does, and then since it does, in the rest of the program, anywhere we need
something of type example, we can instead pass something of type a.
And that gives us the flexibility to treat instances of a as things that have type
example, and another class could implement example as well.
And then if you have some code somewhere, like the body of m2 that takes an example.
It does not know whether it's being given an instance of A, or an instance of B, or
an instance of any other class that implements example, but it does know that
whatever is bound to this variable e has a method, has all the methods that the
example interface requires and they take things of the correct types.
So, interfaces provide no methods, they provide no fields so all the complications
that we had from multiple inheritance are not relevant.
They don't give you anything. If a class implements an interface all it
gives you is more obligations, things you have to do.
What they are for is to produce a more flexible type system.
That you can now define methods that take some argument of type i, where i is some
interface and then pass into that method. Anything that implements that interface.
You can also have fields, like Ruby's instance variables, who's types are
interfaces instead of classes. They're types that tell you what things of
that type have in terms of methods. So, what is going on here is Java with
interfaces has a much more flexible type system than Java without interfaces.
It lets us take two different classes in our program, have them both implement the
same interface, and then we can pass instances of either class, anywhere we
just need something with the interface type.
So they provide a lot of type system flexibility to Java, but that's really all
they provide. So in a dynamically typed language like
Ruby, you're never going to have interfaces, I would never expect them to
be added, because, you don't have a type system you are trying to make flexible.
You already have a dynamically typed language which is way more flexible.
That even Java with interfaces. So dynamic typing versus static typing is
something we studied. We know dynamic typing is more flexible,
static typing is less flexible in many ways.
We went through all of those advantages and disadvantages.
The key idea of interfaces is to start with a statically typed OOP language.
And then make the type system more powerful.
While still not being nearly as flexible as a dynamically typed language like Ruby.