20

I recently read Crockford's book "Javascript: The Good Parts" and one of the underlying premises was that programming languages can have bad sets of features which programmers should avoid.

I'm a Rubyist and whilst I love the language there's always value in getting perspective. So, what do you see as the worst feature (e.g. methods, classes, practices) in Ruby? My intention here is not to start an argument about the merits of the language itself or its speed and so on. Rather I'd prefer a discussion of what features you consider dangerous / troublesome / painful to use, based on past experiences.

8 Answers8

8

You should watch Python vs Ruby: A Battle to The Death by Gary Bernhardt. He makes the quote:

The very things I find ugly in Ruby are what make amazing Ruby software like RSpec possible, and that Python could never have (given the current implementation).

While he talks a lot about Python in particular, he touches on a lot of stuff that's just weird in Ruby. One of the big overarching subjects is monkey patching.

Ruby objects (unlike objects in some other object-oriented languages) can be individually modified. You can always add methods on a per object basis. In Ruby, the behavior or capabilities of an object can deviate from those supplied by its class.

While this provides a lot of flexibility and powers some of Ruby's most popular and complicated gems, it can bite you in the butt if you're trying to debug an issue without realizing that some library somewhere has modified a core method.

Michelle Tilley
  • 1,229
  • 9
  • 17
8

Some people only think of ruby in terms of ruby on rails and it's kinda annoying because the language stands on its own pretty well.

7

I think the worst feature is open classes which allow you to globally change the behavior of all current and future instances of the changed class.

The problematic part of this feature is, that theses (global) changes happen during runtime when the Ruby interpreter comes across the definition, which might be long after you already instantiated a couple of objects which now change their behavior all of a sudden.

In a large code base this can result in very, very hard to find bugs - especially as this gets compounded by Ruby's weak (as compared e.g. to the CLR or JVM) debugging story and use of other features (e.g. eval) in this context can make it quite hard to find the location where this global change occurred. i.e. if you already reached the point where you suspect the 'right' class causing the trouble! In my experience you usually start out with a wild goose chase, as the problems start to surface at an object using the real culprit.

So the best thing would be, either to stop using open classes (#extend and putting the changes in a Module is IMHO much safer, easier to understand and better to test) or if it can't be avoided to:

  • only extend classes with new behavior (i.e. not overriding existing behavior)
  • have a defined place in the source code tree, where all extensions using open classes have to be placed
  • do not use #eval and friends to create open classes
  • put all usages of open classes on a big visible chart, where all developers can see them - and make clear that any changes on them are 'architectural decisions' affecting the whole code base (which they do) and not the place for quick hacks useful for your current task
Alexander Battisti
  • 1,622
  • 11
  • 11
5

Biggest reason I don't use Ruby: It's slower than molasses in January at the North Pole during an ice age. Benchmarking languages is an inexact science, but Ruby appears drastically slower than even JavaScript and Python.

dsimcha
  • 17,234
  • that was my experience too. – Chuck Stephanski Mar 28 '11 at 01:04
  • 2
    what was the application you developed for which ruby was too slow ? I mean, I believe you when you say it is slow, but how did it stop you from reaching your goal ? – David Mar 28 '11 at 11:20
  • 1
    I think Ruby is great when you want to make something like a prototype and want it done quickly, something that isn't huge and won't be doing massive number crunching. If you expect to be chewing a lot of CPU cycles constantly, any good programmer knows to use something like C or C++. – Jeff Welling Mar 28 '11 at 11:33
  • This answer would be more suited to "What are the things you would like improved in the Ruby language?" than "Ruby: The Bad Parts." – Andrew Grimm Mar 28 '11 at 21:58
  • 1
    @David: I would consider using Ruby for simple DNA sequence processing code, but I don't because Python fills a similar niche, has similar features and is much faster. If I'm willing to go lower level, D is even faster and still convenient. – dsimcha Mar 29 '11 at 00:58
  • 1
    @Jeff: Agreed, but C and C++ are a pain to write in. The point of high-level languages like Ruby is to avoid dealing with this pain as much as possible. The slower they are, the less well they fulfill this goal. Ruby is slow even for a high-level dynamic language. That and NumPy/SciPy are why I use Python instead when I need a high-level dynamic language. – dsimcha Mar 29 '11 at 01:00
  • Slow? Nah. It's fast enough. Language benchmarks are often trotted out to prove some pet theory ("Ruby is slow!") and rarely stand up to any scrutiny. – Rein Henrichs May 04 '11 at 06:37
  • To be fair, as far as interpreted languages go, JavaScript is currently very fast, so being slower than it isn't too bad. – Tikhon Jelvis May 04 '11 at 07:14
  • If what you need in a language is raw speed (e.g. number crunching), then Ruby is not your best choice. Although you may want to keep an eye on JRuby and Rubinius, two new implementations of the Ruby language, which bring to bear the optimizing capabilities of the JVM and the LLVM respectively. – yfeldblum May 04 '11 at 11:57
  • Ruby 1.9 is also improving speed issues with its YARV byte code compiler. All three of the teams are working together to maintain compatibility which is really nice considering there isn't an official standards body overseeing the Ruby language spec. – Berin Loritsch May 04 '11 at 12:06
4

If this can be extended to Ruby on Rails, then:

  1. The fact that the database logic gives every single table an auto_increment primary key, including tables that don't need them and shouldn't have them.

  2. The fact that compound keys aren't supported at all.

For just plain Ruby my gripe would be the same as for any language that trades safety for expressiveness; it's easy to do a lot with just a little code, but it's just as easy to make a huge mess with any amount of code.

aroth
  • 792
  • 4
  • 12
  • Please see my edits as I've narrowed the scope of the question. I'll start another parallel one for Rails if this question with edits is approved. –  Mar 26 '11 at 11:48
  • 1
    Sorry, but you're mistaken, not every table in a Rails app is required to have an auto_increment id, notably join tables for has_and_belongs_to_many relationships are suggested to explicitly NOT have an id column. – Brett Bender Mar 26 '11 at 13:38
  • @Brett - Are those relatively new additions? When I was playing with it back in early 2008 it definitely did not have those features. In any case, it's great that they're available now. –  Mar 26 '11 at 13:49
  • 1
    @aroth: I'm not sure that everyone else would consider "relatively new" to mean "within the last three years" :-) –  Mar 26 '11 at 14:33
  • There's an alternative to Rails' ActiveRecord called DataMapper, which is not as opinionated as ActiveRecord. – Endy Tjahjono May 04 '11 at 11:30
3

Ruby embraces metaprogramming (reflection, introspection), multi-paradigm programming, and dynamism at an uncommon level. It's easy to shoot yourself in the foot with power and flexibility.

Troublesome? Ruby has the ability to be extremely readable or inscruptable. I've seen code that looks like it belongs in a Bash script.

Bad Practices? Some Rubyist value cleverness over wisdom. They write and share tricks that show off their cleverness, but this creates unreadable and fragile code.

As an aside: Javascript was a disaster by design, and "The Good Parts" book tries to extract it's hidden beauty. Perl, a language which popularized "There's More Than One Way To Do It" (that is, flexibility), has a similiar book in "Perl, Best Practices". Perl's history is one of experimentation and hard won experience, "Best Practices" represents its knowledge. Perl 6 will be, I think it's fair to say, a reboot of the language based on that knowledge and more. Ruby may suffer from similar issues.

@James and for loops... When you do a for loop in ruby, it then calls ".each". Therefore, "for" is syntactic sugar for people more comfortable with C style loops. But as a Rubyist, you're going to use iterators like .map, .inject, .each_with_object, all the time. You'll never have to write a for loop with something like "i=0;i>6;i++" in ruby, and so you end up dropping the habit. @andrew... eloquent ruby doesn't endorse for loops.

-1

I'd generally avoid things that were added just to be backwards-compatible with other languages. For example, Perlisms and for x in y.

  • I just posted an answer about Ruby Programmers and for loops, and if you can explain I'd be grateful :-) – James Mar 28 '11 at 09:28
-1

This is more about the programmers than the language, but why do Ruby programmers hate for loops so much?

I realise Ruby has:

someCollection.each do |item|
   ...
end

but I've never seen that used in situations where a for loop would not do exactly the same thing.

I've asked several times and never gotten a good answer to this one.

If it's just a style thing, I'm happy to accept that, but I've seen Ruby programmers get really worked up about this and I'm really curious.

James
  • 1,813
  • 1
    Once I even got the answer "It's less key presses", which is clearly false ... :-) – James Mar 28 '11 at 09:38
  • 2
    Two theories: 1) Using for loops is something n00bs do. People who are programming C in Ruby. 2) Blocks are used a lot in Ruby, so using something not block-like is just extra mental effort. – Andrew Grimm Mar 28 '11 at 10:36
  • 3
    While I just started to learn Ruby, blocks are something that I really like and miss when I try to use Python. Would a for loop do the same thing? Of course, to me, this kind of style just suits my preferences more than a for loop. – Jetti Mar 28 '11 at 12:50
  • It's a style thing. Blocks are "Ruby-like" so most Ruby programmers tend to use blocks instead of things like the for loop which is syntactic sugar anyway in Ruby. It boils down to the "Ruby Way" of doing things. There's no difference just one (the block) feels more like writing Ruby in Ruby and the for loop is more like writing Perl/Python/etc. in Ruby. – Wayne Molina Apr 14 '11 at 18:48
  • 2
    @andrew To be honest, your 1st answer is exactly the kind of rubbish I got back when I've asked before. No real reason, with a subtle insult on top. @Wayne, @Jetti and @andrews 2nd answer: thanks. Fair enough then. – James Apr 14 '11 at 21:51
  • Also, Ruby aspired to be as purely object-oriented as possible; C-style for loops are about as procedural as possible. The Ruby approach clearly focuses on the object. – JasonTrue May 04 '11 at 05:46
  • 1
    If you mean "enhanced" for loops (aka. for in do ...) there is no difference apart from #each being in use and appearance closer to its commonly used cousins #inject, #collect, #reject etc. If you're talking about 'C' style indexed loops (aka. for int i = 0; i < whatever; ++i) the difference is, that a) "off by one" errors are impossible and b) that it makes the intention of your loop clear - #each meaning "for each element produce a side effect". A for loop requires you to read the whole loop just to get the 'gist' of its purpose. – Alexander Battisti May 04 '11 at 13:05
  • 10.times{p '⚣'} – jimworm Oct 01 '11 at 20:53
  • Why would you use a for loop, exactly? In any language that supports it, if you want to iterate over a collection, you use a foreach loop. That's what foo.each |item| do is. And as @jimworm just pointed out, looping a specific number of times is more concise in ruby. 100.times do |n| or 100.times {|n| ...} – KChaloux Aug 29 '12 at 14:24
  • A for loop is an imperative construct as mentioned above. Furthermore it dictates a very specific and sequential order whereas with each you promise that each block could be executed in parallel. – Alessandro Vermeulen Nov 22 '12 at 22:08