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

Laudetur, monks.
I began to learn objects in Perl. In my testscript I create a filehandler object. Note: I know that there are proven and comfortable ways to do it, but this is about practicing.
Code:
#!/usr/bin/perl use strict; use warnings; {package MyFilehandler; my $fh; sub openForRead { my $class = shift; my $filename = shift; bless \$filename, $class; open (FH, '<', $filename) or die "could not open file: $!"; $fh = \*FH; } sub writeout { my @lines = <$fh>; print @lines; } } my $testfh = MyFilehandler->openForRead("betvek"); $testfh->writeout;
Error message: #Can't locate object method "writeout" via package "IO::File" at fileobj.pl line 25 (line 25 is  $testfh->writeout; Writeout is right there, same package. This must be a very basic error but I'm stuck for hours. Your help is appreciated.

Replies are listed 'Best First'.
Re: Yet another Can't locate object method question
by choroba (Cardinal) on Mar 15, 2012 at 20:13 UTC
    You constructor (openForRead) returns the last expression evaluated, $fh. But this is an object of a different class - IO::File. You blessed \$filename to your class, not the handle, and you did not return it.

    Moreover, $fh is declared with my in the package. Why? Do you want to keep the same file handle for all the instances of the class? Just create a fresh new reference in the constructor and use idiomatic my $self = shift; in other methods.

      Thank you very much! As for the $fh: silly mistake, I simply have to get accustomed to classes and instances. Thanks again.
Re: Yet another Can't locate object method question
by Khen1950fx (Canon) on Mar 15, 2012 at 21:49 UTC
    I had some fun with this:
    package MyFilehandler; my $fh; sub openForRead { my $class = shift(); my $filename = shift(); bless \$filename, $class; open FH, '<', $filename or die "could not open file: $!"; $fh = \*FH; sub writeOut { my (@lines) = <$fh>; print @lines; }; } close $fh; writeOut( my $testfh = MyFilehandler->openForRead('somefile') );

      You may have had fun, but maintenance programmers or those seeking inspiration or enlightenment would not. Your code contains the same errors that choroba describes, it adds a needlessly nested named sub, a bogus close statement and a nonsensical call to writeOut. The following more conventional code would have served as a simpler and better example:

      #!/usr/bin/perl use strict; use warnings; package MyFilehandler; sub openForRead { my ($class, $file) = @_; my $self = bless {file => $file}, $class; open $self->{fh}, '<', $file or die "could not open '$self->{file} +': $!"; return $self; } sub DESTROY { my ($self) = @_; close $self->{fh}; } sub writeOut { my ($self) = @_; my $fh = $self->{fh}; print <$fh>; } package main; my $testfh = MyFilehandler->openForRead('somefile'); $testfh->writeOut();
      True laziness is hard work
        Thank you for your answer and solution. It works of course, but one thing is not clear to me: $self->{fh} seems to pop out of nowhere. Is it a filehandle which is immediately bound to $self?