Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing Blocks in Squeak Smalltalk

I am programming in squeak and need to compare two blocks of code as follows: (toRunBlock is an instance variable)

~~~Other code~~~
toRunBlock := [nil].
~~~Other code~~~

But at some point, I need to compare it to another block of code:

(toRunBlock = [nil]) ifTrue: [
    "Run some code if toRunBlock hasn't been overwritten"
].

But that check is always giving false, and I can't find a way to check if they're equal. Can someone help me out with this?

like image 630
TheCompModder Avatar asked Jan 05 '23 21:01

TheCompModder


2 Answers

As @LeandroCaniglia pointed out, you shouldn't have to compare blocks. Here are two ways to solve your problem without comparing blocks:

  1. initialize the variable to nil. In your accessor method you initialize it lazily:

    toRunBlock
        ^ toRunBlock ifNil: [ [] ]
    

    Now, when you look at the variable toRunBlock it will be nil unless #toRunBlock has been sent or the block as been set by other means.

    Your code would become:

    toRunBlock ifNil: [
        "Run some code if toRunBlock hasn't been overwritten"
    ].
    
  2. use additional state by setting an instance variable you can check. This could be your setter method for example:

    toRunBlock: aBlock
        toRunBlock := aBlock.
        hasToRunBlockBeenSet := true
    

    And to check you could use a method like this:

    hasToRunBlockBeenSet
        ^ hasToRunBlockBeenSet ifNil: [ false ]
    

    Your code would become:

    self hasToRunBlockBeenSet ifTrue: [
        "Run some code if toRunBlock hasn't been overwritten"
    ].
    

The second method is arguably more reliable.

like image 191
Max Leske Avatar answered Jan 28 '23 15:01

Max Leske


Equality is not defined for BlockClosures, except for reference equality. Although two blocks might behave identically, they are still different because they are closures and not only snippets of code. Each block has a reference to the context (method activation or another block) where it was created in, so your two [nil]s would at least differ in this regard.

You can only check if the block is still the same as earlier by storing somewhere else what it was earlier. Assuming that [nil] is some kind of default value in your case, you could store that [nil] block in another instance variable or a class pool variable (e. g., defaultRunBlock) and compare toRunBlock (by reference) with that variable to check if toRunBlock has been changed.

Object subclass: #YourClass
    instanceVariableNames: 'toRunBlock defaultRunBlock' 
        "or as class variable:"
    classVariableNames: 'DefaultRunBlock'
    poolDictionaries: ''
    category: 'Kernel-Methods'

initialize
    defaultRunBlock := [nil]

otherCode
    toRunBlock := defaultRunBlock

whereYouCompareThem
    toRunBlock == defaultRunBlock ifTrue: [ "..." ]

Or if you wanted to check if toRunBlock changed since the last time when that latter method was called, you could store the previous value in an additional instance variable as well.

whereYouCompareThem
    toRunBlock == previousRunBlock ifTrue: [ "..." ].
    previousRunBlock := toRunBlock
like image 45
JayK Avatar answered Jan 28 '23 17:01

JayK