Hi,

I am neutral about local rebinding.  It is useful sometimes (as
someone has pointed out in this thread).  At the same time, I agree
with you that performance impact is a huge negative factor against
local rebinding.  We need more input.  Dave, what do you think?
Anyone else?

							matz.

In message "Re: [ruby-core:33578] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods"
    on Sun, 5 Dec 2010 10:06:46 +0900, Charles Oliver Nutter <headius / headius.com> writes:
|
|Hello,
|
|On Sat, Dec 4, 2010 at 11:56 AM, Yukihiro Matsumoto <matz / ruby-lang.org> wrote:
|> |For the main cases, I see it working this way:
|> |
|> |* Parser sees "using" in a scope
|> |* Child scopes will now be parsed as though they are refined
|> |* VCALL, FCALL, CALL in child scopes are instead RVCALL, RFCALL, RCALL
|>
|> I see this optimization nice for refinement, but it's impossible to
|> implement local rebinding (a la classbox) that some wanted in this
|> thread this way.
|
|Yes, and that is a primary reason why I would not include local
|rebinding if I were implementing refinements. I don't see how it's
|possible to do without adding overhead to every call (to constantly
|check if there's a refinement active) and forcing the global cache to
|be flushed repeatedly (since a refinement can be applied from any
|scope in any thread at any time). In essence, with local rebinding,
|all method calls would have to:
|
|* Ping on every call to see if a refinement is active, since it's not
|possible to narrow the refinement to only locally-rebound methods.
|* If a refinement is active, check to see if any active refinements
|affect them. This would at minimum require inspecting the refinement
|to see if it includes methods for the target object's class.
|* Either only cache refined methods within that one activation or
|don't cache methods at all, since other calls shouldn't see refined
|methods in the global cache.
|* Do all this in a way that is thread-safe, does not modify any
|globally-visible state, and only impacts the activation where
|refinements are active.
|
|So at a minimum, all calls in the system would have to constantly ping
|*additional* some global state. Because any refinement anywhere would
|modify that state, any time any thread does a local rebinding, all
|calls would have to check to see if they are affected. And refined
|code would require at least adding extra checks to all method cache
|validations (to ensure what was cached was not from a refinement not
|active in the current activation) or require that refined code never
|cache (or only cache within that activation, which would only be
|useful if those call sites are encountered many times in a single
|activation).
|
|For a real-world example of how local rebinding causes problems, look
|at Groovy. Groovy allows local rebinding down-thread; i.e. if a
|"category" is active, all invocations deeper in that thread must check
|the thread-local category to see if they are affected by it. As a
|result:
|
|* All calls everywhere have to constantly check thread-local state to
|see if a category is active
|* Calls down-stream from a category have to check whether the category
|affects them
|* Calls down-stream from a category that are affected by it have to do
|a slow-path uncached method lookup every time
|
|The end result of Categories in Groovy are:
|
|* All performance is affected by them, and fixing it is difficult
|* Users don't use them anymore, since the performance of calls
|down-stream from the category are much slower than regular calls
|* The Groovy team generally regrets that they were added, due to the
|long-term effects
|
|They are considered (by most folks I've talked to) to be a mistake,
|but now there's no going back. It's interesting to note that the
|Groovy approach at least only affects one thread, and there are no
|concurrency issues; only the categorized thread sees the change, and
|since it's explicitly in thread-local state, there's no impact across
|threads. But as in Refinements, the presence of Categories as a
|feature means all calls have to be slower. And even worse, as Groovy
|has moved forward with more and more optimizations, two things have
|made it difficult: open classes and categories. The latter could have
|been avoided.
|
|A Refinements implementation that adds overhead to all calls will
|damage Ruby (or at least, Ruby's chances of being a high-performance
|language) forever.
|
|- Charlie