WeakDelegate <> nil but method is gone

you can simply stuff the value of the weak ref in a local variable, so you keep it alive for the time of the method.

I wished something easy able to affect Michael’s case, something like:

If me.callback.hold() then // Force a +1 reference to the class, if main reference nilled in another place, the object would still alive
    CallbackMethod(me.callback).invoke   // After hold(), never NilObjectException here!
    me.callback.release() // if free, let it go, -1
End if

Well, for that we have a feature request to ask for the target object of a weak reference.
Maybe you sign on?

Retrieving the target() object is interesting, but maybe internally a hold() / release() like feature can be less costly for the sake of retaining the reference, maybe allocates less memory, maybe faster, and gives the status of the retention or not in just one step ( the if ref.hold() then… ). So, I’ll let this point open for further discussion with the engineers. Maybe both? I would like to know their opinions on the subject when they (or Joe) have some time to think about it.
Just a remark, if the release() is not manually called, when the “ref” goes out of scope, the ref.destructor() will take care of the doing as much releases as holds was previously called (internally, to be true, probably it’s just one step). This will keep the reference count balanced in case of omitting or missing some releases.

Well, if you simply assign the local variable with the target, you have it:

dim v as variant = me.callback.WeakTarget.Value If v<>nil then // Force a +1 reference to the class, if main reference nilled in another place, the object would still alive CallbackMethod(me.callback).invoke // After hold(), never NilObjectException here! v = nil // if free, let it go, -1 End if

this will do the hold.

I’m not able to follow all this conversation, so this may be naive or already covered but I think you can use WeakAddressOf safely and without try/catch if you also use a WeakRef to track when the delegate is valid.

[code]Class Class1
Sub foo()
Msgbox “hi”
End Sub
End Class

Delegate Sub myDel()

Sub Action()

dim obj As new Class1

dim callback As Variant = WeakAddressOf obj.foo //whenever you get a weak delegate
dim trackRef As new WeakRef(obj) //also weak link to the instance

if trackRef.Value <> nil then //if the weakRef is ok
myDel(callback).Invoke //then this should work
else
MsgBox “nil”
end

obj = nil

if trackRef.Value <> nil then //if the instance is nil don’t invoke
myDel(callback).Invoke
else
MsgBox “nil”
end

End Sub[/code]

This can easily be wrapped in a class for something like

[code] dim callback As new MyWeakDelegate(obj, WeakAddressOf obj.foo)

if callback.isValid then
myDel(callback.Value).Invoke
end[/code]

Will, you do manually what should be built in. The WeakRef is there internally, it just needs to be exposed via a property.

Christian, your example is elegant, but not clear for a starter. It’s more a trick than a clear way like having 2 specific methods like hold()/release() in your referrer object. That’s clear, functional, with entries in the manual and how to use it and why to use it. Variants have high cost. Creating a new variant just to sustain the lifespan of an object instead of telling the system “hey, just hold the target object for me while I do some work” (probably will increase the weakref object layout in just in just one integer to keep track of the numbers of holds done needing releases in the clean up phase) and the final processing is faster than allocation/deallocation of variants just for this reason. that said, I am not against your idea, I support that as an advanced feature. More like a tool, to be able to access the target, than holding a weak target from disappearing unexpectedly in the middle of a processing.

Will, seems that your idea can fail if your Class1 obj is declared in another place, in another scope, and this Action() is from a timer:

  if trackRef.Value <> nil then  //if the weakRef is ok, go. (At this test time the obj is there)
    .
    myDel(callback).Invoke      //It can raise an NilObjectException here (or after), because, somewhere, the target object was gone just after the "then".
   .

Rick, did you fill a feature request?

I think Xojo Inc. does not want people to mess around with reference counting.
But a way to handle this is to actually have a tag property on the delegates. You can than assign the target weak ref’s value to the tag to increase ref count and later set to nil to decrease.

How’s it any more tricky than

Dim d as new date

Which creates an object & increments the ref count ?
That object won’t be released until the ref count = 0
That’s absolutely consistent across the language

Norman, you probably skipped parts of this conversation, we are talking about weak references and their consequences, the current caveats leading to bugs, and suggestions on how to improve the current mechanics to make it more reliable. Advanced features. Not about normal object instantiation, their ref counting, and their life on simple scopes.
When the time comes to take action on this subject, read this discussion carefully and weigh the options.

Christian, I’ll not fill a FR unless someone from Xojo says me to do so. Your current FR points to this conversation, so they should be aware of our arguments while pondering their decisions.

Just an observation. People will not mess around ref counts. People will just call hold(), release() or let the referrer go out of scope and do an auto-release if held. The internals of those are controlled by Xojo. I was just commenting supposed internal ways of doing it. How exactly, the best way, the fast way, the less resource hungry way, only they know.

[quote=62773:@Rick Araujo]Norman, you probably skipped parts of this conversation, we are talking about weak references and their consequences, the current caveats leading to bugs, and suggestions on how to improve the current mechanics to make it more reliable. Advanced features. Not about normal object instantiation, their ref counting, and their life on simple scopes.
When the time comes to take action on this subject, read this discussion carefully and weigh the options.[/quote]
Please don’t assume what I have / have not read and apply assuming anything.
I’ve read the whole thing from the outset.
There is already syntax that does hold & release in the language and its the same language as we already have for creating objects & references to them - thats precisely what the code I posted does. Create an object get a reference to it and retain the object until all the references are nil and the objects ref count goes to 0.
An exception when you invoke it and whether that is raised because the target is nil is one issue.
An exception when you invoke it that is raised because the target is not nil but encounters other problems that raise NOE’s is indistinguishable
And therein lies one of the fundamental issues - you can’t currently tell what the case is if you get an exception.
A new exception type would help some but won’t fix everything.
Hold & release don’t solve that problem - and if you feel the need for hop & release don’t use weak delegates - use addressor as that holds a hard reference & increments the target reference count so it won’t disappear from under you.
But that runs sounder to why you’d use weak delegates in the first place.

I’ll refrain from replying further until Joe replies as he has somewhat more perspective on this.

And I too, my final words. :slight_smile: My main interest was adding more views on the subject, making suggestions for further analysis, and it’s done. Better if enhanced to avoid prolific code with exception catching and extra variable creations on the user side, as I tried. As for the motivations on why people make such kind of decoupled reference leading to those bug conditions, I don’t know, but I assume that people like Michael, Christian and Thom have logical reasons to do so instead of a fully coupled one. Let’s see what will be done to solve this question. :wink:

Is there any definitive answer to this?

Yeah: there needs to a new member on Delegate (something like ‘IsTargetValid’).

See Feedback case 26060 and 20844.

Thanks Christian.

Any ETA Joe? These reports are marked simply as “reviewed”.