Coderefs in objects: tricky questions

Discussion in 'Perl Misc' started by peterkayatwork@yahoo.com, Sep 26, 2005.

  1. Guest

    I have an object (using standard AUTOLOAD from perltoot) that I want to
    pass a coderef to and be able to run the coderef from.

    If I do this:
    new {
    .... # standard object creation from perltoot
    $self->{Sub}=sub { return $self->Real(@_) };
    return $self;
    };

    sub Real
    {
    my $self=shift;
    my $arg=shift;
    return "[$arg]\n";
    }


    then I can call it via:
    print &{$object->Sub}("Hi");

    and get
    [Hi]

    Few questions:
    1. Is this a Bad Way To Do It?
    2.
    This doesn't work:
    $self->{Sub}=\&{$self->Real};

    Why not?

    The error I get is:

    Use of inherited AUTOLOAD for non-method Object::Hi() is deprecated at
    Object.t line 22.

    Really terribly helpful, isn't it? I can do stuff in Perl, but having
    a super-duper handle on WTF the AUTOLOAD stuff is doing with coderefs
    is a bit beyond me :)

    If anyone has a good answer for why this is happening, I'd love it. If
    anyone has a good suggestion for which FM to read, I'll do so.

    3. Is there a way to set $self->{Sub} without using 'sub'?

    Thanks,

    --Peter
    peterkayatwork (at) yahoo.com
     
    , Sep 26, 2005
    #1
    1. Advertising

  2. Guest

    wrote:
    > I have an object (using standard AUTOLOAD from perltoot) that I want to
    > pass a coderef to and be able to run the coderef from.
    >
    > If I do this:
    > new {


    You need "sub new {". Please post real code.

    > ... # standard object creation from perltoot
    > $self->{Sub}=sub { return $self->Real(@_) };
    > return $self;
    > };


    You said you wanted to pass the coderef into the object, but here
    you are hard coding it, rather than getting it out of new()'s argument
    list!


    >
    > sub Real
    > {
    > my $self=shift;
    > my $arg=shift;
    > return "[$arg]\n";
    > }
    >
    > then I can call it via:
    > print &{$object->Sub}("Hi");


    >
    > and get
    > [Hi]


    Really? I get:

    Can't locate object method "Sub" via package "foo" at object.pl line 23.

    I can't tell if forgot to define the method Sub, or if you forgot to put
    curlies around your dereference of $object using the key 'Sub'.
    Again, post real code.


    >
    > Few questions:
    > 1. Is this a Bad Way To Do It?


    Yes. Not passing a coderef into an object is a bad way to pass a coderef
    into an object. Not posting real code is a bad way to get help on your
    code. And piercing the object encapsulation by directly dereferencing the
    object from outside the package (which it looks like you may be doing) is
    usually a bad way to do OO.

    > 2.
    > This doesn't work:
    > $self->{Sub}=\&{$self->Real};
    >
    > Why not?


    I think it is invoking $self->Real, and then trying to do \&{} on the
    results of that invocation.


    > 3. Is there a way to set $self->{Sub} without using 'sub'?


    $self->{Sub}=$coderef;


    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Sep 26, 2005
    #2
    1. Advertising

  3. Guest

    wrote:
    > Please post real code.


    ######################################################
    # Parent.pm
    #!/usr/bin/perl

    package Parent;
    use strict;
    use warnings;

    use Carp;

    our $AUTOLOAD;

    my %fields = (
    Name => undef,
    Sub => undef,
    );

    sub new
    {
    my $class=shift;
    my $self={
    _permitted => \%fields,
    %fields,
    };
    bless ($self, $class);
    return $self;
    }

    # Automatically create methods for everything defined in %fields above:
    sub AUTOLOAD {
    my $self = shift;
    my $type = ref($self)
    or croak "$self is not an object - cannot AUTOLOAD";

    my $name = $AUTOLOAD;
    $name =~ s/.*://; # strip fully-qualified portion

    unless (exists $self->{_permitted}->{$name} ) {
    croak "Can't access `$name' field in class $type";
    }

    if (@_) {
    return $self->{$name} = shift;
    } else {
    return $self->{$name};
    }
    }

    1;

    ######################################################
    # Object.pm
    #!/usr/bin/perl

    package Object;
    use strict;
    use warnings;

    use Parent;
    our @ISA=qw(Parent);

    sub new
    {
    my $class = shift;
    my $self = $class->SUPER::new();
    my($element);
    # Not needed yet:
    # foreach $element (keys %fields) {
    # $self->{_permitted}->{$element} = $fields{$element};
    # }
    # @{$self}{keys %fields} = values %fields;

    # Give this derived object a default bit of code:
    $self->{Sub}=sub { return $self->Real(@_) };
    return $self;
    }

    sub Real
    {
    my $self=shift;
    my $arg=shift;
    return "[$arg]\n";
    }


    1;

    ######################################################
    # Object.t
    #!/usr/bin/perl
    use strict;
    use warnings;

    use Test::More;

    use Object;

    my $object = new Object;

    print &{$object->Sub}("Hi");

    ######################################################
    # Command line:
    > perl Object.t

    [Hi]
    >


    ######################################################
    Is there a better/more appropriate way to post all the code?
    --Peter
    peterkay (at) yahoo.com
     
    , Sep 26, 2005
    #3
  4. Guest

    wrote:
    > ######################################################
    > # Object.t
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    >
    > use Test::More;
    >
    > use Object;
    >
    > my $object = new Object;
    >
    > print &{$object->Sub}("Hi");


    Sorry, this should have been:

    is(&{$object->Sub}("Hi"), "[Hi]", "Can call coderef from
    $object->Sub");

    (with appropriate command line result)

    It's a bit simplier then what I'm really doing, but illistrates the
    situation :)

    --Peter
     
    , Sep 26, 2005
    #4
  5. wrote in news:1127773260.746269.57950
    @g14g2000cwa.googlegroups.com:

    > wrote:
    >> Please post real code.

    ....

    > # Object.t
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    >
    > use Test::More;
    >
    > use Object;
    >
    > my $object = new Object;
    >
    > print &{$object->Sub}("Hi");
    >
    > ######################################################
    > # Command line:
    >> perl Object.t

    > [Hi]
    >>

    >
    > ######################################################
    > Is there a better/more appropriate way to post all the code?


    Code that works would be great.

    D:\Home\asu1\UseNet\clpmisc> z
    You tried to run a test without a plan! Gotta have a plan. at
    C:/opt/Perl/lib/Test/More.pm line 362
    # Looks like your test died before it could output anything.

    After fixing that:

    D:\Home\asu1\UseNet\clpmisc> z
    1..1
    not ok 1 - Can call coderef from Object=HASH(0x19178e8)->Sub
    # Failed test (D:\Home\asu1\UseNet\clpmisc\z.pl at line 69)
    # got: '[Hi]
    # '
    # expected: '[Hi]'
    # Looks like you failed 1 test of 1.

    So, we fix that by changing the test case to

    is( &{$object->Sub}("Hi"),
    "[Hi]\n",
    "Can call coderef from $object->Sub"
    );

    D:\Home\asu1\UseNet\clpmisc> z
    1..1
    ok 1 - Can call coderef from Object=HASH(0x19178f4)->Sub

    I did slightly modify your code to put everything in one script. The
    modified version follows below.

    I did follow the messages in this thread, but I am still not sure what
    your actual question is.

    #!/usr/bin/perl

    package Parent;
    use strict;
    use warnings;

    use Carp;

    our $AUTOLOAD;

    my %fields = (Name => undef, Sub => undef);

    sub new {
    my $class = shift;
    my $self = {
    _permitted => \%fields,
    %fields,
    };
    bless $self, $class;
    }

    # Automatically create methods for everything defined in %fields above:
    sub AUTOLOAD {
    my $self = shift;
    my $name = $AUTOLOAD;
    $name =~ s/.*://;

    unless (exists $self->{_permitted}->{$name} ) {
    croak "Can't access `$name' field in class ".__PACKAGE__;
    }

    if (@_) {
    return $self->{$name} = shift;
    } else {
    return $self->{$name};
    }
    }

    package Object;

    use strict;
    use warnings;

    use base 'Parent';

    sub new {
    my $class = shift;
    my $self = $class->SUPER::new();

    $self->{Sub} = sub { return $self->Real(@_) };
    return $self;
    }

    sub Real {
    my $self = shift;
    my $arg = shift;
    return "[$arg]\n";
    }

    package main;

    use strict;
    use warnings;

    use Test::More tests => 1;

    my $object = Object->new;

    is( &{$object->Sub}("Hi"),
    "[Hi]\n",
    "Can call coderef from $object->Sub"
    );

    1;


    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Sep 26, 2005
    #5
  6. Guest

    wrote:
    > wrote:
    > > Please post real code.

    >
    > ######################################################
    > # Parent.pm
    > #!/usr/bin/perl


    Thanks, now I can run your code, and have slightly better idea of what you
    are trying to do. (Although I still don't know *why* you are trying to do
    it.)

    However, when I replace your code

    $self->{Sub}=sub { return $self->Real(@_) };

    With the other code from your original message:

    $self->{Sub}=\&{$self->Real};

    I do not get the error you report in your original message.
    I get:

    Use of uninitialized value in concatenation (.) or string at Object.pm line
    33. Undefined subroutine &main::[]
    called at Object.t line 13.

    So it looks like I was right before, $self->Real is being invoked,
    returning "[]\n", which is interpreted as the name of a subroutine. If you
    want to delay the execution of $self->Real, then you do have to use sub {}
    to do it.


    > ######################################################
    > Is there a better/more appropriate way to post all the code?
    > --Peter
    > peterkay (at) yahoo.com


    Well, I would have just put all the packages into one file. But the way
    you did it was perfectly reasonable.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Sep 27, 2005
    #6
  7. Guest

    A. Sinan Unur wrote:
    > I did follow the messages in this thread, but I am still not sure what
    > your actual question is.


    I guess the only question I have left is:

    3. Is there a way to set $self->{Sub} without using 'sub'?

    I want to pull this effect off:

    > $self->{Sub} = sub { return $self->Real(@_) };


    without using 'sub'. I'd love to know how to correctly set up the code
    ref directly. But as was pointed out:

    $self->{Sub}=\&{$self->Real};

    seems to be trying to call $self->Real and then execute the return
    string as code...

    > use base 'Parent';


    Where the h*ll is this documented?

    --Peter
    peterkayatwork (at) yahoo.com
     
    , Sep 28, 2005
    #7
  8. Paul Lalli Guest

    wrote:
    > A. Sinan Unur wrote:


    > > use base 'Parent';

    >
    > Where the h*ll is this documented?


    The profanity is unnecessary, and is unlikely to encourage anyone to
    render your assistance. (No, I'm not saying I or anyone else will
    refuse to help you if you use "hell" - with or without censoring - I'm
    just saying it doesn't aid your cause at all).

    The base pragma, like all modules and pragmas, is documented in the
    associated perldoc:
    perldoc base
    or
    http://perldoc.perl.org/base.html

    Paul Lalli
     
    Paul Lalli, Sep 28, 2005
    #8
  9. "Paul Lalli" <> writes:
    > The base pragma, like all modules and pragmas, is documented in the
    > associated perldoc:
    > perldoc base
    > or
    > http://perldoc.perl.org/base.html


    I think the real question was, "How should I have known I am supposed
    to 'use base'? And that's a fair question. I looked in perltoot--
    it's not even mentioned. In perlobj I see one mention, but it's very
    much in passing, and unless you're reading carefully for references to
    'use base', it's easy to miss. I see a nice explanation in perlboot,
    but I don't know that I had even heard of that one until I was
    searching for further references in perltoot.

    'perldoc base' is only useful if you knew you needed 'use base' in the
    first place, and wanted to know more. Otherwise, it's just lost in a
    sea of very similar looking documentation.

    -=Eric
     
    Eric Schwartz, Sep 28, 2005
    #9
  10. Paul Lalli Guest

    Eric Schwartz wrote:
    > "Paul Lalli" <> writes:
    > > The base pragma, like all modules and pragmas, is documented in the
    > > associated perldoc:
    > > perldoc base
    > > or
    > > http://perldoc.perl.org/base.html

    >
    > I think the real question was, "How should I have known I am supposed
    > to 'use base'? And that's a fair question.


    Eh. Maybe. I could see the OP's question being taken either way.
    Either "Why isn't it documented that I should use this?" or "I am
    completely unable to locate the documentation for this pragma."

    Ambiguity strikes again.

    Paul Lalli
     
    Paul Lalli, Sep 28, 2005
    #10
  11. "Paul Lalli" <> writes:
    > Ambiguity strikes again.


    ... or does it?

    -=Eric, just here to help
     
    Eric Schwartz, Sep 28, 2005
    #11
  12. Guest

    wrote:
    > A. Sinan Unur wrote:
    > > I did follow the messages in this thread, but I am still not sure what
    > > your actual question is.

    >
    > I guess the only question I have left is:
    >
    > 3. Is there a way to set $self->{Sub} without using 'sub'?


    I suppose you could set up either a source filter or a properly prototyped
    subroutine. Then instead of using "sub" you could use
    "supercallifragilisticexpialidotious" or whatever you prefer. I'm not sure
    why you would want to do this.

    >
    > I want to pull this effect off:
    >
    > > $self->{Sub} = sub { return $self->Real(@_) };

    >
    > without using 'sub'.


    Why? What other keywords do you have an aversion to? What is next, do you
    want to use lexical variables without using "my"? Do you want to use
    modules without using "use" or "require"? Do you want to use grep without
    using "grep"?

    If you have a Perlish reason for wanting to avoid "sub", and if you tell us
    what that reason is, perhaps we can help. If you just have some irrational
    aversion to the three letter combination "sub", then I'm afraid that is a
    psychological problem, not a Perl problem.


    > > use base 'Parent';

    >
    > Where the h*ll is this documented?


    perldoc base.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Sep 28, 2005
    #12
  13. Eric Schwartz <> wrote in
    news::

    > "Paul Lalli" <> writes:
    >> The base pragma, like all modules and pragmas, is documented in the
    >> associated perldoc:
    >> perldoc base
    >> or
    >> http://perldoc.perl.org/base.html

    >
    > I think the real question was, "How should I have known I am supposed
    > to 'use base'?


    No one said that the OP should have used 'use base'?

    The use base line was in the code I posted in response to the OP's
    question. I used it rather than mucking with the @ISA by instinct, and
    did not even comment on it.

    > And that's a fair question.


    Of course it is. And it can be answered by the OP reading the
    documentation, or asking that particular question, instead of responding
    with a profanity to my post.

    Sinan
    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Sep 28, 2005
    #13
  14. Guest

    Paul Lalli wrote:
    > wrote:
    >>A. Sinan Unur wrote:
    >>>use base 'Parent';

    >>
    >>Where the h*ll is this documented?

    > The profanity is unnecessary, and is unlikely to encourage anyone to
    > render your assistance. (No, I'm not saying I or anyone else will
    > refuse to help you if you use "hell" - with or without censoring - I'm
    > just saying it doesn't aid your cause at all).


    Yes, I suppose you're right; I was flustered and using "natural"
    language.

    > The base pragma, like all modules and pragmas, is documented in the
    > associated perldoc:
    > perldoc base


    Ah. I can see clearly now - I looked under perltoot and under '-f
    use', where it's certainly not documented. I read it not as (with
    parens for logic, not perl):

    use (base 'Parent'); # parent is DO to base

    but as

    (use base) 'Parent'; # base is somehow modifying use

    I suppose I could even smack myself in the head and exclaim "dumbass!"

    I'll claim I'd had a long day! :)

    --Peter
     
    , Sep 28, 2005
    #14
  15. Guest

    wrote:
    > wrote:
    >>3. Is there a way to set $self->{Sub} without using 'sub'?

    > If you have a Perlish reason for wanting to avoid "sub", and if you tell us
    > what that reason is, perhaps we can help. If you just have some irrational
    > aversion to the three letter combination "sub", then I'm afraid that is a
    > psychological problem, not a Perl problem.


    Well, curiosity, anyway :) In Perl, there is More then One Way To Do
    It. I'm just looking for that other way.

    Besides, can't I claim that the "sub" adds another layer of
    subroutines, thus hurting the execution time of my script? Well, ok, I
    can claim anything I want - wasn't being serious here.

    It's a bit like trying to be a wizard. Doing it without the 'sub'
    would be very esoteric, very symbol-intense, and way cool - a true
    incantation that only the initiated would ever understand. Of course,
    I'd never use it.... I just want to be *able* to.

    Ok, didn't claim it was important; I get the feeling I'm not going to
    make the "Perl"cut - it's all irrational now :) I've got script that
    works just fine with sub. (Thanks for the help, BTW)

    --Peter
     
    , Sep 28, 2005
    #15
  16. Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > wrote:
    > > wrote:
    > >>3. Is there a way to set $self->{Sub} without using 'sub'?

    > > If you have a Perlish reason for wanting to avoid "sub", and if you tell us
    > > what that reason is, perhaps we can help. If you just have some irrational
    > > aversion to the three letter combination "sub", then I'm afraid that is a
    > > psychological problem, not a Perl problem.

    >
    > Well, curiosity, anyway :) In Perl, there is More then One Way To Do
    > It. I'm just looking for that other way.


    [...]

    > It's a bit like trying to be a wizard. Doing it without the 'sub'
    > would be very esoteric, very symbol-intense, and way cool - a true
    > incantation that only the initiated would ever understand. Of course,
    > I'd never use it.... I just want to be *able* to.


    Apparently you want to generate Perl code without using the Perl
    compiler -- in other words, you want to write a partial Perl compiler
    in Perl. While a full implementation of Perl in Perl might be of
    some theoretical interest, the compilation of a single one-purpose
    subroutine you seem to attempt would accomplish nothing except keep you
    busy for a *long* time. It may be a feat, but it would make you look
    about as wizardly as someone who has cut holes in the floor of a car and
    is pushing it around with their feet. "Look, no engine."

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Sep 28, 2005
    #16
  17. This thread reminds me of a piece of code I've seen recently.

    > I want to pull this effect off:
    >
    >> $self->{Sub} = sub { return $self->Real(@_) };

    >
    > without using 'sub'.


    How about
    $self->{sub} = \&Real;

    and then later call it like that:

    &{self->{sub}}( $self, @something );


    I stared at those lines quite a while and they sure worked. Yet, they still
    seemed at least odd, if not plain wrong.

    To put it differently: Can you emulate a OO closure by using a non-oo closure
    and then simply provide the $self argument yourself?


    Manni
     
    Manni Heumann, Oct 1, 2005
    #17
  18. Lawrence Statton N1GAK/XE2 wrote:

    > Manni Heumann <> writes:
    >>
    >> To put it differently: Can you emulate a OO closure by using a non-oo
    >> closure and then simply provide the $self argument yourself?

    >
    >
    > Well -- consider the following: Would that work with inheritance?
    >
    > Once you 'break' the binding to the class, you have lost the ability
    > to inherit from your class.


    Fair enough; very good point.

    But since I can guarantee that noone will ever inherit from the particular
    class where I've seen this used, can you (or somebody else) provide even more
    good points?
     
    Manni Heumann, Oct 1, 2005
    #18
  19. Joe Smith Guest

    wrote:

    > 3. Is there a way to set $self->{Sub} without using 'sub'?
    >
    > I want to pull this effect off:
    >
    >> $self->{Sub} = sub { return $self->Real(@_) };

    >
    > without using 'sub'.


    Why? A coderef is created using 'sub'. A coderef is executed
    by invoking it as a function. Assuming you could create a coderef
    without 'sub', it would still have to be invoked as a
    subroutine/function to get executed.

    > Besides, can't I claim that the "sub" adds another layer of
    > subroutines, thus hurting the execution time of my script?


    No. You have to go through internal process of pushing things
    onto the call stack to execute the code; so there is no getting
    around that bit of overhead.
    -Joe
     
    Joe Smith, Oct 5, 2005
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jim Schueler

    Tricky AUTOLOAD behavior

    Jim Schueler, Aug 25, 2004, in forum: Perl
    Replies:
    1
    Views:
    441
  2. Replies:
    9
    Views:
    540
    CBFalconer
    Apr 25, 2006
  3. 7stud
    Replies:
    11
    Views:
    700
    Dennis Lee Bieber
    Mar 20, 2007
  4. some tricky questions

    , Jun 2, 2007, in forum: C Programming
    Replies:
    31
    Views:
    1,803
    Army1987
    Jul 2, 2007
  5. Rainer Weikusat

    blessed coderefs

    Rainer Weikusat, Jan 28, 2014, in forum: Perl Misc
    Replies:
    3
    Views:
    99
    Rainer Weikusat
    Jan 30, 2014
Loading...

Share This Page