In this session, we'll study message composition.
We'll see how precedence works: the hierarchy of items.
The question that need to be asked is:
"What happens when you have a sequence of unary messages?"
I wrote the following expression:
1000 factorial class name What happens?
You execute it as if I had written all these parentheses.
You can see they're annoying.
When you have messages at the same level
(unary, binary, or keywords: it works with all three),
it evaluates them from left to right.
I send the message factorial to 1000.
Then I send the message class to the result of factorial.
Then I send the message name
to this new object.
It returns LargePositiveInteger.
Factorial 1000 is a large number.
You can also try with factorial 10000.
It's a bit longer.
There are messages with parentheses
when they need to be executed first.
Then you have unary messages, then binary, then keywords.
When at the same level, you go from left to right.
Let's take one example.
I have an unary message, squared,
and a binary message, +.
The unary message wins.
First, I send squared.
Next, I send the message +.
It returns 11. It's right.
This is another situation.
I'm going to raise to the power using raisedTo.
I have a binary message and a keyword. The binary message wins.
First, I get 5.
Then I execute raisedTo, it returns 32. It's right.
This is a more complicated example.
Colors in Pharo are objects.
I have the class Color.
I have three unary messages: gray, white, and black.
I have two binary messages: = and -.
What happens then? The system first executes every unary message.
It returns the color aGray, the color aWhite, and the color aBlack.
Now I have to send messages.
I have to choose between the message - and the message =.
I send the message - to the object aGray with white as an argument.
It returns the color aBlack.
I compare the two colors. I get aBlack = aBlack, which is true.
This is an example to show you
you can also do automatic conversion with Pharo.
It's some sort of joke.
I have the expression 1 class maxVal + 1
I have two unary messages, class and maxVal,
and one binary message.
How is this expression executed?
I send the message class to the small integer 1.
It returns SmallInteger since 1 is an integer. It works.
Since it's the result of 1 class, I send it the message maxVal.
What is the message maxVal?
It means: "What is the largest number you can encode over a small integer?"
I get this large number which ends with 23.
To this number, I send the message + 1.
It doesn't return a small integer
since this is the value that can be represented by a small integer.
As a result, it can't be a small integer.
I want to know what the class of this number is.
I write parentheses and I send class. It returns LargePositiveInteger.
This is the largest of small integers.
And that's the smallest of large integers.
I wrote parentheses
because without them, class would have been sent to 1.
I don't want that: I want to send class to the result.
Imagine that I created a rectangle.
I want to get the point on the bottom right of the rectangle.
I wrote this. It crashes when I execute it.
The system doesn't understand: 100 does not understand bottomRight
Why? Because bottomRight is a unary message.
It gets executed before the others: it is sent to 100, its receiver.
100 can't understand this API as it is that of the class Rectangle.
I have to write parentheses as I did in this expression.
How does it work? What's between parentheses is executed first.
Inside, I have two binary messages which are executed.
They create points: two of them get created.
I send extent: to a point which creates a rectangle.
I have a point 0@0.
I pass it extent 100@100.
It returns this rectangle.
I query it for the value bottomRight.
I get a rectangle.
It returns the value of the point here:
it is 100@100.
I told you things were very simple in Pharo:
there are only messages.
+ is a message like any other. There's no order of precedence.
What's nice is that you can use + for domain specific languages.
You can use + between objects unrelated to mathematical objects.
You can't do it in Java. You can do it in C++ by redefining operators.
In Pharo, the solution
was to decide + would be like any other message.
Emphasis was put on simplicity.
There's a price to pay: there's no mathematical precedence.
Let's see this with an example.
In this expression, there are two operators:
two binary messages.
I execute from left to right.
I get 5 and it returns 50: it's not what I learned in school.
To disambiguate this, I have to rewrite this using parentheses
around *.
You have to be careful when using arithmetic operations in Pharo
since mathematical operators are just messages.
Another example:
if I write 1/3 + 2/3, I don't get the right result
as the system first executes this expression
since it goes from left to right.
If I add parentheses, I get the right result.
I have an interesting point to make:
when I write 1/3 + 2/3, I get the small integer 1.
I don't get 1.000... or 0.999...
I manipulate exact fractions. I get exact calculations.
To sum up,
there are three types of messages, which you should know by now:
unary, binary, keywords.
You first execute parentheses,
then unary, binary, and keywords.
When at the same level,
for instance with two unary messages, you go from left to right.
There's no mathematical precedence
as mathematical operations are plain messages.
What's different from most languages:
arguments are placed inside the message structure. between: and: for instance.