Search Unity

Feature Request add nameof(T) generics support to burst

Discussion in 'Burst' started by rauiz, Sep 8, 2022.

  1. rauiz

    rauiz

    Joined:
    Mar 19, 2013
    Posts:
    43
    Burst doesn't support nameof(TType) at the moment (it returns TType no matter what TType actually is at a particular callsite). By looking at the ECS forum, a lot of bursted code seems to leverage generics to avoid paying runtime costs on generalizations, so this would already be useful for logging purposes at a minimum.

    More interestingly, in systems/cases where you don't care that much about the perf hit this can create if used poorly, it'd enable adding per-type data to a system during initialization. There's some interesting things you could do with this. The gist of it would be:
    • Have a RegisterTypeWithSystem<TType> function that passes some data that the system internally associates with the type. This data can vary based on the system, but you can imagine things like:
      • "Use this allocator for all internal allocations you make related to this type"
      • "Take this function pointer that defines a behaviour for this type" (this is not necessarily a good thing to do all the time, but it can be useful in some cases)
      • "Here's some per-type blob data that you'll need to have in order to work correctly with this type"
      • I currently use this to setup some of my job-management stuff (I do this to gather job-scheduling data to generate a view of running job-graphs).
      • I wanted to use this to setup the size of serialization buffers for specific systems to use in my rollback engine.
      • Etc...
    • Have jobs and/or bursted functions with the form burstedSystem.DoSomething<TType>(ref TType) that leverage nameof(TType) and the system's internal state (typically, maps of type to internal state handles/pointers) to actually do things.
      • When I say system, I don't mean just Unity ECS systems. I mean any custom system a game may have that'll run bursted jobs.
    I've played around with C# Source Generators and, for certain use-cases, I don't mind the perf hit at all just so that I don't have to deal with them (too much setup required for my taste + horrible debugging experience). Given the time and maintenance headache they are, I'd rather just take the perf hit. In my use-cases and tests (outside of burst-land with GetType().FullName instead), the perf impact has been negligible.

    This request is not really about any specific use-case for this --- whether or not you'd want this is very problem-specific anyway. However, I got the impression that this would enable use-cases that you currently have no choice but to go to Source Generators (which is heavy on the dev cost side due to the bad dev environment) or live with some error-prone boilerplate (which can be manageable but scales poorly with respect to team-wise). Based on that and the logging case, I think there's a case for adding support for this.

    I'm no compiler expert too so, if there's a reason this can't/won't be done for both JIT and AOT, I'd love to know that is the case and learn why that is the case.
     
  2. rauiz

    rauiz

    Joined:
    Mar 19, 2013
    Posts:
    43
    I agree with your point about changing C# semantics but now I'm interested in WHY C# doesn't do this, if you know and care to share (I'm not sure why this use-case couldn't be part of what nameof can be used for, but that conversation would be better suited for a C# forum I suppose...)

    I was aware of TypeManager.GetTypeIndex --- the problem is that it's in the Entities package. I do use DOTS on my project, but I don't want to use ECS for various reasons (I experimented with it and it added more complexity to my project specifically than it added value). I supposed I should have mentioned this in the other post. It'd be nice if we could have something similar to TypeManager in DOTS but outside of the Entities package. IMO, there's so much value in Burst/Jobs alone... I just wished generally useful things like TypeManager and Blobs weren't tied to Entities. A Type hash that is Burst compatible with a built-in name cache would be pretty useful outside of Entities too.

    Giving the types a Hash128 would solve that need as well up to a point --- as part of the reason I wanted to do this was to reduce boilerplate code (I still have to declare this hash on every type that want to use the system). I do this for some other use cases, though, and was already considering this.

    I'm not sure why you are so against experimenting with the tools at your disposal (even if that goes against it's orginal design intent)... If it fits (or is very close to fitting) the problem you have, what's the harm in going through the thought exercise to see if there's anything there? Worst case scenario, it doesn't work, you investigate a bit if you can get it there; if you can't, you move on. Best case scenario, the tool is now more useful than it used to be.

    Anyway, thanks for taking the time to answer.
     
  3. rauiz

    rauiz

    Joined:
    Mar 19, 2013
    Posts:
    43
    I guess what I don't understand is WHY the name of a type (along with it's generic parameters) couldn't be known at compile-time for all callsites. Seems weird to me, as I would imagine you need this information to properly compile the thing anyway... But again, I'm far from a compiler expert (hence my questions). If you know the reason, it'd be nice if you could share it. Btw, I read both the nameof language specification as well as the links it points to and I didn't quite spot a reason for that. Maybe I missed something...

    Back to my original point though, I'll just ask the Burst team then: "What's the chance Burst eventually get's some sort of 'reflection' like TypeManager thing that is independent from Entities but still Burst compatible? I think I'd be fine with it being opt-in via an attribute or something [BurstType]."
     
    Last edited: Sep 9, 2022
  4. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    nameof() is just syntax sugar, and dont exist at IL Level. The C# compiler simple replace nameof(TType) with "TType". And generics still exists in the IL code. Only the JIT compiler creates a separate variant for each type at runtime..
     
    MarcoPersson likes this.