Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Passing a class method

by baxy77bax (Deacon)
on Feb 10, 2018 at 15:22 UTC ( [id://1208899]=perlquestion: print w/replies, xml ) Need Help??

baxy77bax has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have a problem with passing a class method. Let me give an example:

package A; sub new { my $class = shift; return bless {}, $class; } sub _exe { my ($self,$a) = shift; $self->$a->(); # probably wrong !! } package B; use base 'A'; sub new { my $class = shift; return bless {}, $class; } sub _what { my ($self,$y) = shift; ## HERE I would like to pass _print() with $y (let it be a string) ## to package A, method _exe() so that it executes ## _print($y) in B.... Is this possible?? } sub _print { my ($self,$x) = shift; print "$x\n"; }
Question in code (there are probably typos but I just need an example so I can study it).

I could just do :

package B; sub new { my $class = shift; return bless {}, $class; } sub _what { my ($self,$y) = shift; $self->_print($y); } sub _print { my ($self,$x) = shift; print "$x\n"; }
But this is not what I am after. How to do this and what is the most elegant way to share methods between classes if they are not in a classical parent child relationship? (note that B inherits from A but now i need to pass a method and a variable for that method from B to A to be executed by A)

Thank you !

Replies are listed 'Best First'.
Re: Passing a class method
by haukex (Archbishop) on Feb 10, 2018 at 15:35 UTC

    Note that my ($self,$x) = shift; is not correct, it should be my ($self,$x) = @_; instead (several times in your code).

    While it is possible to do what you want (Method Names as Strings), it seems like it might not be a good idea, and instead be the beginning of a bad design pattern - if you could explain why you think you need this and what you want to accomplish, perhaps we can suggest a better approach.

    use warnings; use strict; { package A; sub new { bless {}, shift } sub _exe { my $self = shift; my $meth = shift; $self->$meth(@_); } } { package B; use base 'A'; sub new { bless {}, shift } sub _what { my $self = shift; $self->_exe('_print', @_); } sub _print { my ($self, @args) = @_; print @args, "\n"; } } my $b = B->new; $b->_what("foo","bar"); # prints "foobar"
      First of all thank you for your answer, i get it now. Second, i know about my errors i wrote the post too quickly (in a bit of a time squeeze so read it as a pseudo code) And Third, I am always on a lookout for a better way (especially if there is already a solution ):).

      Genera idea is to have an execution class that checks whether the execution passed to it, is simply a system command or a function or an object method. For example let say I am programming something and i need to execute a cmd but i do not want to know how to handle errors, exceptions etc... so I pass it to a class that executes the cmd and returns me an error/result/warning. But sometimes I do not want to pass a system cmd, I want to implement the command in my own function (with parsing) and still use the same module to check for errors/results/exceptions. Moreover, let say maye I know how to OOp (I don't but...) so I don't have a regular function but my methods are encapsulated/members of my own classes which again I want to pass to this third party module and get errors/warnings etc... back.

      Is there anything like that out there. I surveyed for this for couple weeks not and could not find a universal solution .

        i know about my errors i wrote the post too quickly (in a bit of a time squeeze so read it as a pseudo code)

        If you're in a hurry, the best way to get quick answers is to post well-formed questions. Forcing others to fix irrelevant errors in your code can make people less willing to help.

        Anyway, I am about 80% sure I understood what you want to do :-) It sounds like the situation you are describing would probably be appropriate for dynamic method calls, but what is still a bit unclear is how you want to handle errors. I think this is relevant for two reasons: First, different functions/methods will throw errors differently - some return undef, some return a negative number, some die, system commands usually return 0 on success, etc. Second, personally I think that in many cases, the best place to handle errors is on the outermost layer of the program, instead of somewhere deep inside several layers - I have seen overuse of try/catch to suppress relevant errors too often. And you might want to consider that designing a new general dispatch mechanism is not something you want to do in a time squeeze, perhaps it's better to reach for existing tools.

        If you are looking for a general exception handling mechanism, a place to start might be Try::Tiny.

        If by "system command" you mean external programs, then there are several modules to do that with, one of them is my own IPC::Run3::Shell. You can even inherit from IPC::Run3::Shell::Autoload, here's an example where cat is implemented by a method in the package, and any other method calls are autoloaded and turned into system commands, for example the method tac calls the external program tac:

        #!/usr/bin/env perl use warnings; use strict; use IPC::Run3::Shell ':FATAL'; use Try::Tiny; { package Runner; BEGIN { our @ISA = ('IPC::Run3::Shell::Autoload') }; sub new { bless {}, shift }; sub cat { my ($self,$filename) = @_; open my $fh, '<', $filename or die "cat $filename: $!"; while (<$fh>) { print "cat: $_"; } close $fh; } } my $r = Runner->new; $r->cat('/tmp/test.txt'); $r->tac('/tmp/test.txt'); try { $r->cat('/tmp/notexist'); } catch { warn "Failed: $_"; }; try { $r->tac('/tmp/notexist'); } catch { warn "Failed: $_"; }; __END__ cat: Foo cat: Bar cat: Quz Quz Bar Foo Failed: cat /tmp/notexist: No such file or directory at shell.pl line +13. tac: failed to open ‘/tmp/notexist’ for reading: No such file or direc +tory Failed: Command "tac" failed: exit status 1 at shell.pl line 31.
Re: Passing a class method
by karlgoethebier (Abbot) on Feb 10, 2018 at 15:49 UTC

    BTW, my ($self, $y) = shift; isn't a typo, it is wrong IMHO. It should be my ($self, $y) = @_; - if this is what you meant.

    See also shift and perlsub.

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1208899]
Approved by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (6)
As of 2024-04-19 08:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found