Hello. In the previous session,
we saw how to implement the Booleans: not and or.
The third question remains: why on earth did we ask these questions?
That's what we will study.
Let's review the implementation. For not, there were two objects.
We had true and false.
They were instances of the classes True and False.
When we sent a message not,
we queried their respective classes and we executed the methods.
So no problems here.
As I said,
if you look at what you're doing:
first, let the receiver decide.
It means you don't take any decisions,
but you send a message which will resolve itself.
So these two heuristic functions were: let the receiver decide;
and do not ask but tell to do things.
I'll mention this again.
Now let's look at the exercise itself.
So what's this all about?
You will never implement Booleans in your life,
at least I hope so.
Is it really totally useless?
What are the underlying lessons?
I think it's very important to ask you this question:
yes, the implementation is like that, but then what's this all about?
In fact, it shows that whenever I use message sends,
whenever I send a message, I have some sort of case statement.
You will also find these in C programming, etc.
Sending a message is about multiple choices.
What's interesting is: when you send a message,
in the end, it's more than a case because it's a dynamic case.
In fact, it depends on the loaded classes and on the created instances.
Actually, when you program in Java,
you would often write x.f()
to invoke the method f.
What I am explaining to you now is: this period
is a choice operator.
It's really crucial
that this choice is dynamic.
We didn't often tell you about it,
but this is actually what is strongly exemplified here.
To summarize, when you send a message,
it really functions like a dynamic case statement
in the sense that it depends on the loaded classes.
This Boolean example has two instances and two classes;
even with 50 of them, it'd work the same way.
Whenever you send a message to the virtual machine
- since Pharo has one like Java or C# -
the virtual machine's execution tool
selects the right method depending on the receiver's class.
So sending a message is a choice operator.
And each time you use a condition,
you replace this process
implemented in the choice-making virtual machine.
So the solutions with not show
that you should use the choice
given by the virtual machine to implement programs.
You don't need to use any ifs
because sending a message means an if or a condition.
The question you might ask now:
what if I had expressed the initial exercise in a totally different way?
What if I had said, "Can you implement Not in the Boolean class,
or Or in the Boolean class?"
This solution wouldn't have worked.
That's strange. What does it mean?
Having one or several classes greatly impacts
the way I design my applications.
Indeed,
classes play the role of branches or choices.
So if you have a choice to choose yogurt,
but there's only one pot in the shop, you will choose this yogurt.
It's the same.
It means your class represents
a case in your inheritance tree.
What does it imply?
It implies that when I look at a design
with a big fat class full of methods,
I could express it as a hierarchy instead.
This design is better because it's more modular.
I can easily add another choice if I want.
I can extend a choice and say: "This wasn't bad.
"I can refine it to have a new one."
Moreover, it can reduce complexity:
I can focus only on one class, not on something with so many conditions.
So on the one hand, we have a choice operator;
and on the other hand, something that expresses choices.
When you put them together, you get good-quality OOP.
What's even better
is that when you look at the solution with hierarchies,
it becomes even better because I can package the solutions.
It means I can package this as core, and that this is a plug-in.
I will tell my client, "If you want this feature,
"you just need to download this plug-in and pay me."
I will load this code dynamically.
When I create an instance of this class,
when I send my message Operation here,
the plug-in's code will be executed in the system.
To us, that's the essence of OOP.
I send a message and will select the right method.
And I will use the fact that I know the system selects the right method
to get even more elegant implementations.
What have we learned?
We've learned that sending a message lets the receiver decide and choose.
Client does not have to decide.
Client code is more declarative.
There are no conditions. I give orders: do this, do that, open, close;
not, "Do you belong to this class? Are you ready to be closed?"
Different receivers may be substituted dynamically.
We will see about this later, but it's implied.
So most of the time, try to avoid writing ifs.
Use objects and messages when you can.
It's not always the case, but use them at least when you can.
The execution engine, the virtual machine,
acts as a conditional switch each time you send a message.
So use it.
You can also have fun typing the AntiifCampaign.
Programmers launched this campaign to make people stop writing ifs.
So what have we learned in this session?
Two things: when I write x.f(),
either in Java or in Pharo,
I make a choice: I choose the method f
that must be executed depending on the receiver.
So I have this choice operator
and a hierarchy which represents potential choices.
So it's really a skeleton thanks to which choices can be made.
As a result, I have no conditionals. and more extensible programs.
This is the end of the first session
about object designs in Pharo.
And we will see more in the next sessions.