Monday, July 21, 2025

Fun with ScopedValues: An implementation of Implicit Observers

Executive Summary

This is a long and involved post about a new still-in-preview feature in Java called ScopedValues. It demonstrates a use for them that I think is very cool and fun, that is fairly magical, but without involving any compile-time trickery or bytecode manipulation. Nor even any reflection.

You will learn how to use ScopedValues to replace ThreadLocal patterns, and some reasons why it is better than using ThreadLocal.

I’ve intentionally glossed over some complicating details - thread safety in particular. The actual code makes use of non-blocking thread-safe tools, and some minor use of non-blocking thread-safe checks that are neither here nor there wrt the discussion of ScopedValues. For experienced developers, you’ll probably find some interest in thinking how that would work. For less experienced developers, try not to lose the overall thread in the weeds.

ScopedValue Introduction

Java’s Preview Feature, ScopedValue<T>, provides a utility similar to ThreadLocal<T>, which, if you’ve ever had the pleasure of using to spaghettifi a perfectly good codebase, may not seem like a very good thing at all. However, just as Land Value Taxes are similar to Property Taxes, and Universal Basic Income is similar to welfare, it’s the seemingly minor differences that transform these things into radically superior versions.

A ThreadLocal<T> userContext, more-or-less provides a hack that looks a lot like a Map<Thread,UserContext> userContextByThread. You can use it to store some object:

    // With ThreadLocal:
    ThreadLocal<UserContext> userContext = new ThreadLocal<>();
    
    // Set the value (and hope you remember to clean it later)
    userContext.set(new UserContext("alice"));
    
    // Access it from anywhere in the same thread
    UserContext user = userContext.get(); // "alice"
    
    // Oops, forget to clean up
    // userContext.remove(); // This often gets missed!

And, so long as no one has done any funny business with threading in your app between these calls, it’s all perfectly swell. Well, except for the magical values your code depends on that the compiler cannot check for. And, good luck with your unit and integration tests. Also, good luck tracking down why a value wasn’t in the ThreadLocal that you expected to be there.

So, how does ScopedValue give you access to this magic without screwing up your codebase? Using a scoped value looks like this:

    // Define once
    private static final ScopedValue<UserContext> USER_CONTEXT = ScopedValue.newInstance();

    // Use in a controlled scope
    ScopedValue.where(USER_CONTEXT, new UserContext("alice")) 
       .run(() -> {
          // Only here can we access the value
          UserContext user = USER_CONTEXT.get(); // "alice"
          processUserRequest(user);
      
          // No need to clean up - happens automatically!
       });

Here we’re putting the value in the ScopedValue. And then within that scope, we run some code - a Runnable. Could be a ScopedValue.CallableOp<T,EX> which returns a value:

    R processResult = ScopedValue.where(USER_CONTEXT,new UserContext("alice"))
        .call(ScopedValue.CallableOp<R,EX> myCallable);

This will add UserContext("alice") to the “scope”. It can be retrieved like this:

    USER_CONTEXT.get();
    USER_CONTEXT.orElse(defaultSpecialObject);

It’s a lot like an Optional in how you can retrieve or test for existence of a scoped value. These values are put and retrieved per thread, so multiple threads can all call ScopeValue.where(USER_CONTEXT,…) and put different values into the scope that will be tracked for that thread.

Why is this better than ThreadLocal?

While the code is being run within this ScopedValue, if it uses StructuredTaskScope to run child threads, those threads will inherit the Scoped values. There is no such inheritance with ThreadLocal - if you spin up new child threads, you will have to copy values manually to it.

If code runs ScopedValue.where(USER_CONTEXT,differentUser) while running within that scope, it will not erase the previous value held, but instead stores it in a stack, so that when this inner scope is done, the value of the Scope returns to what it was previously. When using ThreadLocal, you’d have to implement such Stack logic yourself.

When a scope ends, the value reverts to null and is not available. When using ThreadLocal, old values often get left lying around, which is no bueno.

ThreadLocal is also memory intensive if you’re using hundreds of thousands or millions of Virtual Threads, as it stores those values with each thread. ScopedValue does things a bit more efficiently.

ThreadLocal<T>                         | ScopedValue<T>
---------------------------------------|----------------------------------------
Values persist indefinitely            | Values automatically cleaned up when scope ends
No inheritance to child threads        | Values inherit to child threads (with StructuredTaskScope)
Manual stack management needed         | Built-in stack management for nested scopes
Prone to information leaks             | Automatic cleanup prevents informational leaks
Doesn't play well with virtual threads | More efficient than ThreadLocal when using virtual threads

Now the fun

Implement an implicit observer system using ScopedValue.

An implicit observer system lets code automatically react to data changes without explicit registration (or deregistration) of listeners. When a piece of code accesses a value, it is automatically registered as interested in future changes to that value.

I’ll introduce you to the magic we can have with such a system before describing how it works, so bear with me.
With an implicit observer system, we can write code like this:

    public class ComplexGUIWidget {
        private UserState currentUser;
        private Label nameLabel;
    
        public ComplexGUIWidget(UserState currentUser) {
            this.currentUser = currentUser; 
            init(); // <- we create the layout for this component, add the nameLabel to the gui...
            Reactor.begin(this::redraw);
        }
        
        
        public void redraw() {
            nameLabel.setText(currentUser.get().getName());
        }
    }

    // Somewhere else in the codebase
    currentUser.set("Bob");  // <- triggers ComplexWidget redraw() to be called again!

And now the name label will update it’s value anytime any code anywhere changes the userState:currentUser value. We might have some kind of SystemState class that includes the currentUser field, and we pass it around or dependency inject the SystemState to our various classes. It’s handy because an application can focus on managing the state of data (by talking to the SystemState class), and any code anywhere can build itself to automatically react to it. The secret sauce is in the Reactor.begin() method, of course. It is all enabled by the ScopedValue functionality.

    public class Observing {
       // The ScopedValue that tracks the CURRENT_OBSERVER
       private static final ScopeValue<Observer> CURRENT_OBSERVER = ScopedValue.newInstance();
        
                 
        public static void runWithObserver(Observer observer, Runnable operation) {
            ScopedValue.where(CURRENT_OBSERVER, observer).run(operation);
        }
      
        public static Observer getCurrentObserver() {
            return CURRENT_OBSERVER.orElse(null);
        }
    }
     
    public interface Observer {
 
        void notifyChange();
     
        default void observe(Runnable runnable) {
            Observing.runWithObserver(this, runnable);
        }
    }

    public class Reactor implements Observer {
        private Runnable actor;
        private boolean dirty = true;
    
        public Reactor(Runnable a) {
            this.actor = a;
        }

        public void notifyChange() {
            if(!dirty) { //we don't act on every notification, only if we're not dirty.
                dirty = true;
                act();
            }
        }
        
        private void act() {
            // using default observe method inherited from Observer interface
            observe(actor);
            dirty = false; // we ran, we're now clean
        }

        public static Reactor begin(Runnable action) {
            Reactor actor = new Reactor(action);
            Thread.ofVirtual().start(() -> {
                actor.act();
            });
            return actor;
        }
    }

By wrapping the Runnable actor in the call to “observe()”, we are adding ourselves as the CURRENT_OBSERVER to the ScopedValue. We will show the code that reads this ScopedValue in order to track access by Observers.

I didn’t show the thread-safe implementation of the notifyChange or act, largely because it is more complex by far if done thread safe. There would be multiple ways to do this, including just slamming “synchronized” keywords down.

On the other side, we need our containers that actually call our Observers notifyChange methods. These can be pre-built boxes that hold a single value:

    public class ValueDataBox<T> implements DataBox<T> {
    
        // here is the value we contain
        private final AtomicReference<T> value = new AtomicReference<>();
        // we track who called us so we can notify them of a change
        private final ConcurrentLinkedQueue<Observer> dependents = new ConcurrentLinkedQueue<>();

        public T get() {
            addDependent();
            return value.get();
        }
    
        private void addDependent() {
            // refer to our interfaces above, THIS is where we get the CURRENT_OBSERVER from the ScopedValue
            Observer dep = Observing.getCurrentObserver();
            if (dep != null) {
                dependents.add(dep);
            }
        }
     
        public void set(T newValue) {
            final T oldValue = value.getAndSet(newValue);
            if (!Objects.equals(oldValue, newValue)) {
                // if the value actually changes, let folks know
                notifyDependents();
            }
        }
    
        private void notifyDependents() {
            dependents.foreach(Observer::notifyChange);
            dependents.clear();
            // non-thread-safe implementation for simplicity here
            // also important, the list of dependents is cleared when we do this, and so observers are automatically unregistered as listeners.
            // to become listeners again, they have to request our data, which they will do upon notification if they are still interested.
        }
    }

Walk Through of the Flow of Data

The Reactor at the bottom is what triggers the recalculation of all the values in the boxes. Without it, everything just marks itself as “dirty” and then sits. So, a reactor is basically a Runnable function that does some side effect usually, such as drawing to a GUI.

Reactor function -> adds itself as the current Observer in the ScopedValue -> calls for values from boxes -> Boxes ask who is the current Observer from the ScopedValue -> add observer as dependent -> return current value -> Reactor uses values to draw something

When a box’s value changes:

iterate through dependents -> call `notifyChange` for each -> clear list of dependents

Note that ALL of these various data boxes, observers and reactors you create are serviced by a single ScopedValue -

    class Observing {
        private static final ScopeValue<Observer> CURRENT_OBSERVER = ScopedValue.newInstance();
    }

it’s not like there are many being created to do all this tracking. Furthermore, as a user of this library, you don’t even need to know it exists!

Lazy Calculated Values

We can also have have purely calculated values, where we have a DataBox implementation, but also we are an Observer, and our get() method returns a cached value until we receive a notifyChange call, and we ditch our cached value. We don’t eagerly recalculate, but only when our get() method is called and we’re “dirty”, so to speak. In this way, the system is a push-pull system. notifications are sent (pushed), but new values are only calculated on demand (pull, or lazy eval).

Wrapped Containers

We can also do more complex things, such as tracking dependents and sending notifications for values that we aren’t directly containing. We can wrap a List, for example, and have multiple Trackers that we manage somewhat manually upon requests for list data. Ie, when list.iterator() is called, we have a tracker wholeListTracker and:

    public Iterator<T> iterator() {
        wholeListTracker.trackAccess();
        return wrappedList.iterator();
    }

    public boolean add(T newItem) {
        wrappedList.add(newItem);
        wholeListTracker.notifyChange();
    }

And now our wholeListTracker will track observers and send notifications to whomever. Truly wrapping a List and enabling users of the list to depend on notification of any changes, no matter how they happen is involved, but once implemented, is simply usable as a regular list that magically notifies you when it’s changed. If you have a GUI method:

    public void drawSomeGUIStuff() {
        clearAwayCurrentButtons();
        // myMagicNameList is a wrapped List as described above
        for(String name : myMagicNameList) {
            addButtonForName(name);
        }
    }

    // somewhere, maybe in our constructor or init() method:
    Reactor.begin(() -> drawSomeGUIStuff); // <- this starts the process

So, whenever the list changes, we clear the current buttons and redraw them. No other code has to be coupled to this code to make it happen. No other code has to “remember” to notify us, or even know this gui component exists. If the gui component is removed, it will close itself and via some code around the concept of “closing” these observers that I’ve not shown, our draw method is never run again and our component is removed as an observer and we have no listener memory leak.

Difference between Events and State Changes

It should be noted that this is not an event system (I do have an implicit dependency event stream implementation though). The difference between events and state changes is subtle, but crucial. If you have a List set up as a notifying box as above, and then someone adds 3 new items to the list, your reactor functions may get 1, 2, or 3 notifications of changes. The only guarantee is that the last notification received will be for the final and current value of the List.

This is an advantage, if used properly in a system where you are building elements that need to reflect current state, as opposed to in a system where you need to perform actions based on events. In the latter, you need a different mechanism. The advantage of the state reflection system is there is some built-in back-pressure handling, as repeated calls to notifyChange are essentially debounced.

Another advantage is we rarely get to think about our application logic purely in terms of state. We are typically using event-based systems to mimic state based changes, which generally proves awkward and verbose. Also tend to be error prone especially as a system grows and you continually have to fit new behaviors into the current scattered state using various events, and your event functions get more and more complex as they try to keep a growing list of objects correctly in sync. Whereas in a proper state system, you can keep your state together and gather the logic around them, and then build reactors anywhere they need to be to reflect the state. So long as your reactors don’t go changing state, it works very well.

Final Thoughts

This sort of implicit observer setup is not a new idea - you can find something similar in javascript’s MobX library, and the concepts of Functional Reactive Programming go back at least to the 90s. I first encountered a similar framework working at Xerox on embedded printer GUIs. In that case, we didn’t have ScopedValues, and so when the “cells” called get() on each other, they actually sent themselves in the call so the provider cell could add the dependent cell as a dependent. So, the calls were SomeValue x = dataBoxWithValue.get(this). This had the unfortunate effect that code that worked in this fashion had to know that it was working as a Cell.

With the ScopedValue, it can be made implicit, and we can wrap otherwise straightforward methods using the Reactor.begin(Runnable) method. It also allows us to manually track read and write access to any property we want, alongside the property, and thus convert external classes to be DataBoxes.

When you build a GUI with this system, you need to shift your thinking about how you organize knowledge of state and interactions. Rather than building models and views and controllers, with controllers sort of wiring everything up between the models and views and views adding themselves as listeners to models, you set up graph structures of state. At the bottom are very simple single-value boxes where simple facts are stored (user is X, user has selected mode Y, mouse is over widget Z). Next are calculated values that look at those simple values, and maybe multiple of them, and calculate some intermediate value. I have used this sort of thing to build up complex Permissions structures, where at bottom is a basic file-level permssion information, but then built on that are more temporary and contextual changes to permissions that can happen due to perhaps multiple users looking at an object, or entering a “read-only” mode for some purpose, or maybe entering read-only mode because other processes are currently running and you want to prevent changes, etc. Your graph of state can be as capable and complex as you like.

And then your GUI representation of state is built in a way where you’re just writing functions that examine current state and draw themselves accordingly, and they will be re-called when any of the state they looked at changes. If you have hundreds of thousands of such elements, you can set up your state and functions such that these notifications go out very selectively, and only the parts of your gui that need to change run their updates.

ScopedValues of course can have many uses, I just think this one is pretty neat.

Monday, April 16, 2012

A sustainable government

With our current government, sustainability appears to be a problem.  Deficits get more out of hand every year it seems, and the overall debt is simply astronomical.  It can be serviced only providing that the economy continues to grow steadily.  And as we're seeing now, that's not a very safe assumption.

But we also find ourselves contemplating universal health care.  How can we even think about this with our budgeting problems?  And yet, the logic is inescapable: single payer countries pay less per capita on health care than we do.  

But single payer means centrally managed, and there are downsides to that too.  But something has to give, because reality is staring us in the face and insists single payer is clearly superior to what we currently have, but our culture prefers a free market.  Can we get the best of both?

I think we can.  I think I have a solution that creates a free market that is freer and better than it's ever been in this country.  My solution removes all government involvement in education, welfare, social security, and health care (except for some regulation, because I believe it is necessary, just like we regulate certain aspects of car insurance).  Not just reduced, eliminates.  Hopefully the libertarians and fiscal conservatives and free market believers are sitting up and taking notice.

My solution also prevents the poor from being severely disadvantaged or being left out.  No one will be dying in the streets from lack of health care.  Indeed, under this plan, only the truly mentally ill would be homeless and destitute.

So hopefully I have your attention now.

The plan involves a simple and universal living stipend and it's utterly simple.  Choose a percentage of mean income that everyone should receive that can ensure a minimal sustainable life assuming they will have to pay for food, housing, health care.  Say 1/3, just for arguments sake.  Levy a flat tax on all income of 33% on everyone, no deductions.  Redistribute the money equally amongst all taxable adults.  That's it.

Now, usually data on income only gives the median income, but I can estimate the mean. Wolfram Alpha tells me total personal income in the US is 13.26 trillion. There are about 230 million adults in the US, which makes the mean income about $58,000.  So, 1/3 of that is $20,000.  Given $20,000 we are asserting that a person should be able to afford health care, food and shelter and other basics.  Probably if they are frugal enough, they can, and with some government regulation of health care insurance, it can probably be made affordable too.  If a couple pools their resources, $40,000 is plenty to handle basic expenses.

But now, health care can be handled by the free market without having any uninsured, because having a minimal level of health insurance would have to be mandated, like car insurance.  After all, if you have a stroke in the street, we are going to treat you, so therefore you must be part of the insurance pool.  Our humanity demands this of us, and so we all demand you buy into it to pay for it.  The lack of any insurance and source of funding for people we do nonetheless provide health care for is a large source of expense in the current system. 

Education can be handled by the free market too, because we can also expect that people have the money to pay for education.  Children receive no stipend until a certain age, so there is no financial benefit to having children.  However, a couple receiving $40,000 a year could afford some education for their children.  

Social security is no longer needed - this is social security.  For everyone.  Same with welfare: this is it.

So now we've removed the biggest unsustainable parts of the government's budget.  Of course, we'd have to get military spending in line too (I don't think any plan works without dramatically reducing our military spending and wars), but that's a separate issue.  The remaining government needs for money add up to about $2.2 trillion. That includes federal, state and local spending, with all pension, welfare, health care, and education spending removed. Military spending makes up about $900 billion of that. $2.2 trillion is about 16.5% of the 13.26 trillion total personal income. It could be paid for with an additional 16.5% float tax rate, bringing the total rate to 50%.

So, we are taxing everyone 50% of their income, and redistributing 33% and using the remaining 16.5% for additional government services.  If you are making $25,000/year currently, you would pay $12,500 and receive $20,000, for total take home of $32,500.  Compare that to what such a person would currently pay, some small amount of income tax, but %15 percent social security tax, 8% sales tax - or probably taking home $20,000.

Someone who makes $80,000 would keep $60,000, which is fairly on par with current levels, again taking social security and sales tax into account.

Someone who makes $500,000 would keep $270,000, and now we see that clearly, the bulk of the money is coming from the wealthy, and your opinion on that will likely vary with your chosen ideology.

However, the point I want to stress is how much of a free market this is enabling.  Not only is the government no longer providing education, health care and welfare, but now everyone in the country is able to take part meaningfully in the free market.  With more people able to make real choices with their money (and not forced, they actually have enough power to reject economic relationships they currently often can't), they add to the markets ability to efficiently allocate resources and provide price discovery.

Monday, December 5, 2011

This Time It's Different

"This Time It's Different" is a catch-phrase often used to indicate an idea is dumb because it flies in the face of history and predicts something that's never happened before.  Ie, "Peak Oil" is dumb for the same reason it would have been dumb to fear the end of whale oil.  We didn't stop using whale oil because we ran out, we stopped because we found real oil.  And we won't stop using oil because we'll run out, we'll stop using it because we'll find the next energy source that will be better.

However, sometimes, it really is different.  It was different for the Easter Islanders when they cut down one too many trees.  It was different when that asteroid hit 65 million years ago.  It was different when nuclear weapons were invented.  Some might call these Black Swans (ala Mr Taleb).

The singularity, regardless of how one defines it, would be different too if it came about.  It is essentially the argument of the singularitarians that exponential change inevitably leads to something different, and that is what makes the singularity - when all bets are off on being able to understand what will happen tomorrow based on our experiences of yesterday.

And, it is nearly impossible for humans to grasp how the exponential curve grows, as it always looks pretty linear to us until it's too late.  Thus, we all will be looking around, seeing nothing much and thinking "ya right, 'This Time It's Different', sure", and then, it happens.  The transition between "nothing much" and "holy crap!" ought to be the subject of a thousand science fiction novels.

This blog is about what's different, or what might be different, this time.  I believe, this time it is different.  Even worse, it seems to be a saddle point between a few possibilities: technological singularity and post-scarcity, ecological collapse, and resource depletion.  One or all of these non-linear trends might very well explode any time now.  How can we possibly predict?  But we have to try.