From: Yukihiro Matsumoto Date: 2010-12-05T10:37:54+09:00 Subject: [ruby-core:33579] Re: [Ruby 1.9-Feature#4085][Open] Refinements and nested methods 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 writes: | |Hello, | |On Sat, Dec 4, 2010 at 11:56 AM, Yukihiro Matsumoto 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