The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

OO Question: No abstract classes or interfaces a good thing?

I'm looking at moving from PHP5 to Ruby, and I've recently had another look at the ruby-lang.org site. There's a section on how Ruby compares to PHP(5).

One of the differences is states is that "there’s no abstract classes or interfaces". I'm no OO guru, but wouldn't that be cause for concern? I've been using frameworks and developing in OO now for about 5 years and while I use abstract classes and interfaces sparringly, I've found them useful - especially when developing a custom Database abstraction layer.

To those of you who have come from another OO language to Ruby, and use Ruby outside of the RoR camp, I ask: do you miss not having abstract classes and interfaces? Is your life now easier without them? What are your thoughts on the matter?

If you can manipulate an object/class at any point, doesn't that make it more important that you can set some rules using an interface or overwrite abstract methods/classes to ensure that you're extending your classes in the right way?

If you can manipulate an object/class at any point, doesn't that make it more important that you can set some rules using an interface or overwrite abstract methods/classes to ensure that you're extending your classes in the right way?

Or you can just build the class and let people use it as-is or in the way they want to.

Unlike classes or objects, abstracts and interfaces are not something that exists in objective reality. They are only "scaffolding" needed to support c++/java static typing system. Since ruby doesn't have static types, there's no need of them.

Unlike classes or objects, abstracts and interfaces are not something that exists in objective reality. They are only "scaffolding" needed to support c++/java static typing system. Since ruby doesn't have static types, there's no need of them.

OK, but isn't that thinking in Ruby terms? How, in Ruby, would you ensure a set of objects to conform to a specific set of methods?

For example, how would I ensure that any developer who creates an extension to my "SendMessage" class makes available the methods I outlined (addRecipient, setBody, sendMessage)? How could I ensure that I don't miss overwriting important methods (such as sendMessage) when extending my "SendMessage" class with "SendHTMLEMail" and "SendTextEMail"? How would I ensure that nobody modifies at run-time the common methods these child classes expect available in the parent (such as parent::getRecipients)?

How, in Ruby, would you ensure a set of objects to conform to a specific set of methods?

1. you document it
2. you unittest it
3. people who extend your class, document and unittest their changes.

The point is you cannot "ensure" anything about your program without running it.

This static vs dynamic (aka interfaces vs ducks, aka java vs ruby) debate has a long long history... I hope you excuse me for not trying to retell the whole story again. Let me just refer you to the Bruce Eckel's article that summarizes both points.

How, in Ruby, would you ensure a set of objects to conform to a specific set of methods?

You can simply test for the existence of a given method before you call it, changing your concern from "is this object the right type?" to "can this object do what I want it to?", which is ultimately what you're concerned about. Advocates of static typing often claim that catching type errors at compile time is better than at run time, but in many people's experience this isn't an issue at all, and even if it were, it can be properly mitigated via the use of unit testing. Also note that there may be other ways of achieving your desired effect using some existing Ruby functionality, such as mixins.

I see... but what I'm concerned about is providing a "scaffold" which the other developers in my team must follow. Its all well and good testing whether the parent has a method which you want to use when you're coding the child class, but I'm developing the parent, and need to be able to create an abstract class and say "these are the methods you must overwrite, failure to do so will cause an error". Is this not possible in Ruby?

It's possible through stupid hacks, but you shouldn't use them. Let the users of your class take care of themselves. Your parent should provide utilities for the children. How (and if) they use them is their business.

I see... but what I'm concerned about is providing a "scaffold" which the other developers in my team must follow. Its all well and good testing whether the parent has a method which you want to use when you're coding the child class, but I'm developing the parent, and need to be able to create an abstract class and say "these are the methods you must overwrite, failure to do so will cause an error". Is this not possible in Ruby?

Why not pass them the spec and let them code it, instead of writing code twice for use once?

Violating your interface or your specs would mean that the end product does not work. That alone should keep conformance to standards high.

Well, following this logic, there is also no mammals (because every mammal is a cat, or a dog, or a cow) and no humans (because they're Tom, or Bob, or Sally). "Animals" is what we call "parent class", not an "abstract" class.

I see... but what I'm concerned about is providing a "scaffold" which the other developers in my team must follow. Its all well and good testing whether the parent has a method which you want to use when you're coding the child class, but I'm developing the parent, and need to be able to create an abstract class and say "these are the methods you must overwrite, failure to do so will cause an error". Is this not possible in Ruby?

The best advice I can give you on starting down the Ruby path is not to figure out how X feature from Y language works in Ruby. If you're used to C++/Java/C# static typing, and class structures, then you have a lot to "re-learn". The best example of this I can give, is as simple as the way a method is dispatched in Ruby.

I've sent a message to the object stored in 'b'. This simple change in how methods are dispatched has immense effects on the language as a whole. It means private isn't really private, it makes interfaces difficult (due to the fact that I could actually change the structure of the interface class, how would that affect classes that are re-using the interface?)

Ruby is a complex language, but you won't get the most out of it's abilities if you just try to re-implement Java/C++ in Ruby.

Ruby is a complex language, but you won't get the most out of it's abilities if you just try to re-implement Java/C++ in Ruby.

This could be problemattic. Coming from a PHP background (I've never bothered with any C++/Java stuff), re-learning a lot of how Ruby handles OO is going to be difficult. Learning OO from books on patterns, then finding that those patterns can't be properly enforced in Ruby is going to be hard, especially when googling ruby seems to return way too much RoR for my liking.

I'm considering putting Ruby down for the minute; it seems as though I'm going to have to make a large investment in time before I can simply make apps with it, as I've been able to do with XQuery, XSL, PHP, and other languages.

This could be problemattic. Coming from a PHP background (I've never bothered with any C++/Java stuff), re-learning a lot of how Ruby handles OO is going to be difficult. Learning OO from books on patterns, then finding that those patterns can't be properly enforced in Ruby is going to be hard, especially when googling ruby seems to return way too much RoR for my liking.

It's not re-learning OO, it's just another addition to how OO can work. In fact most patterns translate fairly well, in fact many are already built into Ruby (Delegates, Enumerators, etc). There are others that don't translate as well. It's not because Ruby can't do those things, it's that it has solved the problem the pattern is trying to address in a different manner.

I'd actually argue that after a couple of weeks with Ruby, you'll feel that it's a much more natural approach OO. It's far from difficult, it's just different. I HIGHLY recommend the Pickaxe book from http://www.pragprog.com, it's pretty much THE reference for how to write Ruby.

I'm considering putting Ruby down for the minute; it seems as though I'm going to have to make a large investment in time before I can simply make apps with it, as I've been able to do with XQuery, XSL, PHP, and other languages.

I'd actually say it's because you're diving in pretty deep, pretty fast. Instead of worrying about why Ruby doesn't have interfaces, work on some smaller, less complex components first. I know the temptation is to leap directly to the more complicated stuff, to get a feel for how your advanced knowledge of Technology X, translates to Technology Y, but when learning a new language, especially one as deep as Ruby, it's probably best to start on the simpler side. That said I've only been writing ruby with any regularity for less than a year, coming from a similar background to your own. Once you get the feel of it, you'll not want to go back to PHP again

Good luck, and please feel free to ask any other questions you get as they come up.

It's not because Ruby can't do those things, it's that it has solved the problem the pattern is trying to address in a different manner.

I see... nobody tells you these things when you pick up a new language... it can be difficult at times, until you find that one resource that makes everything click. http://dpawson.co.uk took me a while to find, but when it did XSL just popped into place in my head after flicking through some of the threads.

Originally Posted by Sgarissta

I HIGHLY recommend the Pickaxe book from http://www.pragprog.com, it's pretty much THE reference for how to write Ruby.

Thanks! Just what I need. I'm sick of walking into bookshops, going to the computer section, and seeing nothing but RoR books. I've got this on order now!

Instead of worrying about why Ruby doesn't have interfaces, work on some smaller, less complex components first.

I've got a task I've assigned myself to complete in Ruby. Would be simple in PHP, but I'm having difficulty knowing where to start in Ruby. I think its just because I'm thinking in PHP terms, and not in Ruby yet. Hopefully the above book will help.

The interface is defined simply to help you and the compiler out at compile time.

In Ruby, it'd look like

Code:

def do_something(p)
p.pop
# Do some other stuff
end

I'm not going to go into the arguments of static vs dynamic typing here, because they've been discussed ad nauseum.

So the real reason you have interfaces is to catch errors at compile time. Abstract classes serve the same purpose, but of course can also provide some of the implementation, use inversion of control, etc.

I remember reading somewhere in these posts, "How do I make sure that people implement the right methods?"
Basically, you just tell them or let their code blow up. In Java when someone implements an interface but forgets the implement one of the methods, the compiler goes "Hey! You still have work to do!" In Ruby, it's the same thing, but it's the interpretter that does it at runtime instead. If you've written a library, and people pass their own objects into it, you just need to tell them what methods to implement. If they don't read it, they'll find out soon enough, just as if they had used an interface.

One last thing I want to point out is the importance of testing in Ruby. In fact, you'll quickly find that TDD in the Ruby community is HUGE. The reason for that is pretty obvious once you go back up to my "or let the code blow up" comment. If you're writing your tests before your production code, the tests are the ones that blow up. Most people agree it's bad to release untested code. In statically-typed languages the compiler will find simple errors like that, so they don't show up in production. But in dynamic languages it's INSANE to release untested code because you don't know about those errors until it's actually running. That's why you'll see so many Ruby hackers use TDD all the time.

Wow this got a lot longer than I anticipated. Hopefully I helped explain some stuff for you though. Finally, you asked if it makes things easier, and I can say 100% that it does for me. I much prefer duck-typing over interfaces. If some code calls a certain method, you just add it to your class. With interfaces, you'll have to implement all the methods, even if you're only using one method! In the end I think it all boils down to how you work. There are upsides and downsides to each of those approaches, and you have to consider them as only a portion of the upsides and downsides to the languages themselves.

Also, one thing I found very illuminating in regards to the Ruby approach was reading Design Patterns, after I had a basic understanding of Ruby. As you read it, you'll find that at least 1/3 of the patterns aren't necessary in Ruby - the problems they solve simply don't exist in Ruby! That's not to say that Ruby is better than Java, but rather that the different approach makes it easy and obvious to write certain types of code, without having to work around the language.

For me, discovering that was a bit of an aha! moment. As I said though, it doesn't make Ruby better, it just illustrates some of the differences. I have no doubt that at some point in the future there will be a language that eliminates some workarounds in Ruby (though I don't know those are yet, only time will tell).

However weird this may sound, I actually find it easier to understand Ruby after understanding the functional programming paradigm. Despite Ruby being totally OO, i didn't really appreciate/understand Ruby's power until i learn Lisp. Transacting from Javascript to Ruby is actually easier than moving from Java to Ruby due to Javascript's metaprogramming capabilities.

I agree with pergesu. Once you start doing Ruby, you realize that your prized patterns are not longer needed.

However weird this may sound, I actually find it easier to understand Ruby after understanding the functional programming paradigm. Despite Ruby being totally OO, i didn't really appreciate/understand Ruby's power until i learn Lisp. Transacting from Javascript to Ruby is actually easier than moving from Java to Ruby due to Javascript's metaprogramming capabilities.

While Ruby is definitely an OO language, it borrows a lot from functional programming as well. Closures, blocks, and in general it's meta programming remind a lot of people of functional languages they've worked in. That said it's missing a few things as well, optimized tail recursion, and if you're a Lisper, then macros definitely seem lacking. I love Ruby because it bridges a lot of the various programming "paradigms" but still gives plenty of room to just be Ruby.

I agree with pergesu. Once you start doing Ruby, you realize that your prized patterns are not longer needed.

Knowing the design patterns is great, it allows you to look at abstraction in a different way for sure. But Ruby being as dynamic as it is, it just doesn't have the same set of problems to solve as some of the other languages, it's great!