Is it possible to follow an object through a computation?

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

Is it possible to follow an object through a computation?

Pharo Smalltalk Users mailing list
Hi -

Is there a way to haltOnChange or some such for an object?  


I have an instance that gets into a state I don't understand and would like to watch it or several of its inst vars for when they change.  

I could set a lot of #haltIf: statements and step through but hope someone has a better strategy


thanks & happy new year.


Paul
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to follow an object through a computation?

Esteban A. Maringolo
Hi Paul,

You can set the object to be "read only" (aka "immutable") and handle the exception.

E.g.

| u |
u := User named: 'Paul'.
u beReadOnlyObject.
[ "your code modifying u's state" ]
on: ModificationForbidden 
do: [ :ex | 
ex halt.
 "inspect state" 
u beWritableObject.
ex resume
].

Probably there is a better way to do this with slots, using default ones or subclassing `InstanceVariableSlot` for that instance only and halting on the `write:to:` method of it.

Regards,

Esteban A. Maringolo


El mié., 2 ene. 2019 a las 15:45, PAUL DEBRUICKER via Pharo-users (<[hidden email]>) escribió:
Hi -

Is there a way to haltOnChange or some such for an object? 


I have an instance that gets into a state I don't understand and would like to watch it or several of its inst vars for when they change. 

I could set a lot of #haltIf: statements and step through but hope someone has a better strategy


thanks & happy new year.


Paul
Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to follow an object through a computation?

Pharo Smalltalk Users mailing list
In reply to this post by Pharo Smalltalk Users mailing list

Hi,

if you are using Pharo 7 I have some work on object-centric debugging that could do that, using Reflectivity.

For example, with object-centric metalinks you could do the following:

##get your object (here are two instances of a trivial class which only has a "name" inst var)

obj1 := MyClass new.
obj2 := MyClass new.

 

##define a "halt" metalink:


link := MetaLink new
    metaObject: Halt;
    selector: #now;
    control: #before.   

 

##install the metalink on the  instance variable "name" of the  first object using the new Reflectivity API

obj1 link: link toSlotNamed: #name.

 

##then the system only halts when you use a method accessing the "name" slot of this object, and not for other instances


obj1 name: 'first name'. <-- halt
obj2 name: 'second name' <-- no halt

 

If you look at Object and Class classes, you will find a more detailed API to install metalinks on different structural entities and to scope them to objects. For example you can ask to halt only when a instance variable is read, or only when something is written in it (in the example above it does both).

These metalinks are only available for Pharo 7 and must be loaded from https://github.com/StevenCostiou/Reflectivity-dev and you must override the current Reflectivity code (click "load" and not "merge"). Hopefully that will be integrated and merged in Pharo 7 or 8 soon.

 

There is also that https://github.com/ClotildeToullec/Collectors/wiki which provides a history tool that stores all objects that went into an instance variable of an object (or even a temp var or a given expression). It uses the Reflectivity API mentionned above. However for now it is needed to provide a condition to scope the capture of objects to a specific instance (but it works well). This tool also gives you the stack for each modification of an instance variable. Objects are stored in memory though, so it can kill your image on too large program executions (that part is currently being investigated...).

 

I do not have time right now to get into more details, but if you try any of it and have questions please ask.

Steven.

 

Reply | Threaded
Open this post in threaded view
|

Re: Is it possible to follow an object through a computation?

Pharo Smalltalk Users mailing list
In reply to this post by Esteban A. Maringolo


> On 3 Jan 2019, at 03:17, Esteban Maringolo <[hidden email]> wrote:
>
> Hi Paul,
>
> You can set the object to be "read only" (aka "immutable") and handle the exception.
>
> E.g.
>
> | u |
> u := User named: 'Paul'.
> u beReadOnlyObject.
> [ "your code modifying u's state" ]
> on: ModificationForbidden
> do: [ :ex |
> ex halt.
> "inspect state"
> u beWritableObject.
> ex resume
> ].
>
> Probably there is a better way to do this with slots, using default ones or subclassing `InstanceVariableSlot` for that instance only and halting on the `write:to:` method of it.
>

I started an experiment to turn the read Only mechanism into a general object change notifier:

https://github.com/MarcusDenker/ChangeDetector

This allows the following style of use:


testObserveObjectWithModification [
        | observed observer |
        observed := 'test2'.
        observer := self.
        observed notifyOnChange: observer.
        "the observed object is now read only"
        self assert: (observed isReadOnlyObject).
        "but we can change it!"
        observed at: 1 put: $T.

        self assert: observed equals: 'Test2'.
        "and the method #objectChangeNotified was called, setting flag"
        self assert: flag equals: #yes.
       
        observed stopNotifyOnChange: observer.
        self deny: (observed isReadOnlyObject).


missing:

-> we need to model read only for all tracked object (we need to remember the old state and restore it)
-> think about threads… is there a problem?


        Marcus