Skip to content

Conversation

@Bromeon
Copy link
Member

@Bromeon Bromeon commented Nov 2, 2025

Closes #381.
Allows Rust functions to provide default values via parameter attribute #[opt(default = ...)] syntax.

Example

#[func] fn method( &self, required: i32, #[opt(default = "str")] string: GString, #[opt(default = 100)] integer: i32, )

This can be called from GDScript as follows:

obj.method(123) obj.method(123, "something") obj.method(123, "something", 456)

The expressions "str", 100 implement AsArg<GString> and AsArg<i32>, respectively.
This means that by-ref types (arrays, objects, etc) must be passed with &value.

Open questions

1. Should we cache and reuse values?

  • At the moment, we re-evaluate the #[opt(default = ...)] expression on each call. What may sound silly avoids the Python "default has different value next time" problem. More on that below.
  • While performance can be a factor, the fact that all functions offering default-arguments downgrade to varcall convention means we have now a lot of pointless Variant conversions + array allocation. So it's not obvious how big of an impact re-evaluating has.
  • Caching also comes with problems, notably memory usage, thread safety and cleanups.

2. Do we allow mutable defaults?

The Python problem arises when two conditions are true: default values are reused, and they are mutable.
If we don't cache, an independent object is provided every time.

If we disallow mutable values, we need to limit the types:

  • Copy values are always fine (ints, floats, bools, vectors, transforms, colors, ...)
  • Godot CoW/immutable types as well (GString, StringName, NodePath, PackedArray)
  • Objects are impossible to make immutable (set_meta etc.)
  • Arrays/dicts would need to be typed, and are immutable if their element type is immutable and they went through into_read_only()

We could allow mutable types but with special opt-in, e.g.:

#[func] fn static_method( #[opt(mut_default = &RefCounted::new_gd())] object: Gd<RefCounted>, )

3. Unification with #[init(val = ...)]

The attribute used for field initialization, #[init(val = ...)], is very similar in its nature. Historically, it works however on T values and not AsArg<T> impls, which makes some expressions a bit different.

Mid-term it can make sense to align the two to use the same syntax, in either direction.

Conservative + incremental approach

As long as there are still uncertainties, I'd like to expose this functionality step-by-step. Starting with only a subset (e.g. limited to some "safe" types) would allow a more organic expansion over time, with feedback from users and concrete patterns emerging.

Especially questions like "is the default reused or not" have a lot of potential for subtle bugs if we change them later, so I'd rather disallow certain designs initially, until it turns out what works best.

Future work

Lots of things can still be done:

  • Performance optimizations
    • I already tried to make sure that #[func] which doesn't use #[opt] has no perf disadvantages. Allocations should be postponed until it's clear that defaults are needed.
  • Registration in editor docs (register-docs)
  • Integration with future builder API
  • More testing
@Bromeon Bromeon added feature Adds functionality to the library c: register Register classes, functions and other symbols to GDScript labels Nov 2, 2025
@Bromeon Bromeon changed the title Default parameters via #[opt(default = ...)] syntax. Default parameters via #[opt(default = ...)] syntax Nov 2, 2025
@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1396

@Bromeon Bromeon force-pushed the feature/func-default-params branch 2 times, most recently from 28b17b3 to f988dd4 Compare November 3, 2025 23:29
@Bromeon Bromeon force-pushed the feature/func-default-params branch from f988dd4 to 7405d51 Compare November 3, 2025 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: register Register classes, functions and other symbols to GDScript feature Adds functionality to the library

3 participants