New candidate JEP: 429: Extent-Local Variables (Incubator)

Holo The Sage Wolf holo3146 at gmail.com
Tue Aug 16 21:23:17 UTC 2022


Is it the case that the information content of a carrier made by
c=ExtentLocal.where(k,v) is just exactly
the pair k,v?

Yes

I suppose a carrier made by c.where(k2,v2) contains exactly k,v,k2,v2.

Semantically yes, but implementation wise, it contains exactly c,k2,v2, it
works as a linked-list of (ExtentLocal<T>, T) pairs

(But if k==k2 then the information content is just k2,v2.)

No, c.where(k, v2) will contain c,k,v2 and c will still contain k,v.

I can store a Carrier in a global variable, even pass it to five other
threads, and have each of them call c.run(…) with completely independent
sets of bindings, except for the k,v,k2,v2 mandated by the carrier’s
information content.

Correct

IIRC

You are remembering correctly, there is a method to search for a value in a
Carrier, Carrier#get(ExtentLocal<T> key), but you cannot iterate over
ExtentLocal that are bound to that Carrier.

although maybe usecases will eventually call […]

I am interested to know what use cases may arise, I can’t imagine exposing
the keys of a carrier to be good. A Carrier is basically an ExtentLocal<T>
to T map. If x is a Carrier there is no way to verify a connection between
the current extent and x, so the only thing I can think of is to check if
some ExtentLocal<T> LOCAL is already bound in x before calling to run/call,
but Carrier#get(ExtentLocal<T>) already solves this problem.

Also, in general, exposing the key set of a Carrier may be a source for
security problems. By exposing the keys you are allowing anyone with access
to the Carrier the ability to view and override all of the ExtentLocal<T>s
that are referenced in that Carrier, including private ones.

larger binding-map API sneaks through

Well… It is not part of the API, but using reflection it is possible to get
a hold on the Snapshot object, as well as the Snapshot.prev and
Carrier.prev fields,
which allow you to find all of the ExtentLocals that exist in the current
extent.

A very different design

Remember you need to support situations like:

ExtentLocal.where(k, v)
                   .run(() -> {
                       ExtentLocal.where(k2, v2).run(...);
                   });

So either you are keeping the full extent in the carrier, or make it
mutable and leave the rest as it is now.

Internally, using a static parameter JavaLangAccess JLA, the full extent
current is saved, and the Carrier is a class that helps you store stuff in
the extent (the Carrier saves the key-value pairs, and when you call the
method run/call it adds it to the current extent), so the first option will
needlessly touch internal components (or copy an internal logic to the high
level part of the feature), and making stuff mutable is always a place for
disasters.

To explain a bit on this, apart from Carrier, there exists a (protected)
class called Snapshot, a Snapshot is basically a linked list of Carriers.

Using this JLA you can access the Snapshot of the current extent.

When using run/call, the carrier (bindings) (1) gets the current extent (
prev), (2) creates a new Snapshot(b) whose value is bindings and tail be
prev and (3) sets the current extent to b.

When calling LocalExtent#get(key), (1) LocalExtent get the current extent,
(2) run on each Snapshot, (3) in each Snapshot it run over every Carrier and
search for key


On Tue, Aug 16, 2022 at 10:22 PM John Rose <john.r.rose at oracle.com> wrote:

> I’m very glad to see this moving towards completion.
> Better threads richly deserve better thread locals!
>
> I’d like to check my understanding of the intermediate
> type Carrier. Is it the case that the information content
> of a carrier made by c=ExtentLocal.where(k,v) is just exactly
> the pair k,v? And then, after that, I suppose a carrier made
> by c.where(k2,v2) contains exactly k,v,k2,v2. (But if
> k==k2 then the information content is just k2,v2.)
>
> And if that is true, then I can store a Carrier in a global
> variable, even pass it to five other threads, and have each
> of them call c.run(…) with completely independent sets of
> bindings, except for the k,v,k2,v2 mandated by the carrier’s
> information content.
>
> What I’m trying to exclude here is that a Carrier somehow
> threads in the ambient binding map for the current extent,
> as non-locally defined by all of the caller frames, plus
> whatever bindings might have been provided when the current
> thread was launched.
>
> IIRC you have chosen not to provide general methods for working
> with binding maps. (There is no key/value iterator on Carrier.)
> And then reifying the very special binding map in the current
> extent is right out. I think this is fine, although maybe use
> cases will eventually call for map-like views on both local
> carrier multi-tuples and grand non-local binding maps. Those
> can be added later if needed.
>
> So, my asking to confirm the very finite and local information
> content of the type Carrier is really me double-checking
> that no larger binding-map API sneaks through the current JEP
> API.
>
> A very different design would sneak in an reified map pointer
> into every result of c=ExtentLocal.where(k,v) such that
> bindings available in c.run(…) would come only from c
> and its uplevel pointer, completely blocking any bindings
> present at the call to c.run. I guess such bindings would
> no longer be properly called “extent-local”; only the binding
> map root would be extent local but it would be subject to
> radical editing on each call to c.run(…).
>
> Make sense?
>


-- 
Holo The Wise Wolf Of Yoitsu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/jdk-dev/attachments/20220817/907c492b/attachment-0001.htm>


More information about the jdk-dev mailing list