Smalltalk if-chain refactoring without class exploding

How does Smalltalk prevent the use of caseOf: what alternatives exist to implement the following situation without exploding the class?

self condition1 ifTrue: [ self actionForCondition1 ] ifFalse: [ self condition2 ifTrue: [ self actionForCondition2 ] ifFalse: [ self condition3 ifTrue: [ self actionForCondition3 ] ifFalse: [ .... ] ] ] 
+6
source share
4 answers

If you scroll to the end

http://www.desk.org:8080/CampSmalltalk/control%20flow

you will find an offer

"There are four ways to express a case-statement in Smalltalk."

and then links to examples.

The text is in the middle of a slightly longer series of pages and periodically refers to a hypothetical tutor and students in the Smalltalk course for illustration; you can ignore this for the purposes of your question)

+3
source

Depending on how your conditions look?

  • If your conditions are type tests

     anObject isKindOf: aClass 

    you can send to the class instead, which means that you are calling the action method on anObject .

  • If your conditions are equality tests

     anObject = anotherObject 

    you can use the dictionary with the object key, and the action is like closing a block.

  • As a final restart, and if nothing else helps you, you might want to rewrite the proposed code to avoid unnecessary nesting:

     self condition1 ifTrue: [ ^ self actionForCondition1 ]. self condition2 ifTrue: [ ^ self actionForCondition2 ]. self condition3 ifTrue: [ ^ self actionForCondition3 ]. ... 
+6
source

I think, at that moment when you need to write this code, I will ask myself why I have to write so many conditions in order to proceed to the next step in my algorithm. Maybe it's time to think what is wrong with the model? Especially if you think that the semantics of message search is actually a case argument:

 selector = selector1 ifTrue: [ invoke method1 ] ifFalse: [ selector= selector2 ifTrue: [ invoke method2 ] ifFalse: [...] ]]]. 

Thus, you should try to turn this into your advantage - use the instruction of the VM operator instead of writing your own.

Using a simple principle: don't ask (object isSomething ifTrue: [self doSomething]), but say (object doSomething), you can avoid having many branches in your code. Of course, sometimes this is not applicable and highly dependent on the situation, but I often prefer to have additional sending messages, rather than another branch in the code.

+2
source

You should take a look at dual dispatch . Depending on how the tests and actions are performed, you can use dual dispatching with a big advantage.

You want a code that looks like this:

self conditionAction performAction.

or

self conditinAction performAction: actionArgs

The #conditionAction method should return a unique instance of the object for each unique condition (without using the case :) operators themselves.

You would not want to make the problem of creating classes to avoid the case case, but in the real world you may have some unique classes that you can use.

+1
source

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


All Articles