-
-
Notifications
You must be signed in to change notification settings - Fork 97
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
C#: Implement IReadOnly*<>
interfaces on Godot's Array<>
and Dictionary<,>
classes
#3844
Comments
For those unfamiliar who would like a more detailed example, you could do something along the lines of: // The mutable version is kept protected. Export can still set and get it for saving/loading.
private Dictionary<KeyCode, string> __keyBindings = new Dictionary<KeyCode, string>();
[Export] protected Dictionary<KeyCode, string> _KeyBindings
{
get => __keyBindings;
set
{
/* ... Do a full set here that builds lookups or other dependent data */
}
}
// The public version is exposed as read-only to make sure it cannot be changed
public IReadOnlyDictionary<KeyCode, string> KeyBindings => __keyBindings;
// Edit functions are then provided to ensure dependent data is kept up-to-date
public void AddBinding( KeyCode code, string action )
{
/* ... add a new binding and update dependent data. */
} |
Implementing the Instead, I prefer the For dictionaries, the equivalent is The good news is you can already implement an public ReadOnlyCollection<T> AsReadOnly<T>(this Godot.Collections.Array<T> array)
{
new ReadOnlyCollection<T>(array);
}
public ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this Godot.Collections.Dictionary<TKey, TValue> dictionary)
{
new ReadOnlyDictionary<TKey, TValue>(dictionary);
} Since Godot's collections already implement Also, since it's a wrapper there is no conversion (which is what I'm guessing you are worried about since you don't want to use C# collections), trying to access the values of the readonly collection will just directly access the underlying collection (this also means if you change the underlying collection the changes are reflected in the readonly collection2). What we could do is include those methods in Godot's collections but I'm not sure it's worth it since it's a one-liner, specially since .NET 7.0 will already provide those extension methods for you (dotnet/runtime#61172) all you need to do is include the Footnotes
|
TLDR; For full ReadOnly functionality, both wrappers and interfaces are useful and have their place. Perhaps I shouldn't have used the term The main reason the interfaces exist is to allow better contract expression by allowing methods to declare that they are not going to change your collection. By marking the input parameter type as So I guess the main question is: My example in my previous comment uses the interface to express a return contract. Returned contracts are a bit more controversial, it's true. When working alone or with a small team they can be safe enough while keeping things simple. (I mean, if one of your team mates casts an |
I ran into this again when trying to write an extension method. I wanted to write: public static TVal GetOrDefault<TKey, TVal>( this IReadOnlyDictionary<TKey, TVal> d, TKey key, TVal @default )
=> d.TryGetValue( key, out var value ) ? value : @default; Which then covers 12 standard dictionary types, but not Godot dictionaries. Had to duplicate the extension method just for the Godot Dict. |
I second what @cgbeutler said. Yes,
but that was never the idea nor point here. It's actually
That is the point of this proposed change. And yes, both the logical precedent of
are for me, by themselves, enough to implement those interfaces here (not to mention the contract side of the problem highlighted above, the convenience of having those interfaces implemented, and the fact that there are no real downsides in doing so). (sorry for the repost, previously I used my company account instead of personal one by mistake :D) |
This was implemented in 4.0 by godotengine/godot#64089 |
Describe the project you are working on
Platformer.
I have some custom resources with a dictionary of arrays within. The resource generates an inverted lookup for the collection when it is edited through the proper setters.
Describe the problem or limitation you are having in your project
I have a dictionary of arrays from which I generate an inverted lookup. That lookup is kept up-to-date when it is edited through the proper setters. With data is dependent on this collection, it would be nice to be able to expose the collection as read-only to ensure that users don't mistakenly get it out-of-sync. Currently, there is no way to expose an immutable version of a Godot collection without converting the whole thing over to a C#-standard collection.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
This feature would allow me to share out a collection that is more immutable. I could then rest easy knowing no synchronization bugs could arise.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
This would add an interfaces to
Array<>
https://github.com/godotengine/godot/blob/3a41bf0e044915ca45440901e9beeea81c3d5505/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs#L345
so it would become:
Similarly
Dictionary<,>
https://github.com/godotengine/godot/blob/3a41bf0e044915ca45440901e9beeea81c3d5505/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs#L367
would become:
The read only interfaces are mostly a reduced set of their mutable counterparts, so not much code would need to be added. I haven't looked into it too much, but
IReadOnlyCollection
sometimes needs a bit of code.If this enhancement will not be used often, can it be worked around with a few lines of script?
This feature should not get in the way otherwise.
Is there a reason why this should be core and not an add-on in the asset library?
Interfaces cannot be added post-hoc.
The text was updated successfully, but these errors were encountered: