Object Oriented and Functional: Is there a middle ground?

I've been developing in Ruby in my spare time for about three months now and of late I've been having this feeling me that somehow I was missing the point. A lot of the 'niceness' of Ruby which I keep hearing about from my colleagues at work just wasn't showing up in my code. I've done some work in javascript, and somehow the sense of freedom which it engendered - and which I'd expected from Ruby - simply wasn't there. And I was pretty darn sure the problem lay in the way I was thinking about my code and in my approach to solving problems in Ruby.

I realised what it was a few days ago after reading Steve Yegge's rather over-dramatic criticism of Java (and other similar languages like C#) in his Execution in the Kingdom of Nouns post. But when you make it through all the theatrics, he does have a point. We often place pieces of logic in a class with no state - anywhere you use a Strategy pattern would be a good example of this. This was something I took for granted since I've never worked in a language where functions are first-class objects, so I believe he has a point - the only reason we put pure logic into a class with no state (in Java or C#) is because we simply have nowhere else to put it. So I did some digging around and found this marvelous post on closures and higher-order functions which helped me understand what the term 'functions as first class objects' really meant.

The thing which struck me after reading this article was that at some level I'd always thought of method_object.call(*args) as reflection as I would do in Java or C# - and if you need to use reflection to get your job done, you've probably messed something up. I mean, yes, there are some situations where reflection makes complete sense, but I've seen cases where people try to bypass poor object design by using reflection. Besides, there is some a loss of performance in those languages when one uses reflection to invoke a method.

But in Ruby (as I'm given to understand at the moment :-)) this isn't the same thing at all. Here, it's perfectly natural way of doing what you would in Java or C# using a strategy. You simply no longer need to put your code in class because you can create a proc object out of it instead.

I'm sure a lot of other interesting ways of using proc objects will surface once I get down to it and do some solid reading. But first I have a few questions around this implementation of the strategy pattern using procs rather than classes.
  1. Where would I place my proc object with the intent of avoiding name collisions? In a module, perhaps?
  2. How do I unit test this, either using Test::Unit or any other alternative?
  3. Have I gone and gotten it all wrong and missed the point completely - again?

When I can find the time, I'll play with some Ruby code and see what happens, but if you have any suggestions or comments, please feel free to chip in.

3 comments:

Unknown said...

1) In a ProcFactory?

2) My answer to any test-related question these days seems to be: Mocks. State-based testing on Procs seems problematic .. edge cases and whatnot. To test the example from ruby docs I'd do something like:

require 'test/unit'
require 'rubygems'
require 'mocha'

def gen_times(factor)
return Proc.new {|n| n*factor }
end


class ProcTestCase < Test::Unit::TestCase
def test_proc
multiplier = 3
input = mock() #=> would be Fixnum 12
input.expects(:*).with(multiplier).returns(36)
times3 = gen_times(multiplier)
output = times3.call(input) #=> 36
assert_equal(output, 36)
end
end

Arsalan Zaidi said...

If you're serious about functional programming, it might make sense to constrain yourself to one while learning about it. Try Erlang or Haskell.

Scala is pretty sweet too, with it's mix of functional and OO models. It runs on the JVM, which AFAIC is a major plus.

Read my blog post if you want (yes! another hit on my blog! :-). BTW, there should be one coming on Scala soon.

Unknown said...

There are more options Like: Mainsoft Cross Platform Development.
This is .NET to Java Cross Platform Development.