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

To learn Perl classes I start reading perlootut Perl 5 version 22.0 documentation. In that I saw this example. As per my understanding the  new works like constructor.

#!/usr/bin/perl use strict; use warnings; package File; my $hostname = File->new( path => '/etc/hostname', content => "foo\n", last_mod_time => 1304974868, ); use Scalar::Util 'blessed'; #print blessed($hash); # undef print blessed($hostname); # File

I wrote this from the example of the documentation. But its showing an error like  Can't locate object method "new" via package "File" at package.pl line 9. Whats the problem in this???

Replies are listed 'Best First'.
Re: Learning classes in Perl
by 1nickt (Canon) on Feb 19, 2016 at 04:09 UTC

    Hi ravi45722

    You are a little mixed up; you've copied code snippets meant to illustrate different things and patched them together, but the result doesn't make sense.

    Your package will contain the constructor sub new() and your script that uses the package will call new() to create an instance of the object.

    Also, even though that tutorial shows package 'File' as an example, it's customary to avoid single-word package names unless they are distinctive; you would be safer with either MyFile or My::File.

    Update in response to OP's reply:

    Are you sure you're ready to tackle OOP in Perl? Have you already become familiar with packages in general? Here's a simple example of a package in a module and a script that uses it, download it and try it out:

    # DayPredict.pm # maps moods to predictions package DayPredict; use strict; use warnings; sub predict { my $mood = shift; if ( $mood eq 'happy' ) { return 'be great'; } elsif ( $mood eq 'sad' ) { return 'get better'; } else { return; # didn't get a mood so return undef } } 1; # module must return a true value
    #!/usr/bin/perl # predict_day.pl # Tells what sort of day you will have based on your mood use strict; use warnings; use feature 'say'; use DayPredict; my $mood = $ARGV[0] or die "no mood!"; my $prediction = DayPredict::predict( $mood ); if ( $prediction ) { say 'Your day will ' . $prediction . ', do not worry.'; } else { say 'Cannot read your mood so unable to predict your day.'; } __END__
    Usage:
    $ perl predict_day.pl happy

    Now if you wanted to do the same thing with OOP, making an object for your day, you might do something like this:

    # MyDay.pm # Interface to objects representing days package MyDay; use strict; use warnings; sub new { # This is boilerplate code you can copy. # But you'd be better off with a module so you don't have to do it + by hand. # Check out Class::Tiny or Moo my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; bless ($self, $class); return $self; } sub mood { my $self = shift; # If there's an argument provided, set the value, # then in either case, return the current value. if ( @_ ) { $self->{'mood'} = shift; } return $self->{'mood'}; } sub predict { my $self = shift; my $prediction; # Get the mood by calling the mood() method on your object # ... referred to as $self here while you're inside it if ( $self->mood eq 'happy' ) { $prediction = 'be great'; } elsif ( $self->mood eq 'sad' ) { $prediction = 'get better'; } return $prediction; # undef if no mood } 1; # module must return a true value
    #!/usr/bin/perl use strict; use warnings; use feature 'say'; # my_day.pl - predicts your day based on your mood use MyDay; my $mood = $ARGV[0] or die "no mood!"; my $day = MyDay->new; # construct a new object $day->mood( $mood ); # set the value of the object attribute # based on this script's argument my $prediction = $day->predict; # call the predict() method on the obj +ect, # which contains your mood stored with +in it. if ( $prediction ) { say 'Your day will ' . $prediction . ', do not worry.'; } else { say 'Cannot read your mood so unable to predict your day.'; } __END__
    Usage:
    $ perl my_day.pl sad
    Hope this is a little clearer now!

    Update: Changed 'package must return a true value' to 'module must return a true value', thanks Discipulus.


    The way forward always starts with a minimal test.

      (This is answer is not intended for the OP, as it will no doubt be over his head...)

      To be computer-linguistically pedantic, new is not a constructor, but a factory class method. That is, it's a class method (which in perl means it is invoked with the class name passed as the first argument, rather than an object reference[1]); and it is a factory method, meaning its purpose is to return objects which probably[2] didn't exist prior to the call. POOP does not have constructors. (I can't speak for any other OO frameworks for perl; one or more of them may support something closer to a classical constructor.)

      [1] Of course, there are always exceptions. This is Perl, after all. If the sub is written appropriately, it can be both a class method and an object method. Or both of those *plus* support non-method invocation syntax. CGI commits this bletchery, for example.

      [2] Of course, there are always exceptions. For example, one common pattern is for the factory method of a class to return the same instance always -- the "singleton".

      One consequence of these factoids is that there is nothing inherently special about "new". Using that as the name of the factory method is mere convention. Another consequence is that any method can be a factory method, if it's written to be one. There are no limitations.

      I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.

        To be computer-linguistically pedantic, new is not a constructor, but a factory class method.

        Meh, if you use it exactly like a constructor, its a constructor I tells ya

      To be frank I don't understand what you said. I am very new to this OOP concept. Please guide to rectify that error. I am taking that example from the  http://perldoc.perl.org/ But still it showing error. I dont understand why?? I am in right side to learn OOP ????

        perlobj should explain this for you.

        #!/usr/bin/perl use strict; use warnings; package MyFile; sub new { my ($class,%args) = @_; my $self = { %args }; bless $self,$class; return $self; } sub print_args { my $self = shift; for (sort keys %$self){ print "$_ = $self->{$_}\n"; } } package main; # create new object my $hostname = MyFile->new( path => '/etc/hostname', content => "foo\n", last_mod_time => 1304974868, ); # call method on object $hostname->print_args();
        poj
Re: Learning classes in Perl
by soonix (Chancellor) on Feb 19, 2016 at 09:39 UTC
    Well, basically the error message tries to tell you that you forgot to define your package's constructor. You can name your constructors as you like, naming it new is a mere convention. And it is missing something like
    sub new { return bless {}, __PACKAGE__; }
    Of course, you could name your constructors differently, e.g. after defining
    sub File { return bless {}, 'File'; }
    you would use File->File instead of File->new.
Re: Learning classes in Perl
by GotToBTru (Prior) on Feb 19, 2016 at 13:08 UTC

    The constructor is not automatically created for you, which is why Perl complains it can't locate the method 'new'. Doing OO in Perl is kind of clunky, which is why most people like to use packages like Moose or Moo or any one of several others. Many of them do things like automatically creating constructors, getters and setters, and handling alot of the overhead issues for you.

    This comes with a cost of added complexity, but if you're really going to code OO in Perl, it is worth your time to invest in learning. You will get that time back multiplied many times in coding and maintenance.

    But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

Re: Learning classes in Perl
by perlfan (Parson) on Feb 22, 2016 at 16:33 UTC
    Object Oriented Perl by Damian Conway is an excellent introduction, not only to OOP in Perl, but to the little features and tricks that make it possible. It will help you in many areas of Perl, not just OOP.

    And while a little dated, there is no modern equivalent.

      I second this recommendation with the caveat that the book has some advice that I would consider misplaced (like the inside-out stuff) and none of the advanced OO frameworks in Perl existed when it was written. This means a lot of the otherwise excellent code suggestions are (probably) moot for most applications. The enduring strength of the book for me was that it taught me how to think about complicated programming tasks in a much more sophisticated way than I'd been managing on my own and showed me why some of the critique/FUD of the so called "bolt-on" OO in Perl is unfounded.

Re: Learning classes in Perl
by zenadu (Initiate) on Feb 24, 2016 at 19:35 UTC

    Hi ravi45722,

    Ignoring the illicit nature of the example, this code is about as basic an example of a complete object oriented implementation from scratch in Perl as I have ever seen.

    I have taken it from the blog post at <link removed because it was an unapproved site or something>.

    Edit: Should have also mentioned, don't even think of doing OO from scratch in perl until after you have completely read at least perlootut, perlreftut, and perlref and have a good handle on hashes and references. If you don't have a good handle on hashes, read perldata completely. After that, OO in perl is actually pretty straight forward and nowhere near as nightmarish or hackish as some suggest. Also if you're not going to read the whole thing, at least keep a copy of perlobj around for reference as perlootut mainly only covers doing OO perl using class builders which do the boilerplate of constructors and accessors for you.
    #!/usr/bin/perl -w # # plants.pl # A CLI to the medicinal plants database. # (C) 2016 Mischa Capazario v.0.1 Tue Feb 23 17:32:19 SAST 2016 # use lib "Plants/"; use Salvia; use strict; &main(); sub main { if( defined $ARGV[0] ) { if ( $ARGV[0] eq 'add' || $ARGV[0] eq 'update' ) { &addStrain(); exit; } elsif ( $ARGV[0] eq 'show' ) { &showStrain(); exit; } elsif ( $ARGV[0] eq 'remove' ) { &removeStrain(); exit; } else { &showHelp("Valid argument expected"); exit; } } else { &showHelp("Valid argument expected"); exit; } } sub addStrain { my $Salvia = Salvia->new(); my $Strain = $ARGV[1] or &showHelp("Valid argument expected"); $Salvia->{'Name'} = $Strain; $Salvia->{$Strain}->{'THC'} = $ARGV[2] or &showHelp("Valid + argument expected"); $Salvia->{$Strain}->{'CBD'} = $ARGV[3] or &showHelp("Valid + argument expected"); $Salvia->{$Strain}->{'THCV'} = $ARGV[4] or &showHelp("Vali +d argument expected"); $Salvia->{$Strain}->{'Verified'} = $ARGV[5] or &showHelp("Vali +d argument expected"); $Salvia->{$Strain}->{'Description'} = $ARGV[6] || undef; $Salvia->add($Salvia); return; } sub showStrain { my $Salvia = Salvia->new(); my $Strain = $ARGV[1]; # or &showHelp("Valid arguments expected"); if ( defined $Strain ) { print "Strain: $Strain\n"; my $StrainHash = $Salvia->get($Strain); die "Strain not found. You can add it with $0 add" unless $Str +ainHash; foreach my $key (sort keys %{$StrainHash} ) { print " $key: $StrainHash->{$key} "; } print "\n"; } else { my $StrainsHash = $Salvia->get(); print "Strains: \n"; foreach my $strain (sort keys %{$StrainsHash} ) { print " $strain "; } print "\n\nRun $0 show for more details.\n"; } } sub removeStrain { my $Salvia = Salvia->new(); my $Strain = $ARGV[1] or &showHelp("Valid arguments expected"); $Salvia->delete($Strain); } sub showHelp { my $msg = shift ||''; die <<EOH $0: $msg Help: $0 add <STRAIN> <THC Value> <CBD Value> <THCV Value> <Verified (yes/no +)> \t\t - Add new herbs strain, <STRAIN>. Specify cannabi +noid \t\t\t values as numbers between 1 and 5. $0 update <STRAIN> <THC Value> <CBD Value> <THCV Value> <Verified (yes +/no)> \t\t - Update herbs strain, <STRAIN>. $0 show \t - Show list of strains $0 show <STRAIN>\t - Show information on <Strain> $0 remove <STRAIN>\t - Remove <Strain> EOH }
    #!/usr/bin/perl -w # # Salvia.pm # Class definition for Salvia object # (C) 2016 Mischa Capazario v.0.1 Tue Feb 23 16:54:06 SAST 2016 # use MLDBM qw(DB_File Storable); use Fcntl; package Salvia; my $dataFile = qq|Plants/Salvia.bdb|; sub new { my $self = shift; return bless {}, $self; } sub add { my $self = shift; my $Strain = shift; return $self->update($Strain); } sub get { my $self = shift; my $Strain = shift; my %Salvia; my $dbm = tie %Salvia, 'MLDBM', $dataFile or die $!; undef $dbm; if( defined $Strain ) { if ( defined $Salvia{$Strain} ) { return \%{$Salvia{$Strain}}; } } else { return \%Salvia; } } sub update { my $self = shift; my $Strain = shift; my %Salvia; my $dbm = tie %Salvia, 'MLDBM', $dataFile or die $!; my $strain = $Strain->{'Name'}; $Salvia{$strain} = $Strain->{$strain}; undef $dbm; untie %Salvia; return %Salvia; } sub delete { my $self = shift; my $Strain = shift; my %Salvia; my $dbm = tie %Salvia, 'MLDBM', $dataFile or die $!; delete($Salvia{$Strain}); undef $dbm; untie %Salvia; return; } 1;