I had a really bad experience of the Ruby standard library today. I sat down with a colleague to look at the performance of a small piece of code that happened to be in a hot spot of our code base. We set up a simple benchmark, saw that it was less than ideal performance, reasoned a bit about the code and decided that perhaps it would be better to replace the use of SortedSet with just #sort! for this particular case. So just to be sure we ran perftools.rb to see what was going on. This is what we saw:

Right. Perhaps #sort! wouldn’t be such a good idea after all. And what is SortedSet doing? Why is is even calling #sort! ? How is it a sorted set if it needs to call #sort! ?

Turns out that SortedSet isn’t.

The first the class does is to try to load rbtree . Yes, the standard library class SortedSet is implemented in terms of the gem rbtree . If it can’t load rbtree it creates (via module_eval and a huge string containing the code, of course) a completely retarded implementation instead.

What. The. Fuck.

The Ruby standard library has gotten some (rightful!) flak over the years, but for me this really takes the biscuit. The Ruby standard library is a disgrace. The Ruby community should have thrown it out a long time ago. It’s full of awful code – some of the worst Ruby code I have ever seen is in the standard library. Many of the APIs are horrible, and much of it was written almost as to be as slow as possible.

I think it puts the Ruby community in a bad light. We should be ashamed of it.

If you’ve somehow escaped noticing the issues with the standard library, here’s a smalll gallery of horrors.

Net::HTTP

An API so byzantine that it makes SOAP look simple. Have you ever written code that used Net::HTTP without looking at the documentation first?

That someone wrote open-uri to hide the ugliness for most use cases is one of the few redeeming qualities of the standard library.

There’s tons of good HTTP libraries available as gems, thankfully.

URI

Until recently the code that parsed query strings had an exponential backtrack bug caused by this regex

/\A(?:%\h\h|[^%#=;&]+)*=(?:%\h\h|[^%#=;&]+)*(?:[;&](?:%\h\h|[^%#=;&]+)*=(?:%\h\h|[^%#=;&]+)*)*\z/o

now it’s changed to

/\A(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)=(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)(?:[;&](?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)=(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*))*\z/o

so that’s good, I guess.

Date

Don’t get me started on Date . It’s been updated in 1.9.3 it seems, but prior to that the performance was just atrocious, and the code was even worse. date/format.rb was completely indecipherable before, but now it’s been ported one-way encrypted to C.

The bottom of the barrel

Then there’s the rest. The things that have ended up in the standard library for historical reasons. For some of it I guess it felt like the right thing to include at the time, but other things are just weird. Why is there a prime number finder in the standard library? Why two option parsing libraries? Why tempfile , but tmpdir ?

There’s been suggestions of moving it out of the distribution and into a default gem or gems. Hopefully we’ll see that in Ruby 2.0. It wouldn’t make the code any better but it would at least be a small step in the right direction.

I think it’s a pity that good libraries like Rake were moved in to the standard library, it feels like the opposite of what we want. The slow release cycle makes it completely pointless trying to contribute to making it better. It’s so much easier to write a gem, or send a pull request to an existing gem, push it to RubyGems. The standard library is where gems go to die.