-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
Improve Object.connect
error handling
#613
Comments
Connect() has been already hugely reworked for 4.0, is any of this still relevant? |
@Zireael07 Which branch would that be? The method appears to look the same in |
@Zoomulator You can read about the signal refactor here. |
@Calinou Thanks for the link. Though I'm still confused which branch the refactoring is? It at least sounds like it was merged already. |
It's in the current
I think the error code system was left in, which means this proposal is still relevant. |
One option would be to do like a lot of libraries do with a if list_item.connect("changed", self, "__update_item", [list_button]):
__update_item(list_item) |
@cgbeutler I see where you're coming from and it's a good idea if there actually were exceptions being thrown.
The error communicate a programming error, while the return code communicate that something unforeseen happened during runtime that you can't know will happen or not when you're programming. From my experience in Godot, that's how the error handling is dealt with. A |
Yeah, I agree that it probably shouldn't print errors and return errors. A WorkaroundFor now, you could mostly achieve the desired result by making a result obj that only pushes an error if the error was never checked. Example Usage: var result = help_obj.try_connect(self, "nonexistent_signal", self, "hello")
if result.error: print( result ) #prints error here, no error pushed to editor
help_obj.try_connect(self, "nonexistent_signal", self, "hello")
# result of the above is GCd without the error being checked, resulting in an error getting pushed to editor Helper code itself: Again, it's not perfect and would probably require turning off warnings, so if that doesn't fit your workflow, you'll have to find another way. |
Object.connect
error handlingObject.connect
error handling
@Calinou Will the refactored signal code fix the following issues? (Also, I think invalid
|
Here are some error constants that could be used for return values:
But I agree that making the method return void is the better solution. |
I think returning void would be a mistake. Without some kind of feedback, there is no way to programmatically know if it connected. You would have to be aware of and check for every way connect could fail to fully know if it failed, which seems problematic for new/naive people. Heck, I don't even know if I'm checking all the cases correctly! For example, the already-in-use case is based on the flags, so the check would be: if 0 == (flags & Object.CONNECT_REFERENCE_COUNTED) and source.is_connected(signal, target, method):
return ERR_ALREADY_IN_USE Something tells me some folks may not understand these complexities of the connect command's checks. For stability of reacting to connect failures, error returns seem waaay more reliable/easy to work from. I, personally, also feel like it's a D.R.Y. violation to have to duplicate all the error checking logic that's already being done inside a function like this. If I add all the checks before calling connect, those are all technically being done twice! And if my set is off, then my error handling has a bug, which is the "Jurassic Park"(book) way of ensuring cascading failures just seem to slip on by. |
To be fair people mostly don't check for the return value either. I see very narrow application for the return value, something where you'd want to wrap I'd also say that in engine we never check the return value of |
I get the appeal for making it void, I do. This call is one that will almost always rear errors at dev time. Most of the time connect's errors are there just for a programmer to see and fix, almost more like a syntax check. Returning an error feels like hiding the syntax check, which is equally bad. Thus we have a standoff! Rare cases where connect is used in a more complex way rely on knowing if it succeeded. It is no longer a syntax check, but a programmatic one that is still needed at run-time. I guess that's why I suggested 2 separate functions. Godot often has 2 ways to do things. One for the simple use cases and one for when you need more access to what the engine is doing. (For example If adding # returns error
var err := button.connect("pressed", self, "_on_button_pressed")
# void that prints error
button.pressed.connect(self._on_button_pressed) |
|
Looking at the source here: All errors are for checking the arguments, except reference-counting. Non existing signals, methods or objects sounds like the responsibility of the caller to keep right and are efficiently communicated via push_error log messages. No other method gives a return code saying you passed a non-object, null or using a non existing method; they just break and log it. It's basic housekeeping for the user to make sure you pass sensible things to a method. That leaves the reference counting. It only returns I'm yet to see an actual complex example where the return code has been used to deal with a failing connection and adjust to another call at runtime. It would surprise me greatly if there is, as I stated in the initial post, the only error code that is currently returned is The current implementation of the return code is giving you no information about what went wrong. Leading me to conclude that the complex case that may be out there only exists in theory and is not actually a requested feature. Removing the error code would have no impact on the versatility of If in the future someone requires it for a good reason, wouldn't it be better to create a |
@Zoomulator I get that you wouldn't use the complex version. I would hope you can respect the fact that I need it. |
@cgbeutler I apologize if you took offense; I can come across as pretty blunt. I just wanted to emphasize that the current state of the error code is unusable and not worth saving for the sake of there being an error code historically. But if you do need it I'd welcome you to propose how the error code would be improved to communicate things properly for your use case. Two or one method makes no difference to me as long as we get spared the mix of error types. I'd only argue for the void variant as the default since checking return codes is easily overlooked by new users and would hide errors from them if the code is ignored. |
@Zoomulator no worries. No offense taken, just trying to figure out what folks consider "deal breakers" on this. Sounds like a I agree that the void-return version of connect makes more sense as the default. As it stands for 4.0, SO! Seems like the connect should probly be made void. If the |
Proposal edit: Applied an anti-snark filter to my writing. Sorry if I came across rude in the original proposal. |
The idea to remove the returned error has been approved! |
Describe the project you are working on:
A rouge-like game, utilizing Godot's signal design pattern to minimize tight coupling between classes.
Describe the problem or limitation you are having in your project:
The
Object.connect
method both logs an error message and returns an error code.Doing both causes a few issues; although being minor they cause a bit of confusion.
Using a return code has some other problems:
ERR_INVALID_PARAMETER
as an error for many different cases.The error code may be used to check if something is already connected.
The problem here is that there are other things that can go wrong if you as a developer pass bad arguments to the function.
This would cause the if branch to be executed for cases unrelated to the reference count.
As mentioned you'll also get the error littering the log even though you've handled it.
Adding a check beforehand would still give you proper error logging.
Comparisons can be made with
File.open
which returns an error code. The difference betweenFile.open
andconnect
is that you can only know ifFile.open
succeeds as it is being called. Even if you check that a file exists before opening, it may be gone at the moment you try to open it. In other wordsFile.open
is a non-deterministic call while a call toObject.connect
/Signal.connect
is fully deterministic.The lack of error codes in the rest of Godot makes this one stand out and makes it appear like there's more going on in
connect
than there actually is. Any error is easily avoided by some leading checks if the developer needs to handle certain states.Describe the feature / enhancement and how it helps to overcome the problem or limitation:
Make
Object.connect
avoid
function instead of returning an error code. This removes the need to explicitly ignore the error and align the function with the rest of Godot regarding error handling. It would also help new users as it's rather confusing what you should do with the return code, as I experienced myself when learning Godot.Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
All errors will be presented in the error log and the
Object.connect
method will returnvoid
.It should be as simple as changing (in
Object.connect
) theERR_FAIL_COND_V
macros to their non-value counterparts and changing the return signature tovoid
.The GDScript VM makes an error check in the yield statement which needs to be rewritten to check for bad arguments.
https://github.com/godotengine/godot/blob/master/core/object/object.cpp#L1304
https://github.com/godotengine/godot/blob/master/core/variant/callable.cpp#L385
If this enhancement will not be used often, can it be worked around with a few lines of script?:
You can disable
return value discarded
warnings, typevar _err = connect(...)
or use an annotationwarning-ignore
to just ignore it.Is there a reason why this should be core and not an add-on in the asset library?:
The proposal is to change an existing method in a core class. You could write your own utility function that ignores the return value for you, but that's a rather patchy fix. This change would mainly benefit new users; avoiding the unnecessary hookup on the obscure error code.
Addendum
It appears to me that the return code for
connect
is a remnant from another error handling pattern in earlier version of Godot that has changed a bit since. Even though it's a small annoyance, I'd say revising it falls under the ease-of-use policy.I would personally consider this to be a very simple change, though it is a breaking change. My hope is that it would be included in the 4.0 version.
Some like the idea of still having a return code that is more detailed and useful while removing the error logs. There is no precedence for this in Godot beyond the non-deterministic functions like
File.open
as explained above. This proposal is for removing the return code in the default implementation ofconnect
but would not oppose an optional method being devised to return an error code instead.The text was updated successfully, but these errors were encountered: