Home
Testing 1,2,3... - January 4th, 2005 [entries|archive|friends|userinfo]
djberg96

[ website | Sapphire ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| Ruby Home RubyForge RAA comp.lang.ruby Ruby Documentation ]

January 4th, 2005

A Tale of Two Journals [Jan. 4th, 2005|01:20 am]
I've been tinkering around with different journaling systems. I ditched my use.perl journal - I just felt too constrained there for some reason. Plus, I've decided that Perl is an inferior language from which there is nothing more I can learn, so it just didn't seem right to stay there. Oh, and don't even get me started on Perl 6.

Anyway, I've got two journals - one over at blogspot and this one. I've decided that this one will be the technical journal and the other one will be the non-technical one. So, if you're reading this and would rather read something more personal and less technical, head on over to http://pleasebackawayslowly.blogspot.com. That's me, too.
link6 comments|post comment

More on mixins versus interfaces [Jan. 4th, 2005|01:37 am]
A while back I was complaining about Java interfaces. My point was that they're just not useful. Tonight I'm going to expound on that a bit.

They aren't useful in *dynamic* languages. Why? Because dynamic languages can do better. Since I'm a Ruby guy, let's talk about where Ruby does things better. They're called mixins. A brief tutorial is in order for my brainwashing to be effective, so here I go.

What's a mixin? A mixin is a module that you can "mix into" your class or object. Modules can also be used to define a namespace, but that's the less interesting part of modules. First, let's see an example.
module Foo
   def method_a
      puts "Hello"
   end

   def method_b
      puts "World"
   end
end

So, now we've got a module with two methods defined. That's the first key thing I want you to notice - these methods are defined, not just declared. In other words, they actually DO something.

Let's say I have a class Bar:

class Bar
end

This class doesn't do anything, but I want to mixin the Foo module. So, let's rewrite that code:
class Bar
   include Foo
end

What just happened here? Simple - all of the Foo module's methods are now available to the Bar class and its instances. So now we can do something like this:

b = Bar.new
b.method_a # "Hello"

We can also extend individual objects, or turn the mixed-in methods into class methods rather than instance methods. Consider:

class Baz; end

a = Baz.new
b = Baz.new

# Extend an individual instance
a.extend(Foo)

a.method_a # "Hello"
b.method_a # Illegal!

# Mixin the Foo module as class methods rather than instance methods
# Note that you can mix them in as both class AND instance methods if you wish
class Blah
   extend Foo
end

Blah.method_a # "Hello"


Now that we've had a brief tutorial, let's talk about interfaces some more. But wait, there's nothing really to talk about. Let's say that we're in Java and we've declared a class Bar that implements the Foo interface. The Foo interface requires that 'method_a' and 'method_b' defined. Ok, now what? What have I gained? The Java folks will say that this does two things. First, it guarantees that certain methods will be defined. Second, it gives you a way to talk about the class and its API.

But what have you gained PROGRAMATICALLY? Nothing. Not a damned thing. You have some empty methods that you have to define yourself. Now compare that to mixins. Not only can I talk about the class ("Baz mixes in the Foo interface"), I also don't have to write an implementation. It's already been written! There's nothing more for me to do* if I don't want or need to. Oh, and never fear - I can redefine those methods after the fact if I want to. Consider:
class Zeta
   include Foo
   def method_a
      puts "Howdy"
   end
end

z = Zeta.new
z.method_a # "Howdy"

As a quick aside, the most common module to mixin is probably Enumerable. You will often see, "this class mixes in the Enumerable module" in various Ruby classes. With that, I know which (additional) methods are implemented.

Do I know exactly how these methods will behave? No. I'll have to read the documentation if I want to be very careful, although for most sanely written code DWIM applies. But the same is true of Java's interfaces - you don't know what those methods are going to do. You only know they exist.

Quick review - interfaces do not provide implementation, while mixins do. Plus, mixins are more flexible. So, what's left for interfaces? About the only argument left to deal with are certain libraries where it makes sense to enforce that certain methods are defined. Take database drivers, for example. Say we've got a DBI library where individual drivers must have their own implementation for fetch, fetchall, etc. Doesn't it make sense to use an interface here?

The answer is that you could, but it isn't necessary. Why? Test Driven Development. All you need are some directions (on how to tweak the setup method) and a test suite that executes a series of assertions to ensure that certain methods are defined for your particular object. If your code passes the test suite, you can consider your driver valid. If it doesn't, you've missed something.

What if such a test suite doesn't exist? What happens then? Probably nothing. Most package authors have a clue about the sort of library they're writing for and what they should implement. Even if they goof, it won't take long for the Open Source community to jump on them and have them fix things in short order. What I'm trying to get at is that it just isn't an issue. I can only think of one time where something like that happened, wasn't that serious to begin with, and it was fixed in the next release. That's Open Source at work folks.

Now, if I STILL haven't convinced you that mixins are superior to interfaces in every way, shape and form I would like to know why. I would also like to point you to http://ruby-miscutils.sourceforge.net/. Look for the "interface" package. Yep, I wrote a package that allows you to implement interfaces in Ruby if you REALLY can't let go. :)

* Well, ok, that isn't always the case in practice. If mixing in the Enumerable module, for example, you should define the '<=>' (object comparison) method so that some of the other methods know how to behave properly. Even so, it isn't absolutely required, and it's still a bargain. :)
link5 comments|post comment

navigation
[ viewing | January 4th, 2005 ]
[ go | Previous Day|Next Day ]

Advertisement