Unsubscribing to events – how?

About Monkey 2 Forums Monkey 2 Programming Help Unsubscribing to events – how?

This topic contains 5 replies, has 3 voices, and was last updated by  degac 1 year, 5 months ago.

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #11595

    Diffrenzy
    Keymaster

    In my actor class, I do this:

    How and when do I unsubscribe ?

    If I used a method like below instead, could I (and shouldn’t I ) do  Sequencer.BeatEmitted-= IGotABeat somewhere, and if so where?

    I put it in

    and that seems to work, but what if Discard is not called?

    [EDIT]: Does Mx2 have Destructors?

    #11608

    Mark Sibly
    Keymaster

    and that seems to work, but what if Discard is not called?

    If Discard is not called, IGotABeat will never be ‘removed’!

    >[EDIT]: Does Mx2 have Destructors?

    No.

    [EDIT] To clarify a bit: I don’t think they’d be much use in this case – and I assume you mean finalizers, ie: a method called when an object becomes unreachable?

    Assigning (or adding) a method to a function pointer has the effect of keeping the method’s ‘instance’ alive for at least as long as the function pointer remains alive, so while an object is pointed to by a reachable function pointer, it will itself be reachable and therefore it’s finalizer will never be called!

    Unless of course the function pointer itself becomes unreachable, but at that point there’s no point in the object -= itself anyway.

    There is an ‘unsafe’ finalizer in the std.resource.Resource class, but this is only intended for discarding OS resources like files, textures etc. Code in resource finalizers must be careful not to touch member objects, arrays or function pointers as there is no logical ‘order’ in which resource finalizers are called so there is no way of knowing which members may have themselves already been finalized, or even freed, when a finalizer runs.

    It might be possible to fix this and add ‘real’ finalizers to the monkey2 language, but I am currently unaware of a way to do it without seriously forking up the incremental GC system and I’m not prepared to do that at this point. If there was a huge demand for it I might be keener (maybe) but I would much rather explore alternate ways to solve problems like this – we have a whole language to play with after all.

    But as mentioned above, even with real finalizers we still have a problem in this cae, and the solution probably involves ‘weak references’ of some sort, ie: if you want an object to be able to -= itself from a function pointer when it becomes unreachable, then you’re implying that being assigned to the function pointer doesn’t ‘count’ as being reachable in the first place! And it may be possible to build something like this into the language – I haven’t thought a whole lot about it, but some kind of mechanism that combined finalizers with weak references might be an interesting idea as they kind of imply each other (in the above case anyway).

    #11614

    Diffrenzy
    Keymaster

    Thanks for explaining. Yes I think I’m talking about Finalizers, but I get why that won’t work If the subject still keeps a reference to the listener.

    I get now that in order not to have objects, that cant be GC’ed, I must remember to call

    before my object goes out of scope, there is no automatic magic cleanup.

    Sounds like I just have to keep this in mind from http://gameprogrammingpatterns.com/observer.html

    This is such a common issue in notification systems that it has a name: the lapsed listener problem. Since subjects retain references to their listeners, you can end up with zombie UI objects lingering in memory. The lesson here is to be disciplined about unregistration.

    #11617

    degac
    Participant

    Sorry, really unclear for a newbee like me!
    Not at the computer, so I can’t experiment to understand better the ‘+’ operator in a function pointer…
    I understand I can ‘add’ a new ‘rule’ (=a pointer to the method IGotABeat), so (if I’m correct) when something happens to my object (sequencer in this case) I can ‘concatenate’ (via the ‘+’ operator) different ‘reactions’ (I can imagine one to print out in the console – IGotABeat_Print, one for displaying something IGotABeat_Draw etc).
    It’s right the ‘logic’ of this, or I’m out of the road???

    And the ‘-‘ operator – from what I’ve read above – in this case is useless… When I call Discard I suppose the object will be destroyed and so everything ‘connected/chained’ to it (like the pointer’s function). Or not?

    If I’m using sequencer.BeatEmitted=NULL I should ‘clear’ any ‘connections’? Right?

    ps: by the way, I think the best way to take trace of what ‘connections’ are ‘active’ is – in the object – create some sort of field/stack/etc to set the status of any possible (and know by the programmer) ‘connection’ created.

    FIELD Igotbeat_print_state:Int=ACTIVE
    Field Igotbear_draw_state:Int=PAUSED

    Or something similar, without make too much complicated the ‘under-the-hood’ management!

    Really, some features of the Monkey2/advanced OOP are … obscure to me 🙂

    #11626

    Mark Sibly
    Keymaster

    To hopefully clarify a bit:

    It’s sort of the same as if you add something to a global stack. It can never be reclaimed/finalized because the stack itself is keeping the object alive. So this code wouldn’t work:

    the lapsed listener problem.

    Yes, this is very much the issue – anything that is listening to an event wont/can’t be reclaimed by GC. And sometimes that’s a good thing, as the event may in fact be the *only* thing keeping an object alive.

    When I call Discard I suppose the object will be destroyed and so everything ‘connected/chained’ to it (like the pointer’s function). Or not?

    Well, there is no Discard. But sort of – when an object becomes ‘unreachable’ (ie: no vars can see it) all of it’s fields – including all ‘listeners’ of any function pointers – become potentially unreachable. Another way to think about it is, when an object becomes unreachable, all its fields are ‘nulled’ out, meaning other object may become unreachable etc. This is often enough to mean you don’t have to worry about any of this in the first place – when the object that is emitting events itself becomes unreachable, none of this is an issue. It’s when you have a ‘persistant’ object that you want to add/remove listeners to you have to be a bit careful to actually call -= when necessary, or the event can ‘artificially’ keep objects alive for longer than they should be. No magic finalizers can help here, we need magic weak references…

    If I’m using sequencer.BeatEmitted=NULL I should ‘clear’ any ‘connections’? Right?

    Setting a function pointer to null effectively ‘removes’ all listeners.

    Really, some features of the Monkey2/advanced OOP are … obscure to me

    But having to deal with adding/removing listeners is a pretty classic programming problem that doesn’t really have much to do with OO.

    We’re really getting into the guts of things here too – I’m going into a lot of detail which I hope isn’t putting anyone off, but in practice, none of this is really very complex.

    #11629

    degac
    Participant

    Ok, many thanks!
    Is not a problem to be complex or not, it’s just to imagine how they works/where they can be useful etc… then everything is the ‘right’ prospective!
    I need a ‘deeper’ immersion to understand things: I’m older, I’m slower… but I reach the goal 🙂

    Thanks again!

Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.