3 ms·
The thing is, I don't think that we need to kill everything to fix this. You can certainly fix the ruby compiler so that monkey-patching is fast, and you don't
by qwertyuiop924 10y ago
The thing is, I don't think that we need to kill everything to fix this. You can certainly fix the ruby compiler so that monkey-patching is fast, and you don't have to deoptimize for this sort of thing.
Call/cc, OTOH, should be dropped from Ruby. It's caused a great deal of pain for the devs, and it's not nearly as important as it is in something like Scheme. They could implement the similar (though not as cool) shift/reset, and have much of the power of call/cc, an easier implementation, and perf that's practical.
- chrisseaton 10y ago> You can certainly fix the ruby compiler so that monkey-patching is fast, and you don't have to deoptimize for this sort of thing. Do you have a concrete idea for how to support monkey patching without deoptimisation and have it be fast? If you do, congratulations it's a major breakthrough in language research and you should write a paper.
- qwertyuiop924 10y agoI was kind of joking about that. Or something. Seeing as I'm not a compiler/interpreter expert, I honestly don't know what I was thinking posting that. Seriously, what was I thinking? But I'm just thinking this is utterly nuts: Not that I'm degrading your accomplishments. If it's really that hard a problem, than the fact that you have solved it at all is impressive. But the fact that we have to go to those lengths at all is crazy. Part of why it seems so nuts to me is probably because I don't know enough about Ruby's internals. As I understand it, A class's methods are kept in a datstructure, associating them with their identity (I think it was a hashtable at some point, although this may have changed) - A vtable, in C++ parlance. When you monkeypatch a method, you're either adding a function to the vtable, or changing which function a vtable entry points to. I don't know why you have to deoptimize to do that. past-me should have probably understood the problem better before he made claims he couldn't back about it, but there's nothing I can about it now, save apologize for being stupid, and ask for an explanation. Which is what I'm doing now.
- eropple 10y agoI'm not Chris, and he's smarter than I am, but I appreciate that you posted this. More people, myself included, should be better about fessing up when we do something silly.
- qwertyuiop924 10y agoAfter seeing so many people not willing to back down, after being proven demonstrably wrong, I said that I wouldn't do the same. So I try not to.
- chrisseaton 10y agoV-tables solve one problem - method lookup. V-tables are faster than a hash table lookup, yes, but they still mean indirect memory access (so you have to go off and chase pointers around main memory just to make your call), and they're designed for languages where you know the methods that your classes have ahead of time and you know the class of each variable. In Ruby you don't have that. You can call any method on any object. The only theoretical way I think it would work would be if you knew all the method names ahead of time, gave them all an index, and gave each class a v-table large enough to contain them all. In a Rails application I estimate this might be about 5,000 entries - so 40KB per class. And with singleton classes lots of objects have their own class, so 40KB per object! And as I said that doesn't work anyway as the method names are not known ahead of time - they can be dynamically created and the set of method names is infinite. But that was method lookup, and that isn't really our problem. I like to use this example from a real Ruby gem to illustrate the bigger problem. def clamp(min, max, value) [min, max, value].sort[1] end That clamps a value between a min and a max. Using v-tables we could look up the calls to #sort and #[] relatively quickly (well we can't because of the problems with v-tables described above, but I'll keep going) but even with a fast lookup this is still terribly slow code. It creates an array, it sorts it, creating another new array, and then indexes it. To make that code fast we don't just need fast lookup, we need to take the logic from the sort routine and inline it into this method, and we need to remove the loop in sort and specialise it for just three entries, then inline the methods that calls, such as #<=> to compare the values, then specialise the sort code for the fact that we only wanted the middle entry and remove the code for sorting the other entries, and then we need to remove the allocation of the two arrays. We need to be able to automatically turn that Ruby code in this. def clamp(min, max, value) # deoptimise if things aren't as expected if value < min min elsif value > max max else value end end (Pretend that the calls to #> and #< are simple operators like in C). There's not even any lookup there any longer - so lookup was never really part of the problem. And crucially, we need to be able to reverse all that inlining if someone monkey patches any of those methods. V-tables don't help us do any of that, but deoptimisation allows us to be in the middle of executing code like that, and reverse the inlining and the specialisation, allocate the objects we removed the allocation of, and keep going after a monkey patch. The implementation of Ruby I work on, JRuby+Truffle, does that kind of optimisation for real. I wrote a thesis about all of this http://chrisseaton.com/phd/ http://chrisseaton.com/phd/
- angelbob 10y agoCall/cc is actually used by Sinatra for its error handling. There's not a good way to get its syntax without doing it that way. (Is the syntax worth using call/cc? Eh, good question. But Sinatra's killer feature is, literally, its syntax, so I don't think I get to tell them "don't do it that way." Rails has an ugly workaround for not using call/cc that bites many, many app programmers who forget to return after calling render().)