Skip to content

Commit

Permalink
completely removed Observers
Browse files Browse the repository at this point in the history
This change was mostly inspired by this issue, dphfox/Fusion#310

I totally agree with Observers being *completely* redundant, and for the most part unneeded, because most the time when you're creating an Observer it's just to pipe it straight into a `:onBind()` or `:onChange()` call. I've replaced Observers with a function simply called `observe()` which takes the target and the callback as arguments and returns a disconnect function. It adds a set inside the target that holds all of the callbacks and when that target value is evaluate it calls all of those observe tasks, essentially removing the Observer "middleman".

(I know I'm not good at describing these things, you can just look at the changes yourself to see what I mean)
  • Loading branch information
HappySunChild committed Feb 16, 2025
1 parent d629166 commit 68370aa
Show file tree
Hide file tree
Showing 17 changed files with 82 additions and 133 deletions.
6 changes: 2 additions & 4 deletions src/Animation/Tween.luau
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ local getTweenAlpha = require(script.Parent.getTweenAlpha)
local getTweenDuration = require(script.Parent.getTweenDuration)
local lerp = require(script.Parent.lerp)

local Observer = require(package.Graph.Observer)
local Stopwatch = require(package.Animation.Stopwatch)

local castToState = require(package.State.castToState)
local depend = require(package.Graph.depend)
local destructor = require(package.Memory.destructor)
local evaluate = require(package.Graph.evaluate)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local Info = Symbols.named 'Info'
Expand Down Expand Up @@ -63,9 +63,7 @@ local function Tween<V>(
end

function class:onChange(callback)
local observer = Observer(self._scope, self)

return observer:onChange(callback), observer
return observe(self, callback)
end

function class:_evaluate()
Expand Down
77 changes: 0 additions & 77 deletions src/Graph/Observer.luau

This file was deleted.

Empty file removed src/Graph/createContext.luau
Empty file.
10 changes: 8 additions & 2 deletions src/Graph/evaluate.luau
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ local function evaluate(target, forceComputation)
targetMeaningfullyChanged = target:_evaluate() or firstEvaluation
end

target[Symbols.Validity] = 'valid'

if targetMeaningfullyChanged then
if target[Symbols.Observers] then
for callback in target[Symbols.Observers] do
task.spawn(callback, target[Symbols.InternalValue])
end
end

target[Symbols.LastChange] = os.clock()
end

target[Symbols.Validity] = 'valid'

return targetMeaningfullyChanged
end

Expand Down
28 changes: 28 additions & 0 deletions src/Graph/observe.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
local package = script.Parent.Parent

local Symbols = require(package.Symbols)
local Types = require(package.Types)

local castToState = require(package.State.castToState)

local function observe<V>(target: Types.UsedAs<V>, callback: (V) -> ())
if not castToState(target) then
return
end

local observers = target[Symbols.Observers]

if observers == nil then
observers = {}

target[Symbols.Observers] = observers
end

observers[callback] = true

return function()
observers[callback] = nil
end
end

return observe
15 changes: 9 additions & 6 deletions src/Instance/Keys/Attribute.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ local package = script.Parent.Parent.Parent

local Types = require(package.Types)

local Observer = require(package.Graph.Observer)
local castToState = require(package.State.castToState)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local keyCache = {}

Expand All @@ -15,16 +16,18 @@ local function Attribute(attribute: string): Types.SpecialKey
kind = 'key',
type = 'attribute',

apply = function(scope: Types.Scope, applyTo: Instance, value: Types.UsedAs<any>)
apply = function(
_: Types.Scope,
applyTo: Instance,
value: Types.UsedAs<any>
)
if castToState(value) then
Observer(scope, value):onBind(function(new)
observe(value, function(new)
applyTo:SetAttribute(attribute, new)
end)

return
end

applyTo:SetAttribute(attribute, value)
applyTo:SetAttribute(attribute, peek(value))
end,
}

Expand Down
11 changes: 7 additions & 4 deletions src/Instance/Keys/Children.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ local package = script.Parent.Parent.Parent

local Types = require(package.Types)

local Observer = require(package.Graph.Observer)

local castToState = require(package.State.castToState)
local doCleanup = require(package.Memory.doCleanup)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local Children: Types.SpecialKey = table.freeze {
kind = 'key',
type = 'children',

apply = function(scope: Types.Scope, applyTo: Instance, children: Types.Child)
apply = function(
scope: Types.Scope,
applyTo: Instance,
children: Types.Child
)
local newChildren, oldChildren = {}, {}
local newScopes, oldScopes = {}, {}

Expand Down Expand Up @@ -46,7 +49,7 @@ local Children: Types.SpecialKey = table.freeze {

if not childScope then
childScope = {}
Observer(childScope, child):onChange(updateChildren)
observe(child, updateChildren)
else
oldScopes[child] = nil
end
Expand Down
10 changes: 7 additions & 3 deletions src/Instance/Keys/Tag.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ local package = script.Parent.Parent.Parent

local Types = require(package.Types)

local Observer = require(package.Graph.Observer)
local castToState = require(package.State.castToState)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local keyCache = {}
Expand All @@ -16,9 +16,13 @@ local function Tag(tag: string): Types.SpecialKey
kind = 'key',
type = 'tag',

apply = function(scope: Types.Scope, instance: Instance, enabled: Types.UsedAs<boolean>)
apply = function(
_: Types.Scope,
instance: Instance,
enabled: Types.UsedAs<boolean>
)
if castToState(enabled) then
Observer(scope, enabled):onChange(function(new)
observe(enabled, function(new)
if new == true then
instance:AddTag(tag)
elseif instance:HasTag(tag) then
Expand Down
11 changes: 5 additions & 6 deletions src/Instance/Keys/_Parent.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ local package = script.Parent.Parent.Parent

local Types = require(package.Types)

local Observer = require(package.Graph.Observer)
local castToState = require(package.State.castToState)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local function setParent(instance: Instance, parent: Instance?)
local success, err = pcall(function()
Expand All @@ -20,19 +21,17 @@ local Parent = table.freeze {
kind = 'key',

apply = function(
scope: Types.Scope,
_: Types.Scope,
applyTo: Instance,
parent: Types.UsedAs<Instance?>
)
if castToState(parent) then
Observer(scope, parent):onBind(function(new)
observe(parent, function(new)
setParent(applyTo, new)
end)

return
end

setParent(applyTo, parent)
setParent(applyTo, peek(parent))
end,
}

Expand Down
16 changes: 6 additions & 10 deletions src/Instance/applyProperties.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ local package = script.Parent.Parent

local Types = require(package.Types)

local Observer = require(package.Graph.Observer)

local Parent = require(package.Instance.Keys._Parent)
local castToState = require(package.State.castToState)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)
local sortKeys = require(package.Instance.Keys.sortKeys)

Expand All @@ -23,20 +22,17 @@ local function setProperty(instance: Instance, property: string, value: any)
end

local function applyProperty(
scope: Types.Scope,
instance: Instance,
property: string,
value: Types.UsedAs<any>
)
if castToState(value) then
Observer(scope, value):onBind(function()
setProperty(instance, property, peek(value))
observe(value, function(new)
setProperty(instance, property, new)
end)

return
end

setProperty(instance, property, value)
setProperty(instance, property, peek(value))
end

local function applyProperties(
Expand All @@ -55,7 +51,7 @@ local function applyProperties(
local keyType = typeof(key)

if keyType == 'string' then
applyProperty(scope, instance, key, value)
applyProperty(instance, key, value)
elseif kindof(key) == 'key' then
table.insert(specialKeys, key)
end
Expand All @@ -68,7 +64,7 @@ local function applyProperties(
end

if props.Parent then
applyProperty(scope, instance, 'Parent', props.Parent)
applyProperty(instance, 'Parent', props.Parent)
end
end

Expand Down
7 changes: 2 additions & 5 deletions src/State/Computed.luau
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ local package = script.Parent.Parent
local Symbols = require(package.Symbols)
local Types = require(package.Types)

local Observer = require(package.Graph.Observer)

local castToState = require(package.State.castToState)
local depend = require(package.Graph.depend)
local destructor = require(package.Memory.destructor)
local evaluate = require(package.Graph.evaluate)
local isSimilar = require(package.Utility.isSimilar)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local Processor = Symbols.named 'Processor'
Expand Down Expand Up @@ -44,9 +43,7 @@ local function Computed<V, VO>(
end

function class:onChange(callback)
local observer = Observer(self[Symbols.Scope], self)

return observer:onChange(callback), observer
return observe(self, callback)
end

function class:map(processor)
Expand Down
6 changes: 2 additions & 4 deletions src/State/ForPairs.luau
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ local Symbols = require(package.Symbols)
local Types = require(package.Types)

local Computed = require(package.State.Computed)
local Observer = require(package.Graph.Observer)

local castToState = require(package.State.castToState)
local depend = require(package.Graph.depend)
local destructor = require(package.Memory.destructor)
local evaluate = require(package.Graph.evaluate)
local observe = require(package.Graph.observe)
local peek = require(package.State.peek)

local Input = Symbols.named 'Input'
Expand Down Expand Up @@ -53,9 +53,7 @@ function class:map(processor)
end

function class:onChange(callback)
local observer = Observer(self[Symbols.Scope], self)

return observer:onChange(callback), observer
return observe(self, callback)
end

function class:_evaluate()
Expand Down
Loading

0 comments on commit 68370aa

Please sign in to comment.