Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

What is this fascinating Rebind Operation design pattern?

Discussion in 'Input System' started by hypnoslave, Apr 16, 2020.

  1. hypnoslave

    hypnoslave

    Joined:
    Sep 8, 2009
    Posts:
    429
    Hey all! I have to admit that lately, you fine Unity folks have kept me busy learning new design patterns as I'm implementing some of your new packages. This Rebind Operation pattern is totally new to me, and it's fascinating. I was hoping someone was in the mood to enlighten me by explaining how it works:

    Code (CSharp):
    1.  
    2. m_RebindOperation?.Dispose();
    3. m_RebindOperation = m_Action.PerformInteractiveRebinding()
    4.     .WithControlsExcluding("<Mouse>/position")
    5.     .WithControlsExcluding("<Mouse>/delta")
    6.     .OnMatchWaitForAnother(0.1f)
    7.     .OnComplete(operation => ButtonRebindCompleted());
    8.  
    1. If the object isn't null already, we "Dispose" it. Why? Don't we have a garbage collector? Is this related to some kind of low level C++ stuff?
    2. How exactly does this stack of methods resolve its self? I assume that each one... creates (?) a new RebindOperation object that somehow merges in the value of the previous one? That's quite clever. Where is this pattern common? I have never seen it before.
    3. What triggers the rebind operation? is that somehow implemented inside of the "OnComplete" assignment? If so, does the OnComplete assignment have to be at the end of the chain here? I would expect some kind of "okay, now do it" method call to follow all this.
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The pattern is usually called "fluent" in some way or other. You can read more about it here.

    Unfortunately yes, it is. One thing that RebindingOperation holds on to is an InputControlList which in turn holds on to unmanaged C++ memory and thus needs to be disposed of.

    The chain shares a single RebindingOperation so no actual allocations happen as part of the method chain. Different APIs in the input system do the same in different ways. Some just pass structs around that encapsulate the relevant context.

    The pattern has become somewhat common in configuration-style APIs. For example, mocking frameworks (like JustMock and Moq, for example) tend to employ the pattern extensively.

    The Start() method is the "okay, now do it". It'll hook itself into input event processing and thus have the rebind operation run in the background.
     
    hypnoslave likes this.
  3. hypnoslave

    hypnoslave

    Joined:
    Sep 8, 2009
    Posts:
    429
    Wow, fascinating. Thank you very much for the detailed response! I can feel myself getting smarter.

    So even though this object doesn't derive from monobehaviour, you Unity ninjas are hooking it into the event processing system anyway. veeeery sneaky.

    Everything's working nicely so far, once I've managed to get my head around this new system. Thanks again!