3

I'm currently working on a Rails project, and have found times where it's easiest to do

if object.class == Foo
  ...
else if object.class == Bar
  ...
else
  ...

I started doing this in views where I needed to display different objects in different ways, but have found myself using it in other places now, such as in functions that take objects as arguments. I'm not precisely sure why, but I feel like this is not good practice.

If it's not good practice, why so?

If it's totally fine, when are times that one might want to use this specifically?

Thanks!

Ted Kalaw
  • 474
  • 1
  • 3
  • 9

3 Answers3

3

Not sure why that works for you at all. When you need to test whether object is instance of class Foo you should use

object.is_a? Foo

But it's not a good practice in Ruby anyway. It'd much better to use polymorphism whenever it's possible. For example, if somewhere in the code you can have object of two different classes and you need to display them differently you can define display method in both classes. After that you can call object.display and object will be displayed using method defined in the corresponding class.

Advantage of that approach is that when you need to add support for the third class or a whole bunch of new classes all you'll need to do is define display method in every one of them. But nothing will change in places where you actually using this method.

KL-7
  • 46,000
  • 9
  • 87
  • 74
  • `to_s` will be called on the class name returned from `object.class` to try and make the types compatible, so it should work. Also `===` will work for checking for type. `object === Foo` – Joshua Clark Nov 21 '11 at 07:47
  • Tried it in both 1.8.7 and 1.9.2: `object.class == A` works fine (even without `===`), but `object.class == 'A'` doesn't work. – KL-7 Nov 21 '11 at 07:53
  • Yeah, I was tired and didn't mean to put the double quotes in. Edited question for future reference, thanks for the answer! – Ted Kalaw Nov 22 '11 at 07:27
2

It's better to express type specific behavior using subtyping. Let the objects know how they are displays. Create a method Display() and pass all you need from outside as parameter. Let "Foo" know to display foo and "Bar" know how to display bar.

There are many articles on replacing conditionals with polymorphism.

George Mamaladze
  • 7,593
  • 2
  • 36
  • 52
2

It’s not a good idea for several reasons. One of them is duck typing – once you start explicitly checking for object class in the code, you can no longer simply pass an instance of a different class that conforms to a similar interface as the original object. This makes proxying, mocking and other common design tricks harder. (The point can be also generalized as breaking encapsulation. It can be argued that the object’s class is an implementation detail that you as a consumer should not be interested in. Broken encapsulation ≈ tight coupling ≈ pain.)

Another reason is extensibility. When you have a giant switch over the object type and want to add one more case, you have to alter the switch code. If this code is embedded in a library, for example, the library users can’t simply extend the library’s behaviour without altering the library code. Ideally all behaviour of an object should be a part of the object itself, so that you can add new behaviour just by adding more object types.

If you need to display different objects in a different way, can’t you simply make the drawing code a part of the object?

zoul
  • 102,279
  • 44
  • 260
  • 354
  • Thanks, the points you described were my qualms exactly! I definitely agree with both you and KL-7 that making a display method is the most sensible way to do it. – Ted Kalaw Nov 22 '11 at 07:25