SitePoint Sponsor

User Tag List

Results 1 to 25 of 25

Hybrid View

  1. #1
    SitePoint Enthusiast
    Join Date
    Jan 2004
    Location
    Manchester
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    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?

  2. #2
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Abstract classes aren't really a big deal when you can change the details of any class/method whenever you want. Let's say you wanted to rewrite how Ruby does uppercasing of strings:
    Code:
    # ...some unrelated code up here...
    
    class String
      def upcase
        #do what you want here
      end
    end
    
    "Foo-Bar".upcase #will use your upcase method

  3. #3
    SitePoint Enthusiast
    Join Date
    Jan 2004
    Location
    Manchester
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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?

  4. #4
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by neobuddah
    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.

  5. #5
    SitePoint Evangelist
    Join Date
    Jan 2005
    Posts
    502
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by vgarcia View Post
    Or you can just build the class and let people use it as-is or in the way they want to.
    I like that quote

  6. #6
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You could use a normal class every time you use an abstract class?

  7. #7
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  8. #8
    SitePoint Enthusiast
    Join Date
    Jan 2004
    Location
    Manchester
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog
    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)?

  9. #9
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by neobuddah
    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.

  10. #10
    SitePoint Enthusiast
    Join Date
    Jan 2004
    Location
    Manchester
    Posts
    32
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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?

  11. #11
    ☆★☆★ silver trophy vgarcia's Avatar
    Join Date
    Jan 2002
    Location
    in transition
    Posts
    21,235
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by neobuddah
    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.

  12. #12
    SitePoint Zealot
    Join Date
    Jul 2004
    Location
    Oklahoma
    Posts
    119
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by neobuddah
    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.

    In Ruby lets say I have the following code:
    Code:
    class A
       def some_method
         puts "hello world"
       end
    end
    
    b = A.new
    b.some_method
    What I have really done is

    Code:
    b= A.new
    b.send(:some_method)
    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.

  13. #13
    SitePoint Enthusiast
    Join Date
    Oct 2006
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by stereofrog
    Unlike classes or objects, abstracts and interfaces are not something that exists in objective reality.
    Sure, abstract classes exist in reality. Take for instance animal. No creature is "an animal" and that's it.

  14. #14
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by neobuddah
    OK, but isn't that thinking in Ruby terms?
    Of course it is. We are in the ruby forum after all.

    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.

  15. #15
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  16. #16
    SitePoint Zealot bronze trophy
    Join Date
    Jun 2004
    Location
    Stockholm, Sweden
    Posts
    148
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ruby is a language for people who don't require the language/compiler/etc. to hold their hand for them.

    Yes, your fellow developers might **** up the implementation of child classes. But then you have bigger problems than the fact that your language of choice doesn't prevent them from ****ing up.
    If there is a way to overcome the suffering, there is no need to worry; if there is no way to overcome the suffering, there is no point to worry.
    - Shantideva

  17. #17
    SitePoint Wizard stereofrog's Avatar
    Join Date
    Apr 2004
    Location
    germany
    Posts
    4,324
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  18. #18
    SitePoint Enthusiast
    Join Date
    Oct 2006
    Posts
    85
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    well it would be abstract, because it can't be a concrete object

    no matter what you call it, it's still an abstract class.

  19. #19
    SitePoint Addict
    Join Date
    Mar 2004
    Location
    Grand Junction, CO
    Posts
    292
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I had the same idea as you when I first started using Ruby after several years of doing all my work in Java.

    What you're encountering is Ruby's duck-typing compared to Java/PHP's static typing.

    For example, in Java you may have
    Code:
    public void doSomething(Poppable p) {
      something = p.pop();
      // Do some other stuff
    }
    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.

  20. #20
    SitePoint Addict
    Join Date
    Mar 2004
    Location
    Grand Junction, CO
    Posts
    292
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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).

  21. #21
    SitePoint Member
    Join Date
    Nov 2006
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  22. #22
    SitePoint Zealot
    Join Date
    Jul 2004
    Location
    Oklahoma
    Posts
    119
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by skruby
    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!


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •