Re-organize type-level attributes in NativeClass derive macro · Issue #848 · godot-rust/gdnative (original) (raw)

The NativeClass macro currently utilizes a large number of type-level attributes, making it tricky to add further expansions to its functionality. The current attributes are:

... while in the future, we might also like to add:

Proposal

My proposal is as follows:

Under this new arrangement, generic bounds and static renames can easily be introduced as keys under the #[nativescript] attribute: #[nativescript(bound = "T: SomeBound", rename = "SomeNewName")]. Prior art for this could be found in the ecosystem, for example, in Serde.

Unresolved questions

It's a common complaint that the signature of the mandatory new is too verbose, the owner argument being seldom used. However, it isn't obvious how this is best dealt with. Our problem here is the need to distinguish three different semantics at the syntax level:

I can see two alternatives to the current situation:

Changing the default constructor to the nullary Default::default, requiring a constructor key for unary constructors

Under this arrangement, the possible annotations are:

This makes it much less verbose to declare types with constructors that do not use the owner argument, and frees up the new identifier unless requested specifically by the user. The downside is that extra annotation is required to reproduce the current default.

Replacing no_constructor with a nested key-value pair under the constructor meta

Under this arrangement, the possible annotations are:

This has the benefit of allowing custom functions for both the nullary case and the unary case, but is very verbose. It should be noted that Default can always be implemented for types with nullary constructors, even though it could be undesirable if the constructor in question is expensive, or if there are multiple such functions.