vinum-team / Vinum

A modern reactive state management library for correctness and speed.
MIT License
16 stars 1 forks source link

Wrapping RBXScriptSignal #4

Closed sinlerdev closed 1 year ago

sinlerdev commented 1 year ago

What and Why

While a fully Vinum-managed DataModel is highly preferred, it is sometimes simpler to depend on the engine's Data (game) for stuff like Health, as they are more integrated to the engine.

It is also important to note that using wrapped RBXScriptSignal objects is significantly more expensive than Vinum pure objects, so this should be used as the last "approach" to solving your specific problem.


Design

Creation and independent Reading:


local wrappedHealth = Wrap(Humanoid.HealthChanged)

print(wrappedHealth) -- "NotFiredYet" kind of symbol

--- health changed
print(wrappedHealth:get()) -- currentHealth value

Used as an InputState for observes, Matches and Mirrors (#1):

Match(wrappedHealth, {
   [currentHealth] = ...
   ["default"] = ...
}, Vinum.JustOk)
sinlerdev commented 1 year ago

I have thought about this for some time, and I think it would be the most optimal if we opt in for "manual" parameter handling rather than automatic.

For example, if Wrap is used for wrapping an event that is fired with more than 1 argument, all the ones after the first one are completely lost.

The "solution" for this is to make the user pass a function that is fired with the said data, and then use what is returned from it.

Something like this:

local wrapped = Wrap(eventFiresWithTwoArgs, function(arg1, arg2) 
   return {arg1, arg2}
end)

print(wrapped:get()) -- {i.e 1, i.e "hi"}
sinlerdev commented 1 year ago

Another approach that I think is somewhat reasonable is to save all the parameters provided by the signal, and then provide a GetValues method that will return them in the form of tuples.

Something more like this:

local wrapped = Wrap(eventFiresWithTwoArgs)

local currentV1, currentV2 = wrapped:getValues()

Another approach that is heavily inspired by this approach, is to create state objects on Wrap creation, and then update those every time the said signal is fired. I believe this is the right way to go with this "event-wrapping" idea.

i.e

local arg1, arg2 = Wrap(event)

print(arg1:get(), arg2:get()) -- None, None

-- signal is fired
print(arg1:get(), arg2:get()) -- something, something
sinlerdev commented 1 year ago

The final API design is:

local arg1, arg2 = Wrap(numOfStateObjs, event)