#ifCurtailed - why the "complete := true" line?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

#ifCurtailed - why the "complete := true" line?

Jaromir Matas
Hi,
I can't figure this one out - is the value of /complete / in #ifCurtailed
method used somewhere?
Very confusing ;) Thanks a lot!
Jaromir

ifCurtailed: aBlock
        | complete result |
        <primitive: 198>
        result := self valueNoContextSwitch.
        complete := true.
        ^result



--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: #ifCurtailed - why the "complete := true" line?

Tobias Pape
Hi


> On 13. Feb 2021, at 12:55, Jaromir <[hidden email]> wrote:
>
> Hi,
> I can't figure this one out - is the value of /complete / in #ifCurtailed
> method used somewhere?
> Very confusing ;) Thanks a lot!
> Jaromir
>
> ifCurtailed: aBlock
> | complete result |
> <primitive: 198>
> result := self valueNoContextSwitch.
> complete := true.
> ^result


Yes.
But first thing to notice is that #ensure: uses the same primitive and the same names and oder of local variables.

In both methods, the comment states:
 " The VM uses prim 198 in a context's method as the mark for an ensure:/ifCurtailed: activation"

But more so:

Look at Context>>unwindTo:

unwindTo: aContext

        | ctx unwindBlock |
        ctx := self.
        [(ctx := ctx findNextUnwindContextUpTo: aContext) isNil] whileFalse: [
                (ctx tempAt: 2) ifNil:[
                        ctx tempAt: 2 put: true.
                        unwindBlock := ctx tempAt: 1.
                        unwindBlock value]
        ].


In a Context, that is the "running" form of a Block, tempAt: 1 is the argument of #ifCurtailed:/#ensure:.
and tempAt: 2 is "completed". So: the context will be marked as being completed either via #ifCurtailed: directly or via #unwindTo:.  However, in #ensure:

ensure: aBlock
        | complete returnValue |
        <primitive: 198>
        returnValue := self valueNoContextSwitch.
        complete ifNil:[
                complete := true.
                aBlock value.
        ].
        ^ returnValue

The aBlock will only be run if the action was not completed yet.
"complete" can be set from the outside as can be seen in #unwindTo:.
It is also visible, that #unwindTo: and #ensure: have a similar structure, but #unwindTo: operates on the data structure of the "running" code.

See also in Context: #restart #resume: #resume:through:  or Process>>#terminate.

I hope this helps :)

Best regards
        -Tobias




Reply | Threaded
Open this post in threaded view
|

Re: #ifCurtailed - why the "complete := true" line?

Jaromir Matas
In reply to this post by Jaromir Matas
Hi Tobias,

>> Hi,
>> I can't figure this one out - is the value of /complete / in #ifCurtailed
>> method used somewhere?

> Yes.

That’s a great help, thanks! So I understand “complete” marks contexts that
have already been processed (unwound) during an abnormal return (in
#resume:through:) or, in case of a normal return it just marks normal
completion of #ensure/#ifCurtailed.

Just to be sure: there’s a close interplay between e.g. #ensure and
#resume:through: but NO interplay between #ensure and #ifCurtailed, right?

And finally, is there a simple example where “complete” plays a role? It
seems to me that if #resume:through: unwinds contexts it never gets to
unwind the same context twice and if the #ensure protected block returns
normally no unwinding even happens.

I tried to remove “complete” from the #ensure/#ifCurtailed code and all my
naive examples work as before :)



> But first thing to notice is that #ensure: uses the same primitive and the
> same names and oder of local variables.
>
> In both methods, the comment states:
>  " The VM uses prim 198 in a context's method as the mark for an
> ensure:/ifCurtailed: activation"
>
> But more so:
>
> Look at Context>>unwindTo:
>
> unwindTo: aContext
>
> ​    | ctx unwindBlock |
> ​    ctx := self.
> ​    [(ctx := ctx findNextUnwindContextUpTo: aContext) isNil] whileFalse:
> [
> ​            (ctx tempAt: 2) ifNil:[
> ​                    ctx tempAt: 2 put: true.
> ​                    unwindBlock := ctx tempAt: 1.
> ​                    unwindBlock value]
> ​    ].
>
> In a Context, that is the "running" form of a Block, tempAt: 1 is the
> argument of #ifCurtailed:/#ensure:.
> and tempAt: 2 is "completed". So: the context will be marked as being
> completed either via #ifCurtailed: directly or via #unwindTo:.  However,
> in #ensure:
>
> ensure: aBlock
>         | complete returnValue |
>         <primitive: 198>
>         returnValue := self valueNoContextSwitch.
>         complete ifNil:[
>                 complete := true.
>                 aBlock value.
>         ].
>         ^ returnValue
>
> The aBlock will only be run if the action was not completed yet.

Now this confused me: if the protected block returns normally, that means no
unwinding has happened and thus “complete” must be nil and aBlock will
always be evaluated.

Conversely, if the protected block returned abnormally I thought it meant
the process would never reach the condition and the aBlock would never be
run here (but on the unwind path instead).

Where am I wrong?

(I used this to explore: [x := thisContext sender explore. ^1] ensure: [x
explore] )

Thanks again!
Jaromir



> "complete" can be set from the outside as can be seen in #unwindTo:.
> It is also visible, that #unwindTo: and #ensure: have a similar structure,
> but #unwindTo: operates on the data structure of the "running" code.
>
> See also in Context: #restart #resume: #resume:through:  or
> Process>>#terminate.
>
> I hope this helps :)
>
> Best regards
>         -Tobias



--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir