Photo by Joseph Rosales on Unsplash

Children have a very accurate sense of curiosity. For them, everything is new and the smallest things can trigger the spark of wanting to know more and understand what something is. This is more commonly called Curiosity.

“We learn more by looking for the answer to a question and not finding it than we do from learning the answer itself.” — Lloyd Alexander

Much like children’s curiosity spark can be triggered with a new awesome monocular enabling them hours and hours of fun, a Software Engineer like myself can have this same spark triggered by a couple of simple lines of code.

Some weeks ago, I was debugging my code and I came across one of these situations where I felt like a child that just got a new awesome toy. I was struck by curiosity wanting to know how some simple lines of code I had on my screen worked.

For the sake of simplicity, I made this simple code snippet that can illustrate the code and its behavior. And now I have a challenge for you reading this blogpost! Can you know what will be printed in the console after running these simple lines of code?

Do you think you know the output of this code? Keep your answers close, let’s get started with the dissection of this code to understand what’s really happening here!

Once I first saw this piece of code I was pretty sure that I knew what the output would be, but I couldn’t be more wrong! The moment I ran the code and saw the output the curiosity spark lighted up!

The king of this show is the class AsyncLocal, here we have a property using this class named _asyncLocal , so what’s special about AsyncLocal<T> ?

AsyncLocal class allow asynchronous code to use a kind of async -compatible almost-equivalent of thread local storage.

This means that AsyncLocal<T> can persist a T value across an asynchronous flow. Each time you enter an async method a fresh new async context is initiated deriving from its parent async context.

So every time a new async context is created, a shallow copy of the current T value in the parent context made, therefore it is recommended the use of immutable data-types.

Lets picture a simple use case for this class, imagine that you need a way to track and centralize all the logs that happen in a request. AsyncLocal could be one option for this, you just need to assign a value at the beginning of the request and have an interceptor that enriches each log with the value initially.

But there is a catch! When persisting a value through asynchronous flows each new async context is isolated from its parent async context. So the information that is being persisted across an asynchronous flow is only persisted down and not up, meaning that a parent context will never be aware of any child context modifications.

This little detail that I wasn’t aware of when first reading the code was the real deal here, knowing this makes a big difference when interpreting and trying to know what the output would be. So running the code would produce the following output in the console:

Square

Circle

Star

Circle

I showed this snippet to some people and many of them got it wrong in the last value, and that is completely ok because they didn’t know that the context wasn’t persisted in its way up like I didn’t. So at this moment, we can say:

Just like a child gets excited with new and undiscovered things so do Engineers, it’s on our nature to always want to know how and why things work the way they work.

AsyncLocal<T> is a class that enables us to persist a value through asynchronous flows but this persistence only happens from parent-to-child contexts.

Nelson out!