What is the best way to enforce certain values ​​in message arguments in smalltalk?

I am working on a simple board game in Pharo, and I have a method on my board that adds objects to a cell. Cells are just a dictionary of points on objects.

As part of the method, I would like to ensure that the point is greater than zero, but less than the width and height of the board, in other words, it should actually be on the board. What is the best way to do this?

My current attempt is as follows:

at: aPoint put: aCell

((((aPoint x > self numberOfRows) 
    or: [aPoint x <= 0]) 
    or: [aPoint y > self numberOfColumns ]) 
    or: [aPoint y <= 0]) 
    ifTrue: [ self error:'The point must be inside the grid.' ].

self cells at: aPoint put: aCell .

Kind of lisp -y with all these parens! But I can’t use short-circuiting or:without closing every expression, so it is evaluated as a logical, not a block (or as a message or:or:or:or:). I could use a binary operator |instead for a short circuit, but that doesn't seem right.

So what is the correct Smalltalk-ish way to handle this?

+3
source share
3 answers

Usually or:nested as follows:

(aPoint x > self numberOfRows 
    or: [ aPoint x <= 0  
    or: [ aPoint y > self numberOfColumns
    or: [ aPoint y <= 0 ] ] ])
        ifTrue: [ self error: 'The point must be inside the grid.' ].

Your nesting is short but less efficient due to repeated tests of the first argument (check the bytecode to see the difference).

An alternative you can use is assert:or assert:description:, which is defined on Object:

self
    assert: (aPoint x > self numberOfRows 
        or: [ aPoint x <= 0  
        or: [ aPoint y > self numberOfColumns
        or: [ aPoint y <= 0 ] ] ])
    description: 'The point must be inside the grid.'
+6

, , .

isValidPoint: aPoint
  aPoint x > self numberOfRows ifTrue: [^ false].
  aPoint x <= 0 ifTrue: [^ false].
  aPoint y > self numberOfColumns ifTrue: [^ false].
  aPoint y <= 0 ifTrue: [^ false].
  ^ true.

, . , .

+4

You can simply fill the dictionary of “cells” with all the points that are valid within the range, that is, somewhere in the initialization that you put:

1 to: numberOfRows do: [:y |
  1 to: numberOfCols do: [:x |
     cells at: x@y put: dummy "or nil " ] ]

then your method of adding a cell at a given point will look as simple as:

at: aPoint put: aCell

   self cells at: aPoint ifAbsent: [ self error: 'The point must be inside the grid.' ].
   self cells at: aPoint put: aCell .

There is also a helper method #between: and: that you can use to minimize code clutter:

((aPoint x between: 1 and: self numCols) and: [
 aPoint y between: 1 and: self numRows ]) ifFalse: [ ... bummer ... ]
+3
source

Source: https://habr.com/ru/post/1779679/


All Articles