I’ve been alluding to some potential “non-local” mechanisms that would enable a more convenient syntax. A have dug slightly deeper into what this would imply and come to the conclusion that it’s a definite no-go.
One tempting case would be to enable a short and sweet signal.bind(component::setText) syntax for creating generic bindings without dedicated methods in all classes. For this to make sense, we would need a way of doing automatic resource management, i.e. so that the signal instance can automatically stop referencing the component instance when the component is detached. The challenge with the syntax is that there’s no direct way of “extracting” component from the Consumer<T> instance that the method receives. Furthermore, you would expect signal.bind(value -> component.setText(value)) to behave in exactly the same way. (Yes, I’m familiar with the fragile serialization trick and how Project Babylon might give a better solution in the future.)
This could be “fixed” by making setText register itself with a thread local so that a detach listener could be added after running the callback. Something like Effect.getCurrent().ifPresent(effect -> effect.addLifeCycleOwner(this)). This would, however, be a disaster waiting to happen whenever there’s conditional logic inside the callback since that might lead to some resources not being detected:
signal.bind(value -> {
if (value.length() > 5) component.setText(value);
});
The callback will always have a reference to the component instance but it will be detected only in some cases. In other words, the mechanism would give the developer the false impression that they don’t need to care about resource management but there would in practice be some non-trivial cases where memory could still leak.