-
-
Notifications
You must be signed in to change notification settings - Fork 251
Add Plane::invalid()
(originally Default
)
#456
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
Conversation
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-456 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks like setting all components to 0 also matches the GDScript behavior.
What I do wonder however, is this a good default to have? Such planes are always degenerate. What is the use case other than "others have it too"?
For Callable
, we deliberately don't provide Default
and instead have the Callable::invalid()
constructor.
Unlike It might also for similar reasons make sense for On another note |
From the user point of view, that's an implementation detail. Having a default state is orthogonal to whether it's implemented in Rust or backed by the engine. We could use
But when would you do that? If you have an In general, having some traits not implemented potentially avoids errors in generic programming, because it forces the user to be conscious about invalid states. Sure, it can make a few situations slightly more complex, but I'd rather have people use Think about it like this: if we designed our own |
The more I reflect upon it, the more I think we should revisit other builtin types.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@you-win Could you replace the Default
derive with a named invalid()
constructor + docs?
If you want, you can also do that for other types marked "❌", but it's also fine to stick to Plane
in this PR.
b64d0be
to
0d7ac18
Compare
Updated to add a new
|
You can just do #[derive(GodotClass)]
#[class(init)]
struct Foo {
#[init(default = Plane::invalid())]
plane: Plane,
} like you would in other cases where there is no |
Yeah, this special need for If someone sees #[init(default = Plane::invalid())]
plane: Plane, , then it's immediately obvious that this field must be properly initialized somewhere. Otherwise, |
Is the ask to remove the I am personally not in favor since it removes the |
Yes, exactly.
I presented the rationale in this reply. What are your arguments to keep it? To me, "because GDScript has it" is not a sufficient criterion for inclusion in Rust; we try to build a more type-safe API whenever possible. |
I am using Rust and GDext because I want to interact with Godot from Rust. I want things from Godot to work like they do in Godot. Type-safety is fine, but I do not think taking that choice away is the correct decision here. Modeling Additionally, keeping the default impl keeps the API closer to the GDScript and C++ apis, which reduces the strain of context switching between all 3 languages. Coming from GDScript or C++ where Having a consistent API surface with the option for additional safety is great. Taking away that option is too opinionated, especially when the library is a binding to something else. |
This reply tries to answer some considerations from a general API design perspective, and hopefully helps at understanding why certain things are done the way they are. For
I see that point, and tend to agree that we should generally strive for exposing all possible Godot functionality in Rust. Where I disagree however is that the API must be the same. This is already not the case for a ton of things:
This is by the way no different for any of the other As I see it, the reason why GDScript must have a default for every built-in type is because it keeps the language simple, and GDScript is simply not powerful enough to express something like
That's a matter of documentation and discoverability. We can mention this at the top of Or even in the book, and make sure the
You, yes. One thing to consider though is that there's a balance between "how close are we to GDScript" and "how close are we to idiomatic Rust". A lot of users approach godot-rust from the Rust angle, meaning they expect Rust idioms and are equally surprised if we do things in a Godot-specific way that feels strange in Rust. There's no general answer to this question; it's a case-by-case trade-off. |
When mapping The thing is, if you have TLDR: I'm not categorically saying
The 2nd and 3rd point are somewhat hard to estimate without seeing real-world code. So I'm interested, could you elaborate a bit on the concrete scenarios that made you miss a |
We can actually pretty easily support this now by implementing impl GodotFfiNullable for Plane {
fn flatten_option(opt: Option<Self>) -> Self {
opt.unwrap_or(Plane::invalid())
}
fn is_null(&self) -> bool {
self.normal.length() == 0
}
} Which would make |
e7929d1
to
81f4308
Compare
81f4308
to
5d08dae
Compare
Updated to just contain the |
Interesting idea! And cool that the trait would support that 🙂 We'd probably still need to see if that makes things actually easier in practice, or if it's rather confusing because
Thanks! I'm definitely interested in more use cases here, so feel free to raise them in the future as well. Some more thoughts (no need to respond, but for reference later on):
Generally, I don't think writing These are the problems that arise (this is not current proc-macro syntax): // Would this be allowed?
#[export]
plane: Plane,
// But this is OK because explicit:
#[export(default = Plane::invalid())]
plane: Plane,
// Or even special syntax:
#[export(invalid_default)]
plane: Plane,
// This is also OK because default is None:
#[export]
plane: Option<Plane>, We also have the exact same problem with So this should be seen in a wider context. I'm also working on some |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
Plane::invalid()
(originally Default
)
I checked the other Godot core types and they all look like they derive/impl default, so
Plane
is the only type that needed to be changed.