-
-
Notifications
You must be signed in to change notification settings - Fork 218
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
f32
vs f64
in Godot APIs
#510
Comments
IMO 5. is the best option from integration safety standpoint. Additional From other points, first point of 2. seems fairly safe and reasonable. I don't think that we should touch return types - I don't know if somehow-somewhere the return type conversion wouldn't make us differ too much from Godot. Return types from Godot methods won't always go straight into another Godot methods straight away. On the other hand Godot itself seems to be doing something like hidden type conversion with its I would also take 1. into consideration if we would like to keep things explicit. Also seems reasonable, but I have some uneasy feeling about that which I can't really articulate. |
Note that we can actually define a function like this atm: #[func]
fn foo(&self, f: f32) -> f32 {
f
} |
I would be in favor of (5) as well. Rationale:
My least favorite would be (1), in particular the first sub-bullet-point variation. Looking at the Godot source shows that there are quite a few things that are explicitly typed as |
Going against the consensus so far, I like (1). :) I respect the Rust purity arguments above, but I also get tired of writing monstrosities like: fn integrate_forces(&mut self, &mut physics_state: Gd<PhysicsDirectBodyState2D>) {
let mut xform = physics_state.get_transform();
xform.origin.x = wrapf(
f64::from(xform.origin.x),
0.0,
f64::from(self.screen_size.x),
) as f32; since Vector2 is f32, but the godot::engine::utilities take f64. (I'm new to Rust and Godot. Maybe I'm just doing it wrong.) Another option would be to extend the API. For example, |
If you use fn wrapf(x: f32, min: f32, max: f32) -> f32 {
godot::engine::utilities(x as f64, min as f64, max as f64) as f32
} Note that the majority of things in trait FloatWrap {
fn wrap(self, lower: f32, upper: f32) -> f32;
}
impl FloatWrap for f32 {
fn wrap(self, lower: f32, upper: f32) -> f32 {
let range = upper - lower;
let mut result = (self - lower) % range;
if result < 0.0 {
result += range;
}
result + lower
}
} And than your example becomes: fn integrate_forces(&mut self, &mut physics_state: Gd<PhysicsDirectBodyState2D>) {
let mut xform = physics_state.get_transform();
xform.origin.x = xform.origin.x.wrap(0.0, self.screen_size.x);
} My point is: There are always rather simple options to work around the "noise" if needed. In my opinion, this doesn't justify just throwing away any |
Generally, I agree. Anything around linear algebra should be This is already mostly the case, but there are remaining inconsistencies in Godot.
I don't think we should just accept this 🙂 Noise is noise, and in this example, every single The magic that lilizoey mentioned might be a trade-off, but for now it works more by accident than by design 😉 and if the signature differs from the trait, it means it's less discoverable, IDE completions will still give you the Overall, I get the feeling that we need to look more closely at individual APIs before making a big decision. Maybe if we manually set So if anyone encounters concrete cases of friction, please post them here! |
I'd prefer #5 as well. As much as I agree ergonomics are paramount in games, a cast seems fairly minor and I'm a little worried about introducing subtle bugs due to round tripping f64's from C++ through gdext and back into Godot. If we squeeze through f32's "under the hood" there it can be pretty surprising for some godot code using a 3rd party gdext module for instance to get back not what they sent in. |
This came up in C#, but was decided against 😀 godotengine/godot#74070 Nonetheless, an important argument was mentioned:
For people who really need Since a lot of people mentioned "a bit of boilerplate doesn't hurt" in this discussion, I'm sure it's fine if the rare |
The confusion around the use of different floating-point types keeps coming up. A lot of people lose time and wonder why they need to convert the
delta: f64
parameter when working withVector2
, which isf32
based. Even our Hello World tutorial needs to deal with this, distracting from more important topics. At the same time, it is arguable whether people typically need the 8-byte precision in games (although it's definitely nice to have it when truly needed).In C++ and GDScript, this is less of a problem. GDScript only has one type
float
(which is 8 bytes except in vectors etc. if single precision builds are used). C++ has both but allows implicit conversions, so multiplyingdouble
withfloat
is not such a ceremony as in Rust.I see multiple options here.
Make all API types
f32
by default.f64
. Either we couple this to the existingdouble-precision
feature, which is technically slightly different, but it could make sense that people who care about this enough would also wantdouble-precision
.Magic on the API boundary.
engine
methods, we could acceptimpl Into<f64>
parameters. However, return types would still need to bef64
orf32
.#[func]
methods, proc-macros could silently translatef32
in parameter and return-type position tof64
. This would however be a departure from "use pure Rust with attributes" and could also confuse static analysis tools, as well as users that encounter signatures different from the trait methods.Keep using both
f32
andf64
, but integrate them wherever possible.Use custom types.
Float
that can be converted to bothf32
andf64
. It could have some integrations like multiplications with vectors etc. But in practice, it won't simplify that much -- you'll usedelta.as_f32()
instead ofdelta as f32
, so ergonomics are questionable.Duration
,Angle
etc. While very interesting by itself, we might not be ready to add those, as we'd need to manually annotate the entire Godot API surface.impl Into
parameter trick), so having a new type means mostly that you now even need to convert tof64
.f32
,f64
,real
and now this.Don't care.
f32
andf64
are mixed apart from "that's what Godot does". And maybe that's enough of an explanation, but to some extent it's a cop-out.The text was updated successfully, but these errors were encountered: