Question

A class I am taking currently requires us to do all of our coding in smalltalk (it's a Design class). On one of our projects, I am looking to do some things, and am having a tough time finding how to do them. It seems that what most people do is modify their own version of smalltalk to do what they need it to do. I am not at liberty to do this, as this would cause an error on my prof's computer when he doesn't have the same built-in methods I do.

Here's what I'm looking to do:

Random Numbers. I need to create a random number between 1 and 1000. Right now I'm faking it by doing

rand := Random new.
rand := (rand nextValue) * 1000.
rand := rand asInteger.

This gives me a number between 0 and 1000. Is there a way to do this in one command? similar to

Random between: 0 and: 1000

And/Or statements. This one bugs the living daylights out of me. I have tried several different configurations of

(statement) and: (statement) ifTrue...
(statement) and (statement) ifTrue...

So I'm faking it with nested ifTrue statements:

(statement) ifTrue:[
    (statement) ifTrue:[...

What is the correct way to do and/or and Random in smalltalk?

Was it helpful?

Solution

The problem is that

 (expr) and: (expr) ifTrue: aBlock

is parsed as the method and:ifTrue: If you look at the Boolean class (and either True or False in particular), you notice that ifTrue: is just a regular method, and that no method and:ifTrue: exists - however, plain and: does. So to make it clear that these are two messages, write

((expr) and: (expr)) ifTrue: aBlock

For longer boolean combinations, notice that there are also methods and:and: and and:and:and: implemented.

OTHER TIPS

(1 to: 1000) atRandom

If you're using VisualWorks, and: takes a block as an argument, so you'd write:

(aBoolean and: [anotherBoolean]) ifTrue: [doSomething].

There's also &, which does not take a block as argument,

aBoolean & anotherBoolean ifTrue:[doSomething].

The difference is and: only evaluates what's in the block if the first bool is true (similar to java), while & always evaluates both.

Thus and: comes in handy if the second condition is computationally expensive, or if it includes state alterations which should only happen when the first condition is true. (that's usually a bad design though).

As for the Random, as long as you deliver your custom method, Random >> between: and: as well as the rest of your code, it runs fine on your professors computer. How to do that specifically, depends on the format in which you are supposed to deliver the assignment.

As for the Random issue: it depends on what ST version you use. In Squeak 3.9, there is Random>>#nextInt:, which is documented as "Answer a random integer in the interval [1, anInteger].". Its implementation reads

(self next * anInteger) truncated + 1

So I have two comments here:

  1. You should really learn to use the class browser. This can answer the (frequent) questions "what messages can I send to objects of class X"
  2. It is common, in ST, to add new methods to existing classes. So if you want Random to have between:and:, just add it, e.g. as

    between: low and: high      
       ^(self next * (high-low+1)) truncated + low
    

To put it simply, without knowing the Smalltalk dialect, I can only give a general answer. The way you stated the random question, yes that's the only way to do it if your professor needs a generic answer.

As for the and/or statements question,

And/Or statements. This one bugs the living daylights out of me. I have tried several different configurations of

(statement) and: (statement) ifTrue...
(statement) and (statement) ifTrue...

What you want to try is:

(statement) and: [statement] ifTrue: [ ... ]

note the brackets, the and: method takes a block as an argument.

To create several random integers between 1 and 1000
First create a random number series. Do this just once.

Then create a new random number by taking the next number from the series. Repeat as necessary.

aRandomSeries := Random new .
    "Seed a new series of random numbers"  

aRandomInt := aRandomSeries newInt: 1000 . 
    "generate a random integer between 0 and 1000"

anotherRandomInt := aRandomSeries newInt: 1000 .
    "generate another random integer between 0 and 1000"

Logical operations

aBoolean will respond to and: and or:. They both take block arguments.

Here is how they work.

and: alternativeBlock
If the receiver is true, answer the value of alternativeBlock; otherwise answer false without evaluating alternativeBlock.

or: alternativeBlock
If the receiver is false, answer the value of alternativeBlock; otherwise answer true without evaluating alternativeBlock.

e.g.
( 3 > 2 ) or: [ 3 < 4 ] ifTrue: [ ]
aBoolean and: [ anotherBoolean ] ifFalse: [ ]

However, Squeak and Pharo Smalltalks will both accept an argument in parentheses ( )
Dolphin Smalltalk will not, and strictly requires the standard Smalltalk syntax of a block argument.

Other related methods:
& an AND that does not require a square bracketted (i.e. block) argument
| an OR that does not require a square bracketted (i.e. block) argument
& and | work in Amber, Cuis, Gnu, Pharo, Squeak, VisualAge and VisualWorks Smalltalks.

Squeak Smalltalk also provides:
and:and: }
and:and:and: } These take multiple block arguments
and:and:and:and }

or:or: }
or:or:or: } These take multiple block arguments
or:or:or:or: }

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top