Hacker News new | past | comments | ask | show | jobs | submit login
We need the eggs (github.com/raganwald)
32 points by raganwald on April 17, 2009 | hide | past | favorite | 24 comments



I'm actually starting to feel sorry for Ruby developers. It seems like any time you install something it can anonymously and unapologetically squash any other thing, whether it's a built-in method, an existing module, or what the meaning of "is" is. Honestly, I'd probably be too afraid to ever install a gem.


To be honest, reading Reg's posts lately you get the impression that this happens all the time. Obviously it does happen a certain amount, hence the various people (quite understandably) complaining about it, but probably not as often as one might start to think, given the number and volume of complaints.


The problem is that when it does happen, you are screwed, hard, and numerous other languages with powerful module systems and powerful metaprogramming and powerful everything-else-that-Ruby-does, and has as many libraries as Ruby (or more), provide a concrete demonstration that you don't need monkeypatching to do awesome things.

Also, the mess only gets bigger as you have more and more people using Ruby. That's part of the seductive danger of the monkeypatching approach... it seems to work so well when you have a small community. Unfortunately, it anti-scales; it gets actively worse the larger the community gets.

So, you are suffering these difficult and often effectively intractable problems (short of modifying other people's libraries which is not something you should need to do in the general case), and in return for this difficulty you get nothing not provided by numerous other languages without such problems.

It's a terrible, terrible trade in the long run. (And the long run is here now.)


Why are you trolling Ruby for this?

There are safe ways to metaprogram Ruby very successfully in an extensible and readable fashion. That's why there's a movement in the Ruby community to kill alias_method_chain for one.

Nor is this a problem that scales with community size. There are bad programmers everywhere. If using their libraries causes your project to explode, don't use their code. Rails is fully admitted to be too clever for it's own good, which is why the push to Rails3 and cleaning out the kludges in the Rails code base is so important. That's why the Merb project was getting so much attention in the first place.

Never the less, this is still about getting numerous different packages to work together. It's a package dependency problem. Granted Ruby's ability to reopen classes anywhere it likes makes this problem more difficult, but i hardly see this as an indictment of any use of the language.

So yes, package management is hard. People should metaprogram responsibly. But that's true in other languages as well. :p


"Nor is this a problem that scales with community size." - The more people you have writing libraries, the more monkeypatches are made in a library, the more likely it is that the monkeypatches will collide. That's so obvious I don't even know how to argue for it.

"Granted Ruby's ability to reopen classes anywhere it likes makes this problem more difficult, but i hardly see this as an indictment of any use of the language."

I do, because other languages manage to provide features and libraries without causing this problem. A problem that is unique to the monkeypatching languages (also Javascript) can be laid at the feet of the design decision to permit it and the community decision to roll in it.

If the community is indeed walking away from monkeypatching.... that doesn't prove I'm wrong, it proves I am and was right about the dangers involved. I don't feel inclined to give the community much credit for coming around to the realization that unfettered monkeypatching is a bad idea two years later than I did.

If you like monkeypatching, you should be listening to Raganwald. He's looking for a way to reap the benefits without paying the price, and I think such a thing could be constructed.

Version control is a separate problem indeed. It should be pointed out that I was responding not directly to the original topic, but the posts that are the parent in this chain. This is perfectly valid.

Oh, and stuff it with the trolling accusation. I'm not looking for flaming responses, I'm hoping to safe someone from stepping into the monkeypatching tarpit that at least historically the Ruby community has advocated so hard for people to leap into. Again, if the community is walking away from that tarpit too, are they "trolling" when they do that? Trolling means something, and it isn't "having strong opinions with reasons given".


Whatever dude, you're not being fair. Particularly with claims like:

"If the community is indeed walking away from monkeypatching.... that doesn't prove I'm wrong, it proves I am and was right about the dangers involved. I don't feel inclined to give the community much credit for coming around to the realization that unfettered monkeypatching is a bad idea two years later than I did."

So "the community" (whoever they are) doesn't move as fast as you do. What have you done to change it? There are people who are out there trying to make things better. Not simply painting everyone with the same brush and then writing them off.

Fine, you've got a problem with the way people use Monkey patching. You should convince people of the dangers of using it. You're not succeeding.

Monkey patching itself isn't the problem. The problem is not writing portable code.

============================

Incidentally i find it extraordinarily frustrating that there are clearly a lot of people who down mod anyone who says anything positive about Ruby (since i can watch my points increase shortly after posting them, only to fall back to basically 1 or zero as time progresses, regardless of the content of my posts).


This is not a monkeypatching problem, per se. It is a problem of scope-independent class definition. There are languages wherin you can monkeypatch the class definition (or the definition of a single instantiation of a class) wherin those patches only are in effect in certain contexts.. so you have a scope to your monkeypatching. I think that this would allow for Interesting Things, while being "safe".


Sometimes monkey patching is good actually. I use Soap4r all the time, and I preferred the debug xml to appear in the console rather than created as a separate file, it was really easy to make a monkey patch that fixed this, without modifying the actual distribution... that way other projects wouldn't be affected.

Another time, there was a small bug in Hpricot, rather than fix it directly in source, I patched it in my code, and removed the patch when the fix was in the production stream.

At least it's nice to have that option available...


> It's a package dependency problem.

If you solve the package dependency problem, you will be left with the meta-programming collision problem. However, I feel that if you solve the meta-programming collision problem, you will also solve the package dependency problem.

Which is the point of this post. I am not saying anything about the size or severity of the two problems, just noting that I think solving one will solve the other.


All of my serious objections to monkeypatching go away if you can scope them.

Then I'm just left with a general "that's icky" feeling that I wouldn't press on anyone.

Raganwald, have you ever used Perl's "local" keyword? It's really similar to what you're looking for; "in this scope and anything I call, the value of the thing identified by $x is now this; when this scope expires, it goes back to what it was before". For what you're looking for, you'd want to drop the "and anything I call" bit, but it's doable.

And I agree that you would also go along ways towards solving this sort of dependency problem.


Raganwald, i agree with your identification of this problem. But the anti-Ruby trolling is getting out of control :( (and i don't blame you for that).

There are a couple different suggestions people have discussed, but some of them, like selector namespacing, have been languishing in discussion land for years (Matz has been talking about it for a while apparently).

This still doesn't solve the case where you have two different plugins or gems that you'd like to use, that require different versions of the same gem. Ruby is open enough to give you enough rope to hang yourself w/ in this case.

The alternative is what... just not doing package versioning? That seems like a step backwards too.


> The alternative is what... just not doing package versioning? That seems like a step backwards too.

Imagine that you have lexical scope for changes to global constants. Like Perl's local keyword or Lisp's let. So you can redefine Array and the new definition is only valid within the lexical scope of a block. Code that the block calls does NOT get the new definition, so your code can have one version of Array#sum, my code can have another, and we can freely call each other or call code that doesn't expect Array to have a #sum method.

Now thinking about that solution to the meta-programming collision problem, the solution to the gem version problem is also plain: gems can be scoped too, and if I use version 1 of a gem in a block and you use version 2 in a block, only the code within our blocks see the effects of the gems they include.

So yes, packages have versions, but the same mechanism that applies lexical scope to meta-programming mediates package version conflicts.


You clearly don't understand package management. Package dependencies is actually a pretty complicated problem. Dependency solving is an NP-complete tree searching problem. Lots of fun.

Anyway, the new guys in rails-core (i.e. the merb-core team) have been working on this and they do have a preliminary solution to the problem.

This is something that wycats (dev lead of merb-core) has been complaining about for a while now.


It's a Rubygems issue, not Ruby.


How so? Rubygems is just a distribution and packaging system; it doesn't do anything special as regards changing the APIs of Ruby's core objects. Ill-considered metaprogramming can be carried out in Ruby regardless of how the code gets loaded.


The line that I was specifically referring is, Honestly, I'd probably be too afraid to ever install a gem.

When you use any packaging system (rubygems, apt-get, cpan), the convenience usually comes at the price of control. In other words, it's very difficult to mix a packaging system with another packaging system or manual installations.

Ill-considered metaprogramming can be carried out in Ruby regardless of how the code gets loaded.

It's true, but with a packaging system you have little control over dependencies so it's difficult to understand the quality of the code you're using. When you install libraries manually, you know specifically what you have on your system and you have the option to not use a library that has a troublesome dependency.

A packing system is not going to prevent ill-considered metaprogramming. But if you have the choice, why would you include an ill-considered library in to your project?


Been bit by that more than a few times, that's why I always freeze rails now. It is the only way. Things should be simpler and more reliable.

ps. I love that you're running your blog through github. Very ingenious.


if i am not mistaken, you can get into similar trouble in javascript with object.prototype. it's interesting that you don't hear much about that, but maybe people just don't expect as much from it.


Mere coincidence that the Python's gem-like packages are called eggs?


Considering that pythons lay eggs, and that Monty Python's use of "Spam and eggs" heavily influences the language's replacement for "foo" and "bar", yes.


I wondered that, also: I didn't think Python's eggs solved this problem... do they?


No, eggs are just an unofficial, "convenient" method for distributing Python modules.

However, AFAIK, Python itself "solves" this problem simply by giving errors whenever you try to import a different version/instance of a module, but I could be wrong.


If you're talking about the native Python modules, I'm pretty sure Python simply ignores repeated imports (and there is no version number in most module names).


Mere coïncidence.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: