A year and a half on from 0.2, we're finally ready to solidify Fusion 0.3 in place. This is a new, forward-looking vision for Fusion, introducing new ideas around memory management, contextual value sharing, and dependency traceability.
A lot has changed, so feel free to take some time and revisit the Fusion documentation. We've rewritten a whole lot of it together!
Here's a quick summary of the highlights... at least, I tried to make it quick, there's too much to mention!
Use functions: flexible trace-able dependencies
Starting in Fusion 0.3, we've introduced a better way of writing your logic, so you always know how Fusion is connecting your code together, and you can freely mix and match state objects with plain values throughout your codebase.
The old StateObject:get()
method has been replaced with new "use functions". These functions grab the value for you, but can also do other things in the meantime.
- The most basic use function is
Fusion.peek()
. It grabs the value without doing anything, no matter what. - Every
Computed
andFor
object exposes their ownuse
function, which grabs the value and adds a dependency, no matter what. - Future use functions could do a whole lot more, from flattening deeply nested objects, to aiding constant optimisations, to performing complex observation tasks!
Plus, something exciting. Uniquely, use functions let you mix in regular values in your code, too! With the UsedAs type, your code can easily accept both plain values and state objects. What's, all use functions will recognise plain values and pass them straight through to you, letting you write truly generic code.
Scopes: rigorous, time-travelling memory management
Fusion 0.3 introduces a brand new way of preventing memory leaks, explicitly organising your code, and even performing time travel to warn you about errors your code will run into in the future.
Scopes are like Maids, but more general, more powerful, and coupled with more expressive tools. All the while, your code stays syntactically clean, with minimal impact on every line you write.
Internally, scopes lay an exciting groundwork for deterministic, debuggable memory management. Future development tools will be able to inspect and show you exactly what your program is holding on to, and detect memory leaks with much more accuracy and precision than what similar garbage collection-based tools could offer.
And today, Fusion already performs automatic time travelling analysis, predicting how your code will clean itself up and warning you right away when your code could destroy itself incorrectly in the future.
This is a massive paradigm shift, and we're not done yet. This is the first expression of the idea, and there's plenty to get on with!
Contextuals: pass common props through space and time
Ever had to pass something down through layers and layers of components? We know the feeling.
That's why Fusion 0.3 introduces contextual values. These values can be modified for the duration of a single callback, letting you pass different values to different parts of your codebase, all controlled by code higher up for truly flexible long-distance communication.
Contextuals are very useful for sharing values that aren't quite global. One popular choice is theme colour - you might want to show both light and dark themes at the same time when you're building your UI in Studio, but don't want to pass theme into every component. Not to worry - contextuals give you the ergonomics of global values and the flexibility of props, all in one.
And best of all, contextuals are a generic Luau construct, meaning they're useful outside of Fusion too. Use them anywhere throughout your game, plugin or project - they'll just work.
Safe expressions: error safety that just works anywhere
Code can fail unexpectedly for many reasons. While Fusion tries to prevent many errors by design, Fusion can't stop you from trying to access data that doesn't exist, or taking actions that don't make sense to the computer.
That's where all-new safe expressions come in, Fusion 0.3's novel construct for ensuring your code runs flawlessly, even at the worst of times.
With safe expressions, you can write any error-prone logic as a plain function, and embed it directly into any other expression such as a Fusion instance template. If your code runs fine, your values are passed straight through.
But should something go wrong, the safe expression lets you divert to a separate error handling expression to return any backup values of your choice! You get full information about the error, and access to debug functions like traceback
right in your own code.
Check out Fusion's brand new error safety guide. to learn how to make the most of safe expressions.
Hybrid execution: efficient and more correct than ever
Fusion 0.3 introduces a new hybrid execution model based on pioneering work in the functional reactive programming world.
With hybrid execution, Fusion now completely skips calculations that go nowhere. With this key optimisation, your code can be written more flexibly than ever before without worrying about phantom performance drains from dead-end chains of computation.
But it gets better. Hybrid execution uses pull-based evaluation, meaning we can now guarantee that every state object you read is up to date immediately and on-demand. What's more, hybrid execution will naturally run your computations in the correct order, guaranteeing correct order of operations without running any sorting algorithm. Your code naturally organises itself.
That's all combined with new push-based, deterministic eager execution for observers. That means your code behaves less randomly, letting you safely predict how it runs across a variety of devices. Plus, it enforces correct order of operations for complex nested subgraphs of objects, meaning your code is run less spuriously when re-evaluating complex dynamic graphs of objects.
The cherry on top is Fusion's new similarity algorithm, which is now fully compatible with NaN, userdatas, metatables, OOP objects and frozen tables. The new algorithm runs quickly for common values, while producing accurate results for the vast majority of user code, all without deep checks that bog your computer down.
With all these foundational changes, we can pursue new feature requests with confidence that we're not closing performance options in the future, so expect to see more adventurous and convenient API designs into the future!
Fusion @ RDC - featuring the top UI experts from the community!
We're proudly making a showing on-stage at Roblox's largest worldwide developer conference!
Make sure to tune into our UI frameworks panel, featuring the brightest sparks in the UI community. From Clip It to classrooms, and Reclass to Roblox itself, we've assembled a star-studded team of Frame fanatics - you'll be able to directly ask us the most difficult, thought-provoking questions about UI.
Plus, we'll be freely distributing a working demonstration of Fusion side by side with React, so you can see just how much Fusion can do, and what real code looks and behaves like - all open source for your education and expansion!
Tune in for the "Using UI Frameworks to Conquer Code Complexity" panel at RDC 2024, whether you're attending virtually or in person. Be there or be square 🤠
With every year that goes by, Fusion continues to grow into a more powerful and expressive library. I'm personally looking forward to the next few years - with established fundamentals in place, we have a lot of feature requests to get to.
This is the most exciting project I've had the privilege of leading, and I can't wait to see where we will go.
Onwards!
- Dan
Pull requests
- Fix
[Out]
key type by @krypt102 in #203 - Update Value.spec.lua by @Dionysusnu in #165
- Add immediate observer callback invokation by @krypt102 in #209
- Implement attribute support into New function. by @krypt102 in #199
- fix: Active set to true by default on BillboardGuis by @zw1ce in #214
- Minor type fixes by @dphfox in #215
- Update documentation to include new functions. by @krypt102 in #212
- Improving our contributions document by @dphfox in #91
- Update default properties to include 3D objects by @krypt102 in #219
- Update Fusion's CI Workflow by @krypt102 in #223
- Explicit dependency management by @dphfox in #216
- Improved typing for Spring by @4812571 in #233
- fix(TweenScheduler): force RepeatCount of -1 to update tween by @quantix-dev in #238
- Fixed exporting types by @xSwezan in #245
- Server Support by @4812571 in #252
- Fix ForValues logging error by @krypt102 in #230
- Document attribute errors by @krypt102 in #225
- Fix ForValues producing no values by @Anaminus in #262
- Ensure that springs reach their goals by @boatbomber in #242
- Fix failing defaultProps test. by @Anaminus in #264
- Branding updates by @dphfox in #272
- Agnostic scheduler by @dphfox in #277
- Fix typechecking by @Almost89 in #280
- Make NaN similar to itself by @Aimarekin in #284
- New hero graphic for home page by @dphfox in #294
- Fix missing pkg_resources (hopefully) by @dphfox in #295
- Add version warning for viewing unreleased docs by @dphfox in #296
- Fix overflow behaviour for version warning banner by @dphfox in #297
- Initial implementation of contextuals by @dphfox in #299
- Add test units for the isSimilar function (#285) by @mskfox in #311
- More accurate error messages when failing to set properties by @mskfox in #315
- Fix to ensure springs propogate their final state before they sleep by @Raild3x in #316
- Scopes + memory groundwork by @dphfox in #273
- Fix selene running benchmark by @dphfox in #317
- sRGB Transformations by @jalsop24 in #283
- Fix PlayerList example FontSize property by @dphfox in #321
- Add luaurc for syntax highlighting by @AridAjd in #324
- Fixed an old link & path to use .luau by @iceeburr in #329
- Change
Fusion.doCleanup
to no longer be variadic by @4812571 in #333 - Convert
doCleanup
to use theTask
type by @4812571 in #335 - Add innerScope to the Fusion type by @rdot117 in #336
- Remove redundant properties from Best Practices/Components by @alexasterisk in #342
- Change deriveScope and innerScope to use DeriveScopeConstructor by @rdot117 in #346
- Fix merge not overwriting values by @lukadev-0 in #343
- Use Luau syntax highlighting by @Someon1e in #345
- [Doc] fixed missing "scope" parameter in Computed and For docs by @tapple in #341
- Render callback tutorial by @dphfox in #356
- Add
Child
helper function by @dphfox in #352 - Unimplement Ref by @dphfox in #363
- Add Safe to Fusion type by @znotfireman in #365
- Debugging hooks by @dphfox in #351
- Lazy evaluation / hybrid push-pull execution model by @dphfox in #323
- Update default type of Scope exported by Fusion by @dphfox in #373
New contributors
- @krypt102 made their first contribution in #203
- @zw1ce made their first contribution in #214
- @4812571 made their first contribution in #233
- @xSwezan made their first contribution in #245
- @Almost89 made their first contribution in #280
- @mskfox made their first contribution in #311
- @Raild3x made their first contribution in #316
- @jalsop24 made their first contribution in #283
- @AridAjd made their first contribution in #324
- @iceeburr made their first contribution in #329
- @lukadev-0 made their first contribution in #343
- @Someon1e made their first contribution in #345
- @tapple made their first contribution in #341
- @znotfireman made their first contribution in #365
Full changelog: v0.2-beta...v0.3-beta