Robert Klemme wrote:
> On 09.02.2009 19:15, David Masover wrote:
>> Robert Klemme wrote:
>>> Yes, you can program OO style in Perl and there is /some/ support for
>>> this - but it does not really give you much advantage over doing OO in
>>> C (yes, you can do that: even std libraries do it, see open and fopen
>>> et al).
>>
>> I haven't done enough C to say for sure, but I loved Perl's OO. There 
>> definitely seems to be more there -- inheritance via @ISA, 
>> constructors via bless -- and while some find it ugly to expose all 
>> the underpinnings, that is one thing I love about Perl.
>
> IMHO Perl makes OO unnecessary hard.

Very true. Most CPAN modules manage it anyway, these days, but I agree 
-- OO doesn't have to be that hard.

It is fun, though.

>> It's also one of the same reasons I love Ruby -- I don't have to get 
>> my hands dirty.
>
> "Same reason"?  That sounds strange to me.

I love Ruby because I don't have to get my hands dirty. I love Perl 
because I'm always getting my hands dirty, pretty much out of necessity.

It's something that's unique to each, and something that I love about 
each, under different circumstances.

>> Arguments are simply passed in as an array, which you can either 
>> unpack or not, as you like.
>
> You can do that in Ruby as well.

Yes, I understand. However, if you look at your example:

> def initialize(*a)
>   what, ever, you_like = a

You're still explicitly accepting one positional argument -- it just 
happens to be the magical one that instead matches "zero or more of the 
remaining positional arguments".

For the same reason, I also find it kind of cool that Perl objects are 
typically just hashes with methods attached. Ruby objects, while 
effectively the same thing, tend to hide instance variables away. I like 
that, it's a cleaner approach, but it is still fun to take a hash of 
options, perhaps filter them, and then bless them as an object.

Occasionally, this actually is more convenient. For instance, in Ruby, I 
too often find myself writing code like this:

class Foo
  attr_reader :some, :random, :args
  def initialize some, random, args
    @some = some
    @random = random
    @args = args
  end
end

Or worse, let's say I don't like positional arguments (and I don't):

class Foo
  attr_reader :some, :random, :args
  def initialize options
    @some = options[:some]
    @random = options[:random]
    @args = options[:args]
  end
end

Or worse, say I've written some setters that do something magical. I 
then want to set those if they've been passed in:

class Foo
  attr_reader :some, :random, :args
  def initialize options
    self.some = options[:some] unless options[:some].nil?
    self.random = options[:random] if options[:random].nil?
    self.args = options[:args] if options[:args].nil?
  end
end

Yes, I could do some metaprogramming. I should stress that I do prefer 
Ruby to Perl, for exactly that reason -- if this ever gets too annoying, 
I can probably do something like the following, which has probably 
already been done somewhere:

module AutoInitializer
  def self.included klass
    klass.extend ClassMethods
  end
  module ClassMethods
    def auto_init *args
      include(Module.new do
        attr_accessor *args
        define_method :initialize do |options|
          args.each do |arg|
            if options.has_key? arg
              self.send "#{arg}=", options[arg]
            end
          end
        end
      end)
    end
  end
end

Now my class is only this:

class Foo
  include AutoInitializer
  auto_init :some, :random, :args
end

That's arguably better, but a bit more work at the beginning. Still, 
it's worth comparing to the Perl solution:

sub init {
  my($class, $self) = @_;
  bless $self => $class;
}

Granted, there are better ways to do that. It's certainly going to get 
hairier if there are going to be setters involved. But that is one of 
the fun side effects of what, at first, seams like a haphazard, 
tacked-on design.

JavaScript is similar, in some respects. Suppose someone passes me in a 
hash of options. Well, hashes are objects, so I can just do this:

function Foo(obj) {
  for (var property in obj) {
    this[property] = obj[property]
  }
};

Bam. Not only instant options, but instant extensibility -- nothing 
prevents a user from passing in a function to override one of mine, thus 
creating a singleton descendant of my class.

I'm going to stop now, because this is getting a bit long, and the core 
point hasn't changed -- I like Ruby, and I see how this kind of stuff 
can be done in Ruby, but I wouldn't immediately dismiss these other 
object systems.
>>
>> my $foo_like_thing = Bar::new();
>> Foo::bar($foo_like_thing, $some_other_arg);
> The current object is passed in as an argument, meaning this is just 
> another subroutine -- it lets you do tricks like this:
>
> What does this?  Does it create a Bar and then initializes it as Foo? 

No, it creates a Bar, and calls Foo's bar method on it, if I've gotten 
the syntax right.

>> Kind of like Javascript's call() and apply() -- and I'm not even sure 
>> this can be done in Ruby. For all the duck typing goodness, I can't 
>> seem to figure out how you'd unbind a method and rebind it to 
>> something of an unrelated class, unless there's an explicit tree of 
>> inheritance.
>
> Why would you want to do that?  There's a reason why both classes are 
> unlrelated, i.e. chances are that the method would not work in the 
> other class / object.  If you want to simply share code then you can 
> use modules which is a much cleaner and safer way to do it.

Indeed, modules are usually the saner choice. However, I have done this 
_often_ in Javascript. Probably the simplest example might be the common 
each loop:

function each(array, func) {
  for (var i in array) {
    func.call(array[i], i);
  }
}
each(['one','two','three'], function(i) {
  // now 'this' is bound to the value
});

Granted, that's a toy, but it is more convenient that way. And then 
there are the cases where you want to do something clever -- say you 
have multiple superclasses:

var Bar = {
  // one big pile of funcitons
}
var Super = {
  // another big pile of functions
}
obj.foo = function() {
  if (i_want_super) {
    Super.bar.apply(this, arguments);
  } else {
    Bar.foo.apply(this, arguments);
  }
}

Maybe some of those are actually superclasses. Maybe they're modules, 
and you only need a single method, not the whole module.

Either way, I would put the burden back on you. Why is this so 
dangerous? Why is it any more dangerous than the other duck typing 
tricks Rubyists use every day? Why shouldn't I be able to do:

a.method(:foo).unbind.bind(b)

when a and b aren't related, but I happen to know they share a common 
theme? After all, what ties the method to the object -- isn't it mostly 
going to be calling instance methods, and occasionally accessing 
instance variables -- so why should 'self' be exempted from the "quacks 
like" rule?

> The problem with this is: you _have_ to build it yourself.  If I only 
> get the basic building blocks and have to reapply them over and over 
> again to get the same result (a bunch of classes with methods and 
> state) then I am wasting time.

And then you discover one of the most basic tools in any language: A 
library.

Take my above AutoInitializer example. I could complain that I have to 
reinvent it every time, but clearly I don't. I can just file it away in 
a file called autoinit.rb, and if it turns out to be original, I can 
upload a gem.

Or I can decide to use openstruct instead.

What matters is how powerful those basic building blocks are, and what 
it looks like when you're finished.