-
-
Notifications
You must be signed in to change notification settings - Fork 646
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
Refactor callbacks #182
Comments
I would prefer it be in |
A fine idea, thanks!
This is something I'd like to avoid:
|
I am probably misunderstanding what you are trying to say so correct me if I get something wrong but
No need for one as its fully legal to store it and return it latter as the Interface class without wrapping it in another object. You can even wrap other objects in lambda methods the same way you would wrap lambda methods in full classes.
The return type would simply change from a long to the callback interface. Nothing else would need to change as it would still be a Functional interface. It would also allow for the extra overload methods that take the long (though I suppose the object type methods would be the helper methods) to be removed and not seen from the user code.
I don't know how garbage collection works with lambda functions as I have not really looked that closely at it however you said that currently you use a weak reference to an object to store it. You could do something similar for the lambda functions if needed without the weak reference part though I don't really know why lwjgl was storing that in the first pace instead of a normal reference unless memory was a concern for some reason in which case it should have been a soft reference not a weak one. |
There are two pieces of state:
The native callback object already contains a (JNI global) reference to the interface implementation. The interface implementation does NOT know anything about the native callback object (it can't know anything if we want lambdas to work). If we want an object return value, the only option is to wrap the native callback object handle in a class. What would be the point of that? |
Its supposed to return the previously set callback or null so I was suggesting a way to possibly do that (a map or something with the long value as the key and the function as the value) in object form but it should be fine ether way if nothing other than the long is needed to reset the function to what it was before if it is changed |
Sorry, I'm probably not explaining things clearly. Lets try again. The dyncall callback object ( The only thing missing now is the Java callback (the instance that implements the callback interface). This is also stored in the callback object struct, in the long keyCB = GLFWKeyCallback.create((windowHandle, key, scancode, action, mods) -> {
// ...
});
GLFWKeyCallback javaCallback = memGlobalRefToObject(dcbGetUserData(keyCB));
// or simply
GLFWKeyCallback javaCallback = Callback.get(keyCB); |
I still think it would be more like java to return the actual callback (return Mostly I was thinking of libraries that may chose the way of simply overriding the current callback with their own and calling the former callback after they have finished processing the data. Not the best way of doing things but far easier than some other ways. Though again as long as the java callback can be easily reached its fine. |
I have no issue with opaque pointers. It'd be really straightforward to make wrapper "create" that call Callback.get(cb) inside if needed. Also not a lot of code would actually call these "GLFWKeyCallback.create" anyway, so making it slightly more verbose for the cases where you do want to retrieve the callback object shouldn't have much impact, if at all. |
After implementing the proposed design above and changing all sample code to use it, I ended up not liking it very much. Specifically, I didn't like having to write edit: obsolete, see below |
The change you made makes it impossible to implement multiple callbacks now, since the shared |
@kenzierocks Could you share an example please? You're talking about multiple callbacks with compatible function signatures, right? |
The previous solution was too confusing and error prone. After further discussion a new approach has been implemented that is compatible with existing code, supports all code styles and has no clean-up surprises. Final designExample 1 (anonymous class): private GLFWKeyCallback keyCB;
// callback setup
glfwSetKeyCallback(window, keyCB = new GLFWKeyCallback() {
@Override
public void invoke(long window, int key, int scancode, int action, int mods) {
// ...
}
});
// cleanup
keyCB.free(); Example 2 (indirect lambda): private GLFWKeyCallback keyCB;
// callback setup
glfwSetKeyCallback(window, keyCB = GLFWKeyCallback.create((windowHnd, key, scancode, action, mods) -> {
// ...
}));
// cleanup
keyCB.free(); Example 3 (direct lambda): // callback setup
glfwSetKeyCallback(window, (windowHnd, key, scancode, action, mods) -> {
// ...
});
// cleanup
glfwSetKeyCallback(window, null).free(); Implementation
|
This is what I used to do @Spasi, extending the |
Method references are perfect for this case. See MouseHelp with method references. Also, don't forget to clean up your callbacks. LWJGL provides a convenient method for freeing GLFW callbacks: |
OK, I'll do that instead. Thanks! |
Like structs, native-to-Java callbacks look out-of-place in Java without special JVM support. Now that LWJGL 3 requires Java 8, we should rethink their design and implementation.
Current design
Callback.<T>
).SAM
interface in each class and apublic static <CallbackClass> create(SAM sam)
method..free()
method on the instance.Pros
Cons
SAM
) for each callback type.Recent changes
Proposed design
Callback
class becomes a utility class that only creates and destroys callback objects.long
value (opaque handle). Callback function arguments and member fields becomelong
.glfwSet<Type>Callback
function return the previously set callbacks).Pros
long
, not arbitrary types.Cons
glGetPointer(GL_DEBUG_CALLBACK_FUNCTION)
), if the handle was not already stored in user code.Callback.free(handle)
(vscbInstance.free()
currently).Example 1, similar to current design:
Example 2, without storing the callback handle:
The text was updated successfully, but these errors were encountered: