patzi
patzi

Reputation: 353

Understanding weird logical operators in smalltalk

So my problem is the following:

When char = 0

boolean = char ~= 0 & char ~= 256

evaluates to true and if I invert the statements like so:

boolean = char ~= 256 & char ~= 0

I get false.

What's happening?. I am expecting false on both cases.

Upvotes: 0

Views: 4125

Answers (2)

Leandro Caniglia
Leandro Caniglia

Reputation: 14858

There is something we are repeating in some answers that I think deserves further clarification. We say evaluation proceeds from left to right. True, but the actual semantics of messages is:

First evaluate the receiver, then the arguments in order; finally send the message.

Since the Smalltalk VM is stack based, this rule means that:

  1. The receiver is evaluated first and the result is pushed on the stack.
  2. The arguments are evaluated in order and their results pushed on the stack.
  3. The message is sent

Item 3 means that the method that the send invokes will find the receiver and the arguments in the stack, in the order defined above.

For instance, in

a := 1.
b := 2.
b := a - (a := b)

variable b will evaluate to (1 - (a := 2)) = -1 and a to 2. Why? Because by the time the assignment a := b is evaluated the receiver a of the subtraction has already been pushed with the value it had at that time, i.e., 1.

Note also that this semantics must be preserved even if the VM happens to use registers instead of the stack. The reason is that evaluations must preserve the semantics, and therefore the order. This fact has an impact on the optimizations that the native code may implement.

It is interesting to observe that this semantics along with the precedence unary > binary > keyword support polymorphism in a simple way. A language that gives more precedence to, say, * than + assumes that * is a multiplication and + an addition. In Smalltalk, however, it is up to the programmer to decide the meaning of these (and any other) selectors without the syntax getting in the way of the actual semantics.

My point here is that "left to right" comes from the fact that we write Smalltalk in English, which is read from "left to right". If we implemented Smalltalk using a language that people read from "right to left" this rule would be contradicted. The actual definition, the one that will remain unchanged, is the one expressed in items 1, 2 and 3 above, which comes from the stack metaphor.

Upvotes: 3

aka.nice
aka.nice

Reputation: 9382

As @Uko said, you must understand the precedence of messages: all binary messages (+ = < & ~= etc..) are evaluated from left to right.

Thus you evaluate:

(((boolean = char) ~= 256) & char) ~= 0

I think you were after:

boolean := (char ~= 256) & (char ~= 0).

So what happens with your expression ?

  • booleanis presumably unitialized (thus nil)
  • char is 0.
  • boolean = char is false.
  • false ~= 256 is true.
  • true & char is char (see below why)
  • char ~= 0 is false (since char = 0)

If you invert 0 and 256, only the last step changes and awnswer true.

The interesting part is the implementation of message & in class True: it probably does not assert that the parameter is a Boolean and looks like:

& aBoolean
    ^aBoolean

If you pass something that is not a Boolean, (like 0 in your case), it will return this thing, whatever surprising it can be...

If you use an IDE (Squeak/Pharo/Visualworks/Dolphin... but not gnu Smalltalk) I suggest you use the menu Debug It and evaluate the expression step by step in the Debugger.

Last, note that char is probably not a good name in Smalltalk context: it might be misleading. Indeed, if it holds 0, it's rather an Integer, not a Character.

Upvotes: 4

Related Questions