Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Feedback request: What should we rename FixedListN to?

Discussion in 'Entity Component System' started by elliotc-unity, Aug 5, 2021.

  1. elliotc-unity

    elliotc-unity

    Unity Technologies

    Joined:
    Nov 5, 2015
    Posts:
    228
    Hi from the dots team!

    Among many other things, we're working on getting com.unity.collections, aka Unity.Collections, to become a verified, non-experimental, all-the-way-released, yes-really-usable package.

    To that end, it has come to our attention that most people assume that for example FixedList128<T> holds 128 items of type T, when in fact it takes up 128 bytes of stack space, and holds however many T's fit into 126 bytes (126 because 2 bytes are used to remember the length). So for example, FixedList128<int> holds 31 ints.

    This is a useful construct when doing various high-performance Bursty type things, but it's obviously a bit unintuitive for non-engine programmers. And it's extra unintuitive because it has this name that suggests an obvious and incorrect interpretation.

    So, we'd like to rename it, and we can use the script updater to make it so that we won't break anybody in the process.

    The question is, what do we call it? We'd like it to be that hardcore enginey people don't hate it TOO much, but non-enginey people also don't pick it up and then shoot themselves in the foot, as they have done already with the existing name.

    The candidates, so far, are as follows:

    - FixedList128Bytes<T>
    - pros: it at least says Bytes, which suggests the 128 might not be items. Also, it suggests why you want to use it (i.e. you have a thing that fits in exactly 2 cache lines).
    - cons: you do not actually get 128 bytes of storage, you get 126.

    - FixedList126Bytes<T>
    - pros: it says Bytes, and it tells you how much storage you have.
    - cons: not obvious why it exists in the first place or why you would want it.

    - ByteBuffer128<T>
    - pros: seems forbidding for non-engine peeps, and it's true that this is what it is.
    - cons: it's kind of odd that a thing called ByteBuffer is strongly typed, and you might expect it to behave more like the untyped NativeStream/UnsafeStream, I guess.

    - ByteBuffer126<T>
    - same issues as above, but specifying available storage instead of the size of the type.

    So! Imagine that you were a person who saw one of these names in intellisense, or in code you were reading that somebody else wrote, and you hadn't read this forum post, nor the docs.
    - Which of these would be the least likely to cause you to shoot yourself in the foot by assuming a wrong thing?
    - Which brings your intuition closest to what you now know the truth to be?
    - Are these in fact better than FixedList128?
    - Do you have another idea that's better than all of these?

    As you may have seen, everything about the 128's above goes for the other sizes, namely 32/64/512/4096.

    Standard-ish disclaimer: we haven't committed to anything yet, and it might end up being too hard to do this rename for unforeseen reasons. We'll try hard though.

    Thanks in advance!
    Elliot

    P.S. I didn't want to make this too long, but there are more wrinkles when it comes to FixedString, which I will ask about later.
     
    Last edited: Aug 5, 2021
    SamOld, andreiagmu, Tony_Max and 6 others like this.
  2. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    258
    Out of the listed names I think FixedList126Bytes<T> is the clearest in terms of stating what it does, but I actually prefer FixedList128Bytes<T> as long as there is clear documentation stating that you can only actually use 126 bytes.
     
    apkdev and elliotc-unity like this.
  3. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    ByteBuffer128<T> is the more descriptive one while still fancy. In the end, it is in fact a strongly-typed byte buffer after all.

    EDIT: After thinking through it, I think that showing the type size is more important than the available space. Just need to have clear documentation AND error message.
     
    Last edited: Aug 5, 2021
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Out of the names provided, I like FixedList128Bytes<T>. However, I don't really like it. I find the number in the middle not very readable and the name is still kinda confusing and doesn't help the string issue.

    I would like to propose this:

    BytesEmplacedList128<T>


    Pros:
    • The odd name would encourage people to look up the documentation.
    • It has the number at the end.
    • The name explains the relationship between Bytes and the List, even suggesting that the length gets reserved somewhere and that the number corresponds to the byte count.
    • It can be abbreviated to "bemp list" in conversations which is kinda fun to say.
    • It translates well to strings as well (replace "list" with "string").
    Another alternative is:

    FixedListInBytes128<T>


    which you could call a "FLIB" :p
     
    NotaNaN, varnon, JesOb and 3 others like this.
  5. Mortuus17

    Mortuus17

    Joined:
    Jan 6, 2020
    Posts:
    105
    ByteBuffer128<T>
    is the clearest to me by far. Although it, as you've said, doesn't point out that it is in fact a list data structure, which would imply that somewhere a
    Count
    is stored.

    ListOf128Bytes<T>
    does that better, especially if you express it like "List of 128 bytes of ints". Although I can see a few problems with that one.

    Man - this is hard. I understand why you asked the community :confused:
     
  6. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,903
    Yay! This is great news!

    It is. Although I have zero problems keeping names which aren't exactly aligned with the C# canon. Collections is part of a toolset which brings our code closer to the metal, I think it can be allowed to be a bit more pragmatic.

    So I am pitching
    FixedBuffer128<T>
    . My reasons:
    - it's a buffer of type T
    - it's fixed sized and fixed typed
    - it occupies 128 bytes
    - it's not too long
    - it's clear what it is
    - it doesn't try to mask itself as a List (which in C# has arbitrary length and other criteria)
    - it's FiB, easier on the tongue than FLiB or BEL or BEmp. :D
     
    Last edited: Aug 5, 2021
    Opeth001, mloveall, NotaNaN and 13 others like this.
  7. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    825
    I'd actually prefer it to stay as it is. I don't consider myself an advanced programmer so I'm pretty sure I'm looking through the lens of a non engine programmer. At the same time I'd like to think my own use of dots has been somewhat more involved than just instantiating a million cubes, and the things I hate typing most are the names that are most verbose. Maybe my auto complete isn't configured right but anyway EndSimulationEntityCommandBuffer is one of them, GetComponentTypeHandle is another. World.DefaultGameObjectInjectionWorld, heh really? What was wrong with Active? And quite frankly I don't care that it didn't describe in perfect detail what it really meant, that should be the help documents job. And maybe its no longer official but cant help but chuckle at
    IJobNativeMultiHashMapMergedSharedKeyIndices.

    FixedList128Bytes doesn't quite match it but I feel like that extra semantic of adding bytes to the name could be another straw to the camel's back so to speak. On its own its not so bad but venturing down the road to making everything overly descriptive in name in my mind doesnt match that "Make it as easy to use as regular Unity" that you are striving for. If regular unity was similar, Object.Instantiate would be Object.InstantiateTriggersGCAllocation or something similarly ridiculous.

    A lot of the api is way more verbose than regular unity and I don't think trying to cram in what belongs in the documents helps things.

    Why I like FixedList128 -
    It looks like a list, seems to act like a list in my own uses so in my mind keep the list part in name.
    Fixed helps denote it does actually have some special behaviour/considerations from a regular list, which I learned a bit from the docs, and a bit from experimentation(also I'm not upset it doesnt have the full feature suite of actual lists, to me a list is series of things that I can add and remove from and I can do that with fixedlists).
    128 over 126, as you said it refers to the stack space, and as dots is all about these kinds of optimization, I feel like it should take precedence over referring to the actual capacity for T

    I dislike buffer as everything seems like a damn buffer in advanced unity. compute buffers, command buffers, entity command buffers, dynamic buffers, graphics buffers, enough buffers!
    Anyway I didn't actually know it was 126 bytes vs 128 before reading this thread but it makes enough sense, I don't feel like this was some huge revelation that I missed out on, nor do I feel like it should be in the name, it should just be something that sits in the docs. I I feel all of these extra long names are a crutch for actual documentation that should explain the quirks and implementation details that we so badly lack. I dont feel that adding bytes or the technically correct storage amount really helps discoverability or ease of use tbh.
     
  8. IgreygooI

    IgreygooI

    Joined:
    Mar 13, 2021
    Posts:
    48
    Why not
    FixedArray128Bytes<T>

    - I have a problem calling it a list. In my opinion, it is a fixed size array with some uninitialized elements and a ushort to track the its length. But FixedArray says excatly what it is, an workaround to:

    public fixed SomeStruct[31] SomeField;

    from this perspective, ByteBuffer128<T> also works.

    - 128 over 126, since from the user side, the capacity is always checked (at least in editor), but the memory size is not explicitly stated. Meanwhile 126 does not really directly tell your about the capacity anyway.
     
    apkdev and elliotc-unity like this.
  9. Rupture13

    Rupture13

    Joined:
    Apr 12, 2016
    Posts:
    129
    Out of the ones suggested, I like FixedList128Bytes<T> most, though I still prefer the current FixedList128<T>.

    Sure, some confusion exists for the current one, but it's very intuitive once you looked it up. I think most people that use FixedLists already, have looked it up instead of guessing what it is and what it does. Of course, having to look up the FixedLists may not be desired, which is where Intellisense can be of use by giving a brief description mentioning the size in bytes (and maybe even the reservation of the last 2 bytes).

    The name it currently has also has advantages despite not being 100% clear: it's relatively short and elegant, without extra-clarifying-but-unnecessary-once-you-know-it clutter, while also describing how it is used in code, "List", with all the methods one can call on it.
    It also doesn't look scary to people with basic programming skills. Those people probably have used Lists a lot in regular Unity and therefore a FixedList128 looks familiar and safe enough. Changing it to a name with "Bytes" or even changing it to be "Buffer" instead of "List" to me seems like it would make it unfamiliar and more scary for some, making them hesitant to even use it.
    The "Fixed" part of the name should also stay in my opinion, as it is very intuitive that a type that is fixed in size is useable for ComponentData. You lose that by omitting the "Fixed" part.
    Lastly, I also think 128 is better than 126. Sure, people who don't know about the 2 bytes make wrong assumptions now when they haven't read the docs, but people who do know about the 2 bytes in general will then make wrong assumptions when it is called 126 when they haven't read the docs, perhaps assuming that they will have 124 bytes they can actually use for a FixedList126.

    There's also the matter of the FixedListByte128 already existing, which is the equivalent of FixedList128<Byte>. If you rename the FixedList128 to FixedList128Bytes, you might end up creating more confusion instead of less, as then you'll have both FixedListByte128 and FixedList128Bytes<T> as types...



    Overall, I think no change in the name, but rather clarification elsewhere, is the best road to go down.
     
  10. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    296
    I actually like the existing FixedList128<T>!

    Less typing than adding bytes to the end every time. There's errors to throw up when it's misused. I think the pros of typing less out weigh the cons of people getting confused. Obviously this is subjective, just my opinion.

    I like it having List in the name rather than array because the entire point of it is to use it like a list. If it were an array/buffer I'd just declare a fixed array.

    I'm ok with the 128 not being 100% accurate of the actual list contents size. I am never calculating this exactly, but just roughly. If it's not big enough then just go to the next size up. 32,64,128 is more associated with memory/byte sizes to me.
     
    Rupture13 likes this.
  11. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I prefer the approach here https://www.jacksondunstan.com/articles/5051.

    Code generation that produces strong names. Easier to reason about size/more control, and easy to customize. Code generation is a slight downside. But a source generator integration into the editor is trivial.
     
  12. quabug

    quabug

    Joined:
    Jul 18, 2015
    Posts:
    66
    It is not just naming, but also the way to design this kind of struct.
    Take this C++ struct as example, it is express "a list container of T with fixed size of ByteSize" clearly, IMO.
    Code (C++):
    1.  
    2. template<typename T, size_t ByteSize>
    3. struct FixedList
    4. {
    5.     unsigned short _length;
    6.     byte _buffer[ByteSize];
    7.     ...
    8. }
    9.  
    10. // new FixedList<int, 30>()
    11.  
    Translate to C# like:
    Code (CSharp):
    1.  
    2. struct FixedList<T, TBufferSize>
    3.     where T : unmanaged
    4.     where TBufferSize : unmanaged, IFixedSize
    5. {
    6.     ushort length;
    7.     TBufferSize buffer;
    8. }
    9.  
    10. struct FixedArray<T, TBufferSize>
    11.     where T : unmanaged
    12.     where TBufferSize : unmanaged, IFixedSize
    13. {
    14.     TBufferSize buffer;
    15. }
    16.  
    17.  
    18. interface IFixedSize {}
    19.  
    20. [StructLayout(LayoutKind.Explicit, Size = 30)]
    21. struct Bytes30 : IFixedSize {}
    22.  
    23. [StructLayout(LayoutKind.Explicit, Size = 1024 * 32)]
    24. struct KiloBytes32 : IFixedSize {}
    25.  
    26. static void Example()
    27. {
    28.     new FixedList<int, Bytes30>();
    29.     new FixedArray<long, KiloBytes32>();
    30. }
    31.  
     
  13. Noctiphobia

    Noctiphobia

    Joined:
    Jun 9, 2021
    Posts:
    8
    IMO ByteBuffer126<T> would be the right choice. I don't see any reason to use 128 besides it being a power of two. People probably don't care as much about how much space it actually takes, they care mostly how much they can store there. As far as a typed byte buffer seeming weird, true, that's not the first thing that crosses your mind. But once you actually notice that it's strongly typed, it's pretty obvious what this means.

    Just press tab, "less typing" is the reason there are atrocities like Microsoft's _snwprintf_s_l.
     
  14. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    FixedList128<Byte>
    ByteBuffer128<Byte>


    For me they both not perfect.
    I have small experience (4 years) in C++ and 12+ years in C# (from C# 1.1)

    List in C# is dynamic (auto grow) collection while static one is Array (dont know actually how novices fill that)
    So adding list for name of static collection looks bad because it is contrary C# basic collections (List, Array, Dictionay)
    So no FixedList...

    ByteBuffer128<Byte> look somewhat ugly because of 2 things:
    - Byte expressed 2 times
    - Buffer, for me and according to wiki, is region of a physical memory storage i.e. Some Amount of Bytes, KBytes... so no need to write ByteBuffer just Buffer is enough

    With all that I will prefer Buffer128<Byte> but if it is actually have interface of list than it is not enough

    Buffer128List<Byte> - there we have List again may be we can add better word to express its List interface:
    Buffer128IList<Byte> - lets go into details what this name means for me:
    - Buffer - region of a physical memory storage expressed in bytes like all memory on devices
    - 128 - size of buffer
    - IList - it is indexed collection of items but not list. It is looks like list - no more. C# Array is IList too.
    - <Byte> - actual type of items in collection like anywhere in C#
    - May be it can actually implement C# IList interface

    On par with it there can be
    Buffer128<Byte> - it is not IList so no 2 bytes to store count it is more like Array but for DOTS and low level programming because size of struct is more important on low level and for DOTS perfomnace than count of items inside.

    Summary
    Buffer128<T> - Array like
    Buffer128IList<T> - List like
     
    ArnoldMPG, Micz84 and JoNax97 like this.
  15. Occuros

    Occuros

    Joined:
    Sep 4, 2018
    Posts:
    284
    Personal preference goes to
    FixedListInBytes128<T>


    - It's a little more verbose but makes it clearer what it means
    - the size is at the end, which makes it more consistent
    - 128 or 126 are both confusing without documentation (and probably will lead to mistakes) and 128 sounds more accurate to me.
    - FLIB sounds nice

    In addition, it would probably help a lot to have the specific version for the primitive bytes with the actually available count:

    FixedFloatList31

    FixedIntList31
    etc.

    (with proper documentation and explanation)
     
  16. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    943
    Tough one. I vote ByteBuffer126<T>. It's more clear that there's only space for 126 bytes.
     
  17. Krajca

    Krajca

    Joined:
    May 6, 2014
    Posts:
    347
    I know these weren't on the list but for me, this should be either:
    -FixedByteList126 or,
    -FixedByteBuffer126

    From the proposed names, I think FixedList126Bytes<T> is best.
     
    Orimay likes this.
  18. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    +1 to FixedBuffer128<T> or just Buffer128<T>
     
    varnon and brunocoimbra like this.
  19. Tony_Max

    Tony_Max

    Joined:
    Feb 7, 2017
    Posts:
    334
    +1 to FixedBuffer128<T> or ByteBuffer128<T>
     
    brunocoimbra likes this.
  20. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    908
    +1 to FixedBuffer128<T>

    Seems to me like the best wording. It's not really a List so Buffer is more fitting. It's not really Bytes because it's generic and it has a fixed size.
     
    mariandev likes this.
  21. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    Note that I'm not native english language speaker so I'm not "fluent" about all the details and "quirks" of the language and my understanding of words may be "off" a bit.
    Fixed appears to me as "repaired", the opposite of broken. Just have a look at 20 german words fixed can mean.
    Buffer is a construct which takes something to release it in a controlled way.

    Do you want to name it after what "it is", what "it is used for", "how it is used" or what "it does"?

    Since it just seem to represent a portion of memory which can be used in an arbitrary way why not name it so? TypedMemory128Bytes would be my suggestion.

    I know choice doesn't get easier when people suggest names outside of your "scope" ;).

    In any case I would vote against the term "List" for this type since it wakes too much (wrong) expectations of what it is capable of.

    Seems you have picked the worst field when you have to deal with both of those ;).
     
  22. Timboc

    Timboc

    Joined:
    Jun 22, 2015
    Posts:
    234
    Strong preference for knowing how much data I can put in there and not relying on *implicit* knowledge that 2 bytes are occupied. Better to wonder why 126 than think you can put in 32 ints.
    Throwing out another thought. Any chance some common types could get equivalent definitions?
    E.g. IntBuffer31 <=> ByteBuffer126<int>
    Similar to the codegen suggestion above, I can see an issue of extra code for supporting the common types. Though at least if they were all equivalents I'd expect it's mostly a few hundred lines, type-once deal.
     
  23. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    436
    I like Buffer128IList<T> and FixedBuffer128<T>. Because of clarity verbosity compromise. I think 128 is better then 126 because in DOTS we care how much stuff takes space in memory not only data.
    There should be a poll after some suggestion will be proposed.
     
    Rupture13, brunocoimbra and JesOb like this.
  24. Orimay

    Orimay

    Joined:
    Nov 16, 2012
    Posts:
    304
    +1 for
    ListOf128Bytes<T>
     
  25. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    791
    FixedList126Bytes<T> people care about how much storage something has. When picking list size a programmers needs to pick based on how much storage he needs. Like literally you have a lot of different fixed list sizes. I don't get why anyone would care how much memory something uses. The two bytes are not a lot, really getting into the weeds with 128.
     
    Last edited: Aug 5, 2021
    Krajca likes this.
  26. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    863
    +1 to FixedBuffer128<T>
     
  27. Guedez

    Guedez

    Joined:
    Jun 1, 2012
    Posts:
    823
    ReinterpretableStruct128<T> would be my vote, after all, it's no different from a struct that is being interpreted as a list, no? You don't allocate or dispose of it like other lists, right?
    I never used it so I don't know what it can or cannot do. Heck, make so you can reinterpret it as either a large struct or a list of smaller structs, don't restrict it to only being able to interpret it as lists.
    Can you make a NativeArray of it?

    I get that this is very off topic. But some for of "Collection.IsValid" would be greatly appreciated before the package is deemed "yes-really-usable package". I can only check if IsCreated, so if something else somewhere deallocated my array I have no way of checking beforehand. This stops me from being able to create safeguards, where an array will be deallocated even if there was an exception on the method that supposedly should have deallocated it.
     
  28. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    791
    I wonder how many people in this thread have actually used FixedList or even understand when to use it. I get a feeling that people are viewing this as some low level thing. When actually it is a DynamicBuffer competitor.
     
    HellGate94 and Tony_Max like this.
  29. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    258
    I've used it a fair amount, but mostly inside blobs and Rpcs. It is a good competitor to Dynamic Buffer, but should not replace the usage of Dynamic Buffers.

    Entities are stored in chunks of 16 KB and all of the memory needed for a fixed collection is stored in that collection. If you are using a lot of FixedListN<T> and if N is large a lot of the time, you can fill up a chunk with only a few entities.

    Dynamic Buffers on the other hand store data in the Archetype Chunk iff it is less than or equal to the internal capacity. Once a Dynamic Buffer exceeds its internal capacity all data is copied to a heap memory block. The compromise being that access to the data is slower, but you don't create chunks with few entities.
     
  30. Guedez

    Guedez

    Joined:
    Jun 1, 2012
    Posts:
    823
    I just started using today because I didn't even knew it was a thing until today. pretty good though, I might never use buffers and not be afraid of lists anymore.
     
  31. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    This is a little misleading, I would even argue that DynamicBuffer itself is proof of how FixedBuffer would be a better naming than FixedList.

    In a simple way, FixedList is similar to C# arrays, having a fixed size, while DynamicBuffer is way more similar to C# lists. DynamicBuffer is also associated with an Entity, while FixedLists have many more different use cases available.
     
  32. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    I typically assume a "Buffer" is feature-specific memory that I don't own (or am expected to give up ownership of) but allowed to touch in order to interact with that abstracted feature.

    And in C#, I assume a "List" is an array with built in count for a valid number of elements in the array packed at the front.

    But it is pretty clear from this thread that not everyone has these same assumptions, and that's what makes naming these types so hard.
     
  33. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    Well C# does have a feature commonly called "fixed buffer" that mostly works in the same way as the FixedList works, but with the major difference that with FixedList you choose the total type size while with C# fixed buffers you choose the buffer's element count.
     
  34. elliotc-unity

    elliotc-unity

    Unity Technologies

    Joined:
    Nov 5, 2015
    Posts:
    228
    After much gnashing of teeth (including the welcome gnashing from y'all!), we settled on FixedList128Bytes/FixedString128Bytes. Reasoning: Nobody agrees about anything, other than that people did seem to shoot themselves in the foot a lot with FixedList128, so we had to change something, and this was the minimum-upheaval change.

    I am also mildly annoyed that the name got longer, but I highly recommend everybody who doesn't have working intellisense pick up VS or Rider, so that you have to type every name at most once!

    I also agree it's unfortunate that it doesn't end in a number anymore.

    We do actually have @quabug 's suggestion implemented, with FixedList<int, Bytes126>, but the scriptupdater can't update from FixedList128<int> to that today, and for various reasons I couldn't justify rejiggering the scriptupdater on this go-round. :)
     
    SamOld, Tony_Max, Anthiese and 8 others like this.
  35. Rupture13

    Rupture13

    Joined:
    Apr 12, 2016
    Posts:
    129
    Does this mean there will be both the new "FixedList128Bytes" (containing type T) as well as the already existing "FixedListByte128" (containing type Byte)?
     
  36. elliotc-unity

    elliotc-unity

    Unity Technologies

    Joined:
    Nov 5, 2015
    Posts:
    228
    No, the latter I set to upgrade to FixedList128Bytes<byte>, and the same for all the others (e.g. FixedListInt128 -> FixedList128Bytes<int>, etc).