The most convincing argument as to why not to include refinements in the Ruby spec comes from alternative implementations like JRuby and Rubinius. Method dispatch will need to be vastly more complex (and have scope-limited caching) to support this feature. Much, much slower. Folks using these implementations are still on the fringe, but it seems wrong to add a feature to Ruby that makes both more complicated code and slower running code.
Wasn't Object#source_location added in 1.9 to help folks understand and find method definitions in code? Shouldn't we simply test our code to ensure it functions correctly and not force additional semantics all the time to fix a rare issue?
> Shouldn't we simply test our code to ensure it functions correctly and not force additional semantics all the time to fix a rare issue?
The problem is you can't. If library A and B define String#to_param differently for internal use you can't use them together, while both of them are perfectly correct on their own.
Thanks for linking this. I'd only glanced at refinements so far... reading these comments and example code makes my head hurt. I wouldn't have thought "solving" monkey-patching with something even more convoluted and confusing was even possible. My favorite code example is from tenderlove:
class Foo < SomeParent
def baz(str)
cached = str.camelize
ary.map {|name| cached + name}
end
end
Could have a completely different meaning than this code:
class Foo < SomeParent
def baz(str)
ary.map {|name| str.camelize + name}
end
end
I wish 2.0 had focused on speed, not a bunch of features that working rubyists really don't care about. Esp. not ones this poorly thought out (you'd think given 2 years discussion they would have abandoned the idea).
I don't much like refinements, but conflicting monkey patches from different third party libraries _has_ been an issue over the years.
The ruby community is not even the first one to notice that, there is plenty of literature on "selector namespaces" and "classboxes" from the smalltalk crowd.
When it comes to monkeypatching, this is one thing that JS and Ruby got wrong. C# got it right. It'd be great if you could monkeypatch in JS/Ruby in a module level scope vs a global scope. Good to see that Ruby is taking steps to remedy this. Too bad my favorite language, JS, hasn't yet.
C# had an easier time here, though, because it's statically typed. Extension methods rely entirely on static types and static binding.
Getting normal method call syntax while still being lexically scoped like extension methods without opening the monkey-patching can of worms is still an open research area as far as I know. I know of classboxes, a proposal for something similar to ES Harmony (that they ended up passing on) and Ruby refinements, and that's pretty much it.
I agree with the intent, but unless you're referring to something else (could well be), Extension Methods in c# aren't monkey patches. They're just semantic sugar. They didn't require new runtime support, just compiler support.
Just write your own JS interpreter inside of JS and make sure you execute your functions inside your own interpreter and not the one provided by the browser... problem solved.
While I run into unexpected monkey-patching from time to time (i.e. just about anytime I include an "active_" library from Rails), I can't remember the last time it's screwed me over. But I can see the potential...what have been the most prevalent cases of conflicts for day-to-day Rubyists?
Merb & DataMapper's integration with Rails 2 was seriously hindered by ActiveSupport's core monkey patching, coupled with how ActiveRecord was inextricably linked with other Rails components.
As a consequence, it really took Rails3's clean up of ActiveSupport to allow for other ORMs and libs to integrate in a safe manner.
I'm not 100% certain about the way that refinements currently work (mainly because I haven't had time to dig into the proposal), but the case that wycats makes for refinements amount to defensive coding. When you chose to include a lib, you should be able to control whether and how it steps on the rest of your app (and w/ refinements that can be done by specifying for other parts of your app, that it should/n't listen when someone tries to monkey patch its stuff).
I had issues with libraries providing fixes for builtin libraries (I believe Net::HTTP), yehuda katz had his own example[0] with activesupport and right_aws, the memorable Chainsaw Infanticide Logger Maneuver[1] rant was about plenty of people redefining Logger's methods. I also believe one of the reason rspec changed their syntax is to avoid some monkey patching issues[2]
The bad thing is, most of the issues would be caught quickly if we could run stuff with -w, but nowadays nobody uses and you'll get floded with warnings from the libraries you use :(
What problem does monkey patching solve? It seems to only add complexity onto the already complex nature of inheritance. What do I gain by adding camelize to String vs. using MyModule.camelize?
Among other things, MyModule.camelize doesn't provide an extension point for polymorphism. Consider a serialization library in which different classes should be able to have separate freeze/thaw behavior. It's possible to do this in current-day Ruby without easy collisions, but it tends to involve cumbersome manual prefixing or emulating method dispatch yourself.
Methods being namespaced in packages separately from the class hierarchy is something CLOS has that I miss in almost all the more Smalltalk-y languages.
`module_eval` and `refinements` seem like good ideas unless you mix them. if `module_eval` wouldn't be so widely used op's arguments about what refinements do to code readability would mostly fall.
...why not simply just find way to discourage people from using these together, like having blocks of code only see refinements from their defining scope, not the one they are actually run in?(this would make it obvious for library authors that mixing these to features is "not sane to do", if the fact that they are used to solve similar when it comes to creating DSLs problems does not make it obvious)
Does anyone know how Objective-C categories handle some of the issues brought up with Ruby 2.0 refinements?
It seems method swizzling is a far less touched trick than monkey patching, and the latest LLVM compiler throws a warning if a category overrides an existing method. I am curious about low level differences in how the two languages approach this problem.
Method swizzling and refinements are basically the same thing. The real difference isn't in the features, it's in the fact that Ruby is a dynamic language, and Obj-C is only dynamically typed. You can swizzle all you want in a statically compiled program, and refinements work equally well in a "static" Ruby program. The problems with refinements start coming to light when you start refining things at runtime, i.e., with module_eval. Obj-C doesn't have this problem, since swizzling happens only once at compile time.
Objective-C categories are just like monkey-patching in Ruby. You can have collision with categories in Obj-C just like in Ruby, you'll just get a compiler warning (maybe error).
[+] [-] kaiuhl|13 years ago|reply
Wasn't Object#source_location added in 1.9 to help folks understand and find method definitions in code? Shouldn't we simply test our code to ensure it functions correctly and not force additional semantics all the time to fix a rare issue?
[+] [-] riffraff|13 years ago|reply
The problem is you can't. If library A and B define String#to_param differently for internal use you can't use them together, while both of them are perfectly correct on their own.
[+] [-] dgregd|13 years ago|reply
Maybe refinements should evolve into some MRI diagnostics mode.
[+] [-] xentronium|13 years ago|reply
Headius technical comments on ruby tracker are a must-read.
As my personal take, I am appalled at refinements. I think this is a bad idea solving the wrong problem.
[+] [-] themgt|13 years ago|reply
[+] [-] andrewvc|13 years ago|reply
[+] [-] riffraff|13 years ago|reply
I don't much like refinements, but conflicting monkey patches from different third party libraries _has_ been an issue over the years.
The ruby community is not even the first one to notice that, there is plenty of literature on "selector namespaces" and "classboxes" from the smalltalk crowd.
[+] [-] jonpaul|13 years ago|reply
[+] [-] munificent|13 years ago|reply
Getting normal method call syntax while still being lexically scoped like extension methods without opening the monkey-patching can of worms is still an open research area as far as I know. I know of classboxes, a proposal for something similar to ES Harmony (that they ended up passing on) and Ruby refinements, and that's pretty much it.
[+] [-] ssmoot|13 years ago|reply
Which is a neat way to go about it.
[+] [-] hnriot|13 years ago|reply
[+] [-] danso|13 years ago|reply
[+] [-] knowtheory|13 years ago|reply
As a consequence, it really took Rails3's clean up of ActiveSupport to allow for other ORMs and libs to integrate in a safe manner.
I'm not 100% certain about the way that refinements currently work (mainly because I haven't had time to dig into the proposal), but the case that wycats makes for refinements amount to defensive coding. When you chose to include a lib, you should be able to control whether and how it steps on the rest of your app (and w/ refinements that can be done by specifying for other parts of your app, that it should/n't listen when someone tries to monkey patch its stuff).
[+] [-] riffraff|13 years ago|reply
The bad thing is, most of the issues would be caught quickly if we could run stuff with -w, but nowadays nobody uses and you'll get floded with warnings from the libraries you use :(
[0] http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-pra...
[1] http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/...
[2] http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectatio...
[+] [-] MatthewPhillips|13 years ago|reply
[+] [-] premchai21|13 years ago|reply
Methods being namespaced in packages separately from the class hierarchy is something CLOS has that I miss in almost all the more Smalltalk-y languages.
[+] [-] munificent|13 years ago|reply
[+] [-] nnq|13 years ago|reply
...why not simply just find way to discourage people from using these together, like having blocks of code only see refinements from their defining scope, not the one they are actually run in?(this would make it obvious for library authors that mixing these to features is "not sane to do", if the fact that they are used to solve similar when it comes to creating DSLs problems does not make it obvious)
[+] [-] pirateking|13 years ago|reply
It seems method swizzling is a far less touched trick than monkey patching, and the latest LLVM compiler throws a warning if a category overrides an existing method. I am curious about low level differences in how the two languages approach this problem.
[+] [-] sha90|13 years ago|reply
[+] [-] judofyr|13 years ago|reply
[+] [-] danso|13 years ago|reply
[deleted]