in reply to Re: Is it ok to mix functional and oo programming in one package?
in thread Is it ok to mix functional and oo programming in one package?

There are some gotchas here.

bless { name => 'foo' }, ref($class)||$class;

The ref dance is completely unnecessary. Unless you're implementing a prototype-based OO system (and the rest of the constructor suggests that you're not), drop it.

my $ref = ref $_[0]; if ($ref eq __PACKAGE__) {

This just broke inheritance. If you really need to do this check, use Scalar::Util's blessed() or reftype().

my $obj = new Foo;

This syntax introduces weird parser ambiguities that often depend on the order of compilation. Stick with Foo->new().

Foo::bar($obj);

This breaks inheritance.

... you can make the ref $_[0] business a little cleaner with use UNIVERSAL 'isa'...

That will break delegation and cognates and has the possibility of breaking inheritance. It may break overloading as well.

Replies are listed 'Best First'.
Re^3: Is it ok to mix functional and oo programming in one package?
by gamache (Friar) on Oct 18, 2007 at 20:02 UTC
    my $obj = new Foo;

    This syntax introduces weird parser ambiguities that often depend on the order of compilation. Stick with Foo->new().

    According to the Camel Book beside me, method invocation using the METHOD CLASS_OR_INSTANCE LIST form is exactly equivalent to CLASS_OR_INSTANCE->METHOD (LIST) form.

      When it works, it is. The problem is that it doesn't always work. new Foo has two barewords, and whenever the Perl parser encounters barewords, it has to guess at what they are. Sometimes it has hints at what those barewords are (if it's encountered declarations of filehandles or subroutines) and it can guess correctly. Sometimes it doesn't have hints, because Perl embraces late binding.

      Sometimes it has hints which contradict late binding altogether. There's where you run into problems, because you have to know exactly which hints matter and when the parser knows about them to diagnose and correct the problem.

      Alternately, you could use a syntax which isn't ambiguous to the parser and has the benefit of clarifying what exactly happens (new not being a keyword in Perl as it is in some other languages with OO systems).

        I don't think there's any guessing. If there is, let me know so I can fix this.

      To expand a bit on what chromatic said:

      The key words in "method invocation using the METHOD CLASS_OR_INSTANCE LIST form is exactly equivalent to CLASS_OR_INSTANCE->METHOD (LIST) form." are "method invocation".

      In other words, if new Foo is resolved by the perl parser as a method call it is exactly equivalent. The problem is that it isn't always. For instance, this works:

      #!/usr/bin/perl use warnings; use strict; my $a = new Foo; $a->hello; package Foo; sub new { return bless {},shift; } sub hello { print "hello"; }
      output:
      hello
      While this doesn't:
      #!/usr/bin/perl use warnings; use strict; sub new { print "haha"; return; } my $a = new Foo; $a->hello; package Foo; sub new { return bless {},shift; } sub hello { print "hello"; }
      output:
      Bareword "Foo" not allowed while "strict subs" in use at test.pl line +10. Execution of test.pl aborted due to compilation errors.
        Ahh, interesting. I have never shot myself in the foot with that caliber of bullet. Thank you for elucidating.

        Is there some way to do this:

        #!/usr/bin/perl use warnings; use strict; use Foo; # some "forward declaration" syntax instead of looking for Fo +o.pm? sub new { print "haha"; return; } my $a = new Foo; $a->hello; package Foo; sub new { return bless {},shift; } sub hello { print "hello"; }

        I couldn't find it under use in perlfunc. I was also trying use main::Foo; and use ::Foo; based on some ideas that popped into my head while reading about Packages in perlmod.


        I humbly seek wisdom.

      Avoiding the:

      my $obj = new Foo;
      indirect object syntax is routine Perl style advice. See, for example: