Smalltalk: what's the difference between "&" and "and:"
Asked Answered
S

2

12

I just started learning Smalltalk at uni.

I would like to know the difference between the messages & and and: (just like | and or:)

Sweatbox answered 14/9, 2021 at 22:20 Comment(0)
S
15

Welcome to Smalltalk! You are asking a good question that points out some subtle differences in expressions that are outside or inside blocks.

The '&' message is a "binary" message so takes only one argument. In this case the argument is expected to be a Boolean or an expression that evaluates to a Boolean. Most importantly for our purposes in this comparison, the expression will always be evaluated.

The 'and:' message is a "keyword" message and also takes only one argument. But in this case the argument is expected to be a Block that if later sent the 'value' message would return a Boolean. So, for our purposes in this comparison, the Block will not always be evaluated. (The difference between the binary and keyword messages does not matter for this question.)

The option to not evaluate the argument allows Short-circuit evaluation in which knowing the left-hand side often allows us to avoid a (possibly expensive) calculation of the right-hand side. So, if the left ("receiver") is false, there is nothing to be gained by evaluating the right-hand side.

So, consider the following:

self cheapFalse & self expensiveTrue. "an expensive way to get false"
self cheapFalse and: [self expensiveTrue]. "a cheap way to get false"
Schnozzle answered 14/9, 2021 at 23:55 Comment(0)
S
9

One obvious difference is that and: is a keyword message thus you can write something like

a > b and: [b < c]

while with & you would need parentheses in this expression:

a > b & (b < c)

because all the binary messages (+, -, >, <, &, |) have the same precedence.

More importantly, and: and or: expect blocks while & and | expect values. This means that you can write

this shouldRedraw and: [ obj stateChanged ]

where obj stateChanged will be executed only if this shouldRedraw is true. This is useful if you want to optimize your code and avoid computing something which is not needed at the moment.

Strikebound answered 14/9, 2021 at 23:47 Comment(3)
You should put "b < c" in a block in you first code example. Also, shouldCompute should be changed to shouldRedraw.Schnozzle
Hi @JamesFoster, thank you very much for reviewing my answer!!Strikebound
Note that nothing prevents passing a block to a binary message in the language (if you wish, you can create a binary message that expects a block argument). It's just a convention used in the Kernel library.Urbannai

© 2022 - 2024 — McMap. All rights reserved.