+5
Completed

Simplify lists

Lazlo Bonin (Lead Developer) 3 years ago updated 5 months ago 8 1 duplicate

There needs to be a manual page to explain lists, because they're a bit confusing at the moment.

In the mean time, here's an explanation I gave on Discord:


Generic means that they are strongly typed, e.g. List<GameObject>. When you see "<>" or "List of ..." (in Human naming), it's a generic list. A generic (strongly typed) list can only have items of the specified type in it. Loosely-typed (non-generic) lists can have any mix of item types in them.(edited)

Generic lists are not supported on AOT platforms, because generic code is generated JIT. You don't need to understand that, just know it.

Therefore, when AOT Safe Mode is enabled (by default) AND you are currently targetting an AOT platform, Bolt will not let you create generic lists (List<T>) in variables or units, or use IList methods, because they'll fail at runtime on AOT platforms.(edited)

This is why Bolt provides an AotList type, which is basically a non-generic List and works everywhere (including on JIT platforms).

Both generic List<T> and AotList implement IList. However, because interface methods are not well supported in AOT platforms (same reason), you shouldn't use IList methods, but rather the built-in list units.

Finally, arrays (e.g. GameObject[]) are tricky. They're supported in AOT (yay), BUT they lie about the fact that they implement IList.

They implement IList, but calling things like IList.Add or IList.Remove on an array will throw an exception, because arrays cannot be resized on the fly.

And because they can't be resized on the fly, the built in list units cannot modify the input array, but have to return a copy of it with the modification (add/remove) applied.

This is why lists are generally far superior to arrays, and you should use them if you can.

I understand that an "Array to List" unit would be very helpful for cases where the Unity API returns an array, which it almost always does.

Final note, when you use the Create List unit, Bolt creates an AotList in the background.

As you can see, this is all very tricky!

If this is all way too confusing for you, the absolute safest guideline would be:

If you're only targetting JIT platforms (Windows, Mac, Linux):
- DO Use generic lists in your variables
- DO Use Collections/Lists units in your graphs
- DO NOT Use IList units in your graphs (there's no need!)

If you're also or only targetting AOT platforms (mobile, console and everything else):
- DO Use AotList in your variables
- DO Use Collections/Lists units in your graphs
- DO NOT Disable AOT safe mode (it's there for a reason!)
- DO NOT Use generic lists in your variables (you can't with safe mode enabled)
- DO NOT Use IList in your graphs (you can't with safe mode enabled)

This also makes me realize that IList and IDictionary should be removed from default types, because safer units are provided for them. It would remove some ambiguity in the fuzzy finder.

Bolt Version:
Unity Version:
Platform(s):
Scripting Backend:
.NET Version (API Compatibility Level):

Duplicates 1

+3
Under Review

Thinking about this further, I feel like the design should be improved rather than documenting poor design.

Some ideas:

  • Removing list and dictionary interfaces from default types, because they're actually useless
    • Their methods don't work on AOT
    • All of their useful methods are also provided by custom built-in units under Collections
  • Adding a type field to the Create List unit, ensuring type safety
    • This allows us to display inline fields for each port whenever supported
    • It will also help creating strongly typed lists when Bolt 2 code generation arrives
  • Maybe Adding "useless" type fields to Create Dictionary, which would only be used for Bolt 2 generation
  • Removing list literals from graph options (but not from variable type options)
    • There's a billion of them and it's annoying
    • They don't work on AOT
    • They could always be replaced by the new Create List, now that inline fields on ports are supported
  • Removing AotList and AotDictionary from the graph options (but not from variable type options)

With those changes, the only options that would be available as units would be what's under Collections/Lists, which is a lot simpler. And these always work on AOT..

+2

Also:

  • AotLists should have a type property that forces their value to be of that specific type (at runtime).
  • AotDictionaries should have a valueType and keyType that serve the same purpose
  • Having those types would allow the inspector to display the proper inspector instead of having to choose the types for each item.

Note to self: investigate using generic collections as base classes for AotList and AotDictionary for compatibility with Odin.

Is there a technical reason list elements are restricted to a maximum of 10?

No, but if you need to add more, you're probably going to want to use a loop (For / For Each) and the Add Item node. It's just the "initial" creation that's limited to 10, although I could up that while reworking lists.

That would be great if it could be upped.  The lists I do aren't conducive to using a for/for each loop.  I use them where I can, but there are times it's not possible.

I see, can you please create a feature request (idea) thread to remind me to put that in a future update?

Completed

(Sorry for the bump/necro, I'm doing some roadmap grooming following the Unity acquisition!)

This is now supported in Bolt 2 Alpha as generics are fully supported; the List<T> type can be used anywhere.