Skip to content

f32 vs f64 in Godot APIs #510

@Bromeon

Description

@Bromeon

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 with Vector2, which is f32 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 multiplying double with float is not such a ceremony as in Rust.

I see multiple options here.

  1. Make all API types f32 by default.

    • Allow people to opt-in to f64. Either we couple this to the existing double-precision feature, which is technically slightly different, but it could make sense that people who care about this enough would also want double-precision.
    • Alternatively, a separate feature. I would need to have very good reasons here; we already have lots of Cargo features and I want to avoid their proliferation -- to keep usage simple and since it's impossible to test all combinations properly. I'd almost say we should try combining it with the existing feature first, and then wait for concrete user feedback.
  2. Magic on the API boundary.

    • For engine methods, we could accept impl Into<f64> parameters. However, return types would still need to be f64 or f32.
    • For user-defined #[func] methods, proc-macros could silently translate f32 in parameter and return-type position to f64. 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.
  3. Keep using both f32 and f64, but integrate them wherever possible.

    • Vector operators would accept both parameter types.
    • This falls short since vector fields still have one type, and return types also have one type. We will still need conversions, just in some places not. Not sure if this truly makes code clearer.
  4. Use custom types.

    • Either a generic Float that can be converted to both f32 and f64. It could have some integrations like multiplications with vectors etc. But in practice, it won't simplify that much -- you'll use delta.as_f32() instead of delta as f32, so ergonomics are questionable.
    • Use specialized types like 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.
    • In general, I'm not sure we win that much here. Rust doesn't have implicit conversions (apart from the impl Into parameter trick), so having a new type means mostly that you now even need to convert to f64.
    • Also, it makes the type system more complex -- there is f32, f64, real and now this.
  5. Don't care.

    • We say that the current solution is the best possible one. This would be the rusty approach, saying "things are maximally explicit, your problem if the code is verbose".
    • Not sure if I particularly like this approach, especially in gamedev where pragmatic approaches and productivity are often preferred. See also Ergonomics and Panics for a similar discussion.
    • There is clear indication from Discord help requests that the status quo brings some confusion. We don't have a good explanation why f32 and f64 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: engineGodot classes (nodes, resources, ...)c: registerRegister classes, functions and other symbols to GDScriptquality-of-lifeNo new functionality, but improves ergonomics/internals

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions