Why doesn't ObjectField have type parameters?

Right now I’m seeing a lot of code:

ObjectField fGenerator = new ObjectField() { name = "Generator", objectType = typeof(BLAH)};
            fGenerator.RegisterValueChangedCallback( evt =>
            {
                BLAH instance = (BLAH) evt.newValue;
                ...
            } );

Which ought to be:

ObjectField fGenerator = new ObjectField<BLAH>() { name = "Generator"};
           fGenerator.RegisterValueChangedCallback<BLAH>( evt =>
           {
               ...
           } );

…but ObjectField doesn’t allow this. The rest of UIToolkit uses Generics correctly - the Register…Changed<>() methods being a prime example - so why isn’t ObjectField using it?

Is there some technical reason why it can’t? At the moment it simply appears to have been written incorrectly.

There is nothing in the docs to explain this:

"
Description
Constructor.
"

1 Like

One of the main reasons we tend to avoid generics is that there isn’t a very obvious way to support generic types in UXML. Most generic usage in UI Toolkit element is for base classes.

Also, I think there is an actual benefit of the current approach which is that the objectType is not fixed, and can be changed after the creation of the object field.

Maybe this is a good use case for a custom subclass of object field on your end ? You could make it generic and just capture the objectType from the generic type parameter.

1 Like

I struggle to think of times I’ve wanted a Unity objectfield to have a mutable type. Maybe I’m missing a trick here, there’s some programming approach I should be using in Unity and I’m not? Most of the examples I can think of are from 2010 or so when I didn’t yet know how Unity was structured, and kept trying to write code that made sense in non-Unity environments.

Untyped? yes. Fixed type? Almost always.

But changeable type? Very rare. It would make a lot of sense in Python, where the language is specifically designed to have that feature - but in C# it seems like a bad idea.

Subclassing OF would be fine, but it means the list of “classes that every project has to import and solely exist to workaround bugs and design mistakes in UIToolkit” gets longer (I try to keep it as short as possible), and I think that is a poor show for an API that isn’t production ready yet and still has time to fix such oversights. NB: I’m happy to subclass it, just … I’d prefer it if our projects didn’t have to keep patching the API.

(plus: I feel that in 2020 Unity’s own standard/bar for API design is higher than that. For other Unity API’s we’ve been specifically asked by Unity staff to report things like this and get them changed before they go to a production release)

FloatField, IntField etc use Generics correctly. Why is ObjectField a second-class citizen? How is FloatField a “base class” and ObjectField is not?

(as a side-note: if UIToolkit is being held back by “what works well in UXML” then that is a sad state of affairs, severely undermining the potential and what it’s been sold as (a complete replacement for UnityUI - according to roadmaps, Unite presentations, etc). If it’s the guiding principle for UIT at the moment then I predict it will get retired yet again within the next 3-4 years and replaced by YetAnotherUnityUIPackage, a trend that I’d been hoping we’d seen the end of :smile:)

The UI Builder has an example of ObjectField having a target object type that is dynamic, because we support several kind of assets to be used as a background image.

6637456--757291--Screen Shot 2020-12-18 at 11.31.27 AM.png

I am not saying this is the most common case, but that flexibility is handy at times.

In any case, the current API design looks logical to me. BaseField is meat to be an abstract base class and each subclass provides its concrete parameter type.

ObjectField could be generic on its own but that’s a different story. Under the hood, there is no difference in storage or handling of the value because it’s a reference type. The objectType is just forwarded to the ObjectSelector as a filter.

I understand this might be annoying for you to have to cast between Object and the type you care about, but I don’t think this should make it high on our priority list at the moment :slight_smile:

1 Like