vinum-team / Vinum

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

Vinum Toolkit #21

Closed sinlerdev closed 1 year ago

sinlerdev commented 1 year ago

The core library for Vinum is more of an unopinionated library- there are cases where mistakes can happen from your end, and Vinum won't care, and in fact, sometimes it assumes you know what you're doing with it- i.e the Writable modifier doesn't care you passed to it, as it just mutates a single field in the given table, and sometimes, it will allow passing Reflects, but those don't have a way to write to them directly from an internal standpoint.

Of course, the writable-reflect problem can be fixed by simply giving an internal setValue method to Reflect that will error when invoked, however, I think it isn't an ideal solution, as it can introduce some bugs to yourcode. Plus, we could also say that Staticify is a dangerous tool as it directly changes the use parameter to the read standard function- meaning that there're not any checks in place to account for human mistakes.

Aside from error reporting, there are few features that Vinum does not want to provide as it breaks clarity and sometimes, it is entirely useless. The most popular unsupported feature is default processors.

Processors are a very essential and fundamental feature- in fact, they are so fundamental that they are actually a way of assigning some procedures to take place when an update is prompted. Sometimes, however, the processors that are often only needed are isDifferent, and in some cases, isDifferent packed with cleanup, however, since Vinum doesn't want to break clarity, it is required for the user to pass them to an object constructor every single time.

The solution to this is to offer a wrapper over each object constructors, that if no processor is used, a default processor will be used. However, an issue with this is, how are we gonna make the user define those default processors?

As previously mentioned, there are often two universal cases that must be supported:

  1. Objects that it is reasonable to assume they only need isDifferent
  2. Objects that need both isDifferent and Cleanup both combined.

I have a solution, which is not support these cases natively, yet provide tools to support all cases.

Consider this example:

local Constructify = Toolkit.Constructify
local defaultProcessor = Constructify(Processors.Combine {
  Processors.isDifferent,
  Processors.Cleanup
})

local defaultHold = defaultProcessor(Hold)

defaultHold(100)

-- probably will accept explicit processors too
defaultHold(100, anyProcessor)

This does:

  1. Call a function Constructify on a combined processor, which returns a closure that when called, returns a wrapped version of the given constructor.
  2. When the wrapped version is called, it calls the said constructor, and pass it all the given arguments- with the difference that passing processors isn't forced anymore!

Of course, the toolkit library should also optimize for the previously mentioned cases, so pre-defined closures for isDifferent and Cleanup should already be defined.

sinlerdev commented 1 year ago

After some thinking, I am fairly sure that such a toolkit library should be not implemented, and instead modify the core library to do so.