Issue #13893 has been updated by cremes (Chuck Remes).


> One detail, where would we define this Local class?
> ::Local sounds too risky. Thread::Local or Fiber::Local sounds misleading.
>

The `Local` class is meant to be private. It's behavior should be the same/similar for both Fiber and Thread. Putting it under the Thread namespace makes sense to me since Fibers are also subordinate to Threads (i.e. they are locked to their creating thread, can't migrate between threads, cannot exist independent of a Thread, etc.).

Syntax:

~~~ ruby
  Fiber.local[:key] = 'fiber local value'
  Thread.local[:key] = 'thread local value'
vs
  Fiber.current.local[:key] = 'fiber local value'
  Thread.current.local[:key] = 'thread local value'
~~~
I understand why you prefer the first syntax since it is shorter. However, I think it obscures the ownership of the thread-local or fiber-local data when making it available via a class method. This local storage does NOT belong to the class; it belongs to an instance of the class. I think in this situation that requiring a few extra keystrokes is necessary to highlight the correct ownership of the data by making it required to access the data via an instance of Thread or Fiber.

Regarding discouraging modification of locals from a different thread/fiber, the `Local` class should be modified to capture the `Thread.current` and `Fiber.current` at the time of creation. This can be checked when accessing the local storage and throw an Exception when a different thread or fiber tries to modify local storage that it does not own. Good catch!

Here's some updated code:

~~~ ruby
  class Local
    def initialize
      @storage = {}
      @thread_creator = Thread.current
      @fiber_creator = Fiber.current
    end
  
    def [](key)
      ownership_check
      @storage[key]
    end
  
    def []=(key, value)
      ownership_check
      @storage[key] = value
    end
  
    def key?(key)
      ownership_check
      @storage.key?(key)
    end
  
    def keys
      ownership_check
      @storage.keys
    end
  
    private
  
    def ownership_check
      return if @thread_creator == Thread.current && @fiber_creator == Fiber.current
      raise ThreadError, "Access to local storage disallowed from non-originating thread or fiber!"
    end
  end

~~~

----------------------------------------
Feature #13893: Add Fiber#[] and Fiber#[]= and restore Thread#[] and Thread#[]= to their original behavior
https://bugs.ruby-lang.org/issues/13893#change-68123

* Author: cremes (Chuck Remes)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Ruby 3 API cleanup suggestion.

The Thread and Fiber classes have a very odd API for setting/getting thread local and fiber local variables. With Ruby 3 coming soon, this is a perfect opportunity to make this API more coherent and return to the Principal of Least Surprise. The concept of Fibers and Threads should be completely separated and we should no longer assume that a Fiber is attached to any particular Thread.

I suggest this:

```
class Fiber
  # Gets a fiber-local variable.
  def [](index)
    ...
  end

  # Sets a fiber-local variable.
  def []=(index, value)
    ...
  end

  # Returns true if the given +key+ exists as a fiber-local variable.
  def key?(key)
    ...
  end

  # Returns an array of fiber-local variable names as symbols.
  def keys
    ...
  end
end

class Thread
  # Gets a thread-local variable.
  def [](index)
    ...
  end

  # Sets a thread-local variable.
  def []=(index, value)
    ...
  end

  # Returns true if the given +key+ exists as a thread-local variable.
  def key?(key)
    ...
  end

  # Returns an array of thread-local variable names as symbols.
  def keys
    ...
  end
end
```

Also, remove ```Thread#thread_variable?```, `Thread#thread_variable_get`, `Thread#variable_set`, and `Thread#thread_variables` since that behavior is already covered by `Thread#key?`, `Thread#keys`, `Thread#[]`, and `Thread#[]=`. The APIs for both Thread and Fiber are more coherent and less surprising with these changes.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>