Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce self-deregistering closures for on / onany #48

Merged
merged 12 commits into from
Oct 5, 2020

Conversation

jkrumbiegel
Copy link
Contributor

@jkrumbiegel jkrumbiegel commented Aug 27, 2020

We still have the problem that it's hard to keep track of the connections we make with Observables and to clean them up after use. This PR seeks to help while staying close enough to the previous API, that it hopefully doesn't break too much code using Observables.

The main change is that on returns a new type ObserverFunction. This wraps the closure Function which is normally returned by on. It stores the function, the observable that is being listened to, and a weak flag. If the weak flag is set via on(..., weak = true), the ObserverFunction will call off(observable, closure) when finalized.

This allows for some easy housekeeping. Imagine some large plotting object that creates multiple connections via on. We just have to push! all weak ObserverFunctions into one big vector, and if our plot object goes out of scope, so will that vector and all the connections we made will be released.

The weak flag is set to false by default, which means that the behavior doesn't change from what we have now.

Even with weak = false, this PR can make it a bit easier to clean up Observables, as the ObserverFunctions carry both the closure and related Observable, and it's therefore easier to call off(observerfunc) without having to find both of these parts first.

I see almost no code storing the result of on in the wild right now, which would be necessary to do housekeeping (which is not being done). It would therefore be easy with this PR to improve code by storing the result and calling off on it at an appropriate time, or making the whole thing weak and let scoping handle it. If preexisting code is storing the result of on, then the receiving structure is probably typed Function, and as I've made ObserverFunction <: Function this should also not be breaking.

CI is currently failing because of some problem with ObservablePairs. I have never used this and cannot understand from the code what they are supposed to do. Neither are they documented. So I assume they are not very important.

@jkrumbiegel
Copy link
Contributor Author

jkrumbiegel commented Sep 27, 2020

@SimonDanisch @piever I fixed the problem with observable pairs, it was just an example of code that actually did do something with the return value of on.

Do you see any other potential problems with this change? Otherwise it would be great to add this soon, so I can use it to clean up some code in MakieLayout.

One difficulty is with map / map! / lift because they are expected to return an observable. So there is not really room to return ObserverFuncs. There must be some other way to simplify disconnecting them. Looking at the code I was again surprised of how little interest it must have seemed when writing this library to ever disconnect anything again :)

@jkrumbiegel jkrumbiegel marked this pull request as ready for review September 27, 2020 12:12
@SimonDanisch
Copy link
Member

Ok, I think there should be no problem merging this! @shashi, do you have any comments?

src/Observables.jl Outdated Show resolved Hide resolved
@shashi
Copy link
Member

shashi commented Sep 28, 2020

Looks good to me!

otherwise it gets annoying to ensure that no error happens when a weak observable has `off` called before being finalized. much easier if off doesn't error
@jkrumbiegel
Copy link
Contributor Author

jkrumbiegel commented Sep 28, 2020

so because of an edge case where the user could call off on a weak ObserverFunc which would cause the finalizer to fail later, I have changed off so that it doesn't throw a keyerror. It just returns true or false depending on if it could find the function and remove it. I think that should be an acceptable change and it leaves the implementation very simple. off can just run again and does no harm. No code should depend on off having no return value.

src/Observables.jl Outdated Show resolved Hide resolved
@shashi
Copy link
Member

shashi commented Oct 2, 2020

That change to off sounds good!

@shashi shashi self-requested a review October 5, 2020 14:44
@SimonDanisch SimonDanisch merged commit 00e62eb into JuliaGizmos:master Oct 5, 2020
timholy added a commit that referenced this pull request Jan 8, 2021
This addresses a comment made in
#48 (comment)
by implementing storage for the ObserverFunctions
added by `map`.
This also adds optional precompilation support for observables,
precompiling the methods based on the `T` in `Observable{T}`.
timholy added a commit that referenced this pull request Jan 9, 2021
This addresses a comment made in
#48 (comment)
by implementing storage for the ObserverFunctions
added by `map`.
This also adds optional precompilation support for observables,
precompiling the methods based on the `T` in `Observable{T}`.
timholy added a commit that referenced this pull request Jan 14, 2021
This addresses a comment made in
#48 (comment)
by implementing storage for the ObserverFunctions
added by `map`.
This also adds optional precompilation support for observables,
precompiling the methods based on the `T` in `Observable{T}`.
timholy added a commit that referenced this pull request Jan 16, 2021
This addresses a comment made in
#48 (comment)
by implementing storage for the ObserverFunctions
added by `map`.
This also adds optional precompilation support for observables,
precompiling the methods based on the `T` in `Observable{T}`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants