-
Notifications
You must be signed in to change notification settings - Fork 143
WIP: Bindings #159
WIP: Bindings #159
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A handful of changes!
@@ -1,4 +1,4 @@ | |||
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui | |||
local PlayerGui = game:GetService("Players").LocalPlayer:WaitForChild("PlayerGui") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An unfortunate consequence of APS, I guess: all my synchronization bugs in all the example code I write start coming to light.
lib/Binding.lua
Outdated
Create a new binding object with the given starting value. This | ||
function will be exposed to users of Roact. | ||
]] | ||
function Binding.create(initialValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I've been doing lately is separating instance methods from static methods, since it becomes clearer which is which. Since we don't expose Binding
to users, that's a little less important.
lib/Binding.lua
Outdated
[Internal.changeSignal] = createSignal(), | ||
} | ||
|
||
binding[Internal.update] = function(self, newValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we define these once and then use metatables to get at them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's probably the way to go. The thing that made this approach convenient is that I could use upvalues instead of making everything private via Symbols, which is an elegant solution conceptually but it makes the bodies of my functions kind of hideous.
lib/createSignal.lua
Outdated
]] | ||
|
||
local DEBUG_SIGNAL = true | ||
local debug_globalSubs = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we drop these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I intended to prune them from the final version
lib/init.lua
Outdated
|
||
Change = require(script.PropMarkers.Change), | ||
Children = require(script.PropMarkers.Children), | ||
Event = require(script.PropMarkers.Event), | ||
Ref = require(script.PropMarkers.Ref), | ||
|
||
createBinding = Binding.create, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be grouped with the other methods!
rojo.json
Outdated
"start-benchmarks": { | ||
"path": "start-benchmarks.server.lua", | ||
"target": "ServerScriptService.start-benchmarks" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you're working locally, you can set the Disabled
property on these scripts instead of removing them from your rojo.json
config!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, but that's only if the file exists :P I think the current state of new-reconciler might be missing the benchmark runner file:
thread '<unnamed>' panicked at 'Unable to watch partition start-benchmarks, with path C:\Users\pdoyle\dev\projects\refs-sample-project\modules\roact\start-benchmarks.server.lua! Make sure that it's a file or directory.', src\vfs\vfs_watcher.rs:86:25 note: Run with
RUST_BACKTRACE=1 for a backtrace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to revert this for the time being in this PR? I'll figure out whatever fun merge mishap happened that made us lose some of these things.
lib/Binding.lua
Outdated
Creates a new binding from the given source and with the given mapping. | ||
|
||
The source can either be a starting value or another Binding object, | ||
which is useful for mapping a binding onto another binding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this function work only for creating a binding from another binding?
Alternatively, can we just inline this functionality into what map
does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this was where I was a bit conflicted trying to converge creating a binding vs. creating a mapped binding. I think moving the logic into map
is probably reasonable.
Co-Authored-By: ZoteTheMighty <pdoyle@roblox.com>
Co-Authored-By: ZoteTheMighty <pdoyle@roblox.com>
Co-Authored-By: ZoteTheMighty <pdoyle@roblox.com>
…ject changes through setHotProperty
rojo.json
Outdated
"start-benchmarks": { | ||
"path": "start-benchmarks.server.lua", | ||
"target": "ServerScriptService.start-benchmarks" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to revert this for the time being in this PR? I'll figure out whatever fun merge mishap happened that made us lose some of these things.
lib/Binding.lua
Outdated
local binding = Binding.create(mapFunc(self:getValue())) | ||
|
||
binding._mapFunc = mapFunc | ||
binding._source = self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably use a more descriptive name, like __upstreamBinding
?
lib/Binding.lua
Outdated
This allows us to avoid subscribing to our source until someone | ||
has subscribed to us, and avoid creating dangling connections | ||
]] | ||
if Type.of(self._source) == Type.Binding and self._disconnectSource == nil then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it sufficient to just check if self._source ~= nil
here? It probably shouldn't be any other type!
lib/Binding.lua
Outdated
_value = initialValue, | ||
_changeSignal = createSignal(), | ||
_mapFunc = mapIdentity, | ||
_subCount = 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's list out other values we have here, even if they're nil
, just so that we have a central place to look.
lib/Binding.lua
Outdated
local binding = { | ||
[Type] = Type.Binding, | ||
|
||
_value = initialValue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to group together all of the internal properties into a sub-table indexed by a symbol? I've been using this pattern in a couple places to hide values in a way that's a little more structured than this naming convention.
lib/Binding.lua
Outdated
end | ||
|
||
local Binding = {} | ||
local BindingInternal = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename this to prototype
or bindingPrototype
to make it more explicit what it does?
* hide private members in subtable * rename BindingInternal * check for nil instead of Type.of * rename 'source' to 'upstreamBinding' * list nil-initialized members in 'create' * directly return parent value from getValue
Closes #158
This PR is a work in progress and is built off of the new-reconciler branch
An initial implementation of Bindings. This addresses the basic use cases for it, and has some mechanisms to prevent unintended access to private functionality.
It also includes a very arbitrary example of how bindings can modify values outside of Roact's render in a more straightforward way than is possible with refs.
TODO: