Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Functions in Perl

by bluethundr (Pilgrim)
on May 23, 2004 at 00:13 UTC ( #355665=perlquestion: print w/replies, xml ) Need Help??
bluethundr has asked for the wisdom of the Perl Monks concerning the following question:

Hey guys,

I just learned how to treat functions in Perl using Laura Lemay's "Perl In 21 Days" by Sams. The question was on p.272 of that tome and exercise one states:

Write a subroutine that does nothing but print its arguments, one argument per line, with each line numbered.

Now some clarification: Lemay's attitude is that if it is an imported function or one that is part of perl itself one refers to it as a "function". If it is one that you write yourself, it's what she refers to as a "subroutine". This was just her writing style, and says that one can refer to them as either and you'll still be right from a comp sci. standpoint.

I do plan on getting merlyn's book (as has been suggested) as well as the O'Reilly one by St. Wall. But in the meantime I am getting my toes wet with Lemay's book. One step at a time, eh?

Well anyway, here is how I approached the problem. I hope you goes don't mind me asking this everytime I give myself an assignment! But I would love to see how a more experienced programmer would do things. I am still studying my earlier thread, btw which generated and INCREDIBLE response for which I am grateful. Here goes:
#!/usr/bin/perl -w &initarg; while ($i !~ /stop/i) { # hey! all I could think of! :) printf("Please enter phrase number %d : ", $count+1); # here's +where knowing some c has helped me chomp ($i = <STDIN>); $phr[$count] = $i; $count++; } &printarg(@phr); sub printarg { my $count = 1; foreach $i (@_) { print "Phrase number $count : $i\n"; $count++; } } sub initarg { @phr = (); # the author suggests initializing variables to null $i = ""; # done yet? $count = 0; # number of the phrase }

Now I know that I may have separated some things out into their own functions that maybe I shouldn't have. That's the sort of thing I would love to recieve criticism on. Also, I got some feedback on one of my earlier posts that I should use 'strict', etc. I totally agree with that viewpoint! But I haven't "book learned" these concepts yet! I'm sure I'll get to them eventually. But at my toddler's level on perlness at the moment, I think I can afford to leave certain things till later when I learn about them.


Replies are listed 'Best First'.
Re: Functions in Perl
by eyepopslikeamosquito (Chancellor) on May 23, 2004 at 02:14 UTC
    Just a few general style comments. First, get into the habit of starting your programs with:
    use strict;
    at least until you understand when not to use it. I have not seen Lemay's book, but I trust it has a good explanation of use strict -- if not, discard it immediately. Second, drop the awful Perl-4 style:
    function calling syntax and use the modern style:
    Third, lexicals are good. So replace:
    foreach $i (@_) {
    foreach my $i (@_) {
    Again, I trust Lemay describes why lexicals should generally be preferred to globals. Like the others, I recommend switching to learning perl. See merlyn's blog entry for an interesting example of a Perl beginner learning Perl in public from merlyn's excellent introductory work.
      Interesting. Thanks! This is all good stuff! And I respect what merlyn has to say. Tremendously so! But don't particularly agree with that blog entry you pointed me to.

      But again, I value your input.
        I don't think he meant to imply it was in any way self-demeaning to publicize one's learning process, simply that it was interesting that someone would take the time to document and publish that experience on the net. Although, in regard to blog entries, that's actually pretty common.

        Roses are red, violets are blue. All my base, are belong to you.
Re: Functions in Perl
by rjray (Chaplain) on May 23, 2004 at 00:22 UTC

    In the general sense, yes, your solution to the exercise is correct and functional. Many would suggest various tweaks and adjustments for the sake of clarity and/or efficiency, but overall it's good, and as a beginner you seem to be on a good track.

    However, I would recommend moving to Learning Perl sooner rather than later. I have nothing against Laura Lemay, but most of the "Learn * in 21 Days" books focus too little on understanding the core topic itself, and leave the reader with limited ability to adapt and improvise.


      Thanks man! I fully plan on reading that book! Everyone's been recommending it to me everywhere I turn! I generally trust O'Reilly's offerings to begin with. But I figure, it can't exactly hurt to finish the book I'm already half way through! Also generally speaking I tend to like to get my feet wet with a Sams 21 Days book and reinforce what I learned through more credible resources. That's how I did it with C++ at any rate, and I had some success there. So I decided that I am going to follow that formula again with Perl.

      Also, I I've found that writers inevitably see the same things in different ways. Obviously, one can never duplicate the exact experience or point of view of another human being! And I find that reading the exact same topic matter, covered from inevitably differing perspectives, has been immeasurably advantageous as a learning strategy.
Re: Functions in Perl
by TomDLux (Vicar) on May 23, 2004 at 04:20 UTC

    Modern practice is to make variables as local as possible. Creating a routine to initialize global variables is totally contrary to modern practice. As much as possible, functions/routines should only manipulate data and variables they recieve as arguments. As well, initializing an array to an empty array is pointless, as is initializing a strting to an empty string, or an integer to zero ... they are all created witht he value undef, which in many situations has the effect you assign explicitly. Admittedly, in certain odd situations, it becomes essential to assign a value to avoid pointless warning messages, but assigning routine intial values is a C practice, made obsolete by C++, Java and Perl.

    As far as your printarg is concerned, it looks fine to me. However (You knew there was a however coming, didn't you?) the instructions only say to number the args, no comment about starting at zero or one or 17425. I would use that to my advantage to use the automatic numbering system of an array:

    for my $idx ( 0..$#_ ) { # $#_ is index of last element, # scalar @_ is number of elements print "$idx $_[$idx]\n"; # or to start numbering at one print $idx+1 . " $_[$idx]\n" }

    I was quick to learn $#array, took me a lot longer to learn 'scalar @array .... both are useful.



Re: Functions in Perl
by Fletch (Chancellor) on May 23, 2004 at 01:15 UTC

    Unless you specifically need to format numbers to a particular number of decimal places or do zero-filling, using printf rather than just print (or even just interpolating into a double quoted string for that matter) is unnecessary (and makes you look like a C programmer :). You also will add the end token "stop" to your list. Consider using the more idiomatic while( <STDIN> ) { chomp; last if /^stop$/i; ... } instead.

    You also might want to take a look at perltidy for a bit more idiomatic (and consistent) indentation. Not that this is python, but you're all over there with four, three, and zero spaces.

Re: Functions in Perl
by Cody Pendant (Prior) on May 23, 2004 at 05:57 UTC

    I just wanted to post that I believe you've interpreted the author's request incorrectly, or rather you've done way too much work!

    The way I interpret it, she just wants you to write a sub such that, given subRoutine('foo','bar','baz','quux') it prints out

    1 foo 2 bar 3 baz 4 quux

    =~y~b-v~a-z~s; print

      I know it is obvious but the OP might learn something from it:

      sub args { print "$_\n" for @_ } args( qw( Perl is fun ) );
Re: Functions in Perl
by eric256 (Parson) on May 23, 2004 at 05:43 UTC

    This incorporates a bit from the others and a bit of my own. :) Normaly I would shove the prompt into a sub of its own and use it as the condition for the while loop, but here i went with the simpler way! I came from C too although I started with ++ so I had streams for input output instead of printf.

    use strict; use warnings; my @phrases = (); my $i = 1; print "Please enter phrase number " . $i++ . " (or 'stop'): "; while (<STDIN>) { chomp; last if /^stop$/; #only if they put just the word stop print "Please enter phrase number " . $i++ . " (or 'stop'): "; push @phrases, $_; } printphrases(@phrases); sub printphrases { my $i = 1; print $i++ . ") $_\n" foreach @_; } __DATA__ C:\test>perl Please enter phrase number 1 (or 'stop'): hello world Please enter phrase number 2 (or 'stop'): this is fun Please enter phrase number 3 (or 'stop'): cool Please enter phrase number 4 (or 'stop'): dude! Please enter phrase number 5 (or 'stop'): stop 1) hello world 2) this is fun 3) cool 4) dude!

    Eric Hodges
Re: Functions in Perl
by dash2 (Hermit) on May 23, 2004 at 22:02 UTC
    One advantage (and sometimes, drawback) of Perl is that you can do things fast.

    sub showargs{ print map {"$_ $_[$_]\n"} 0..$#_}

    Doing things fast often leads to code that other people can't read. So don't assume this is good practice. But it's fun, and for a throwaway script it's acceptable.

    An explanation:

    map {code} @array runs code on every element of an array, just like a foreach loop. Inside the code block, each element of the array is aliased to $_.

    0..$#array creates a list going from 0, to the index of the last element in @array. So 0..$#_ goes from 0 to the last element in @_, which is your array of arguments.

    Finally, "$_ $_[$_]" prints first the aliased element, then the corresponding member of @_.

    I'm sure some other monks can get this faster (and more obscure....)

    A massive flamewar beneath your chosen depth has not been shown here
Re: Functions in Perl
by Gunth (Scribe) on May 23, 2004 at 14:01 UTC
    Also, an example like this is very suitable for an Object Oriented application. For example:
    #!/usr/bin/perl use strict; use warnings; my $example = Example->new; $example->print( map { chomp $_; $_; } <STDIN> ); $example->print('That\'s all!'); sub Example::new { my ($class, $start_num) = @_; bless \$start_num, $class; } sub Example::print { my $self = shift; print ++$$self, ": $_\n" for @_; }
      Yikes! OOP is overkill here. This is all you need:
      sub printargs { my $i = 1; printf "%d %s\n", $i++, $_ foreach @_; }

        That doesn't do what Gunth's OO code does. His code makes an object that holds the counter that keeps increasing for every call to &print. So the second time it continues where it stopped the first time. Your code has the equivalent result of throwing away the object after each use, i.e. Example::->new->(...).

        My closure example below shows the equivalent of the OO example.


      Or this can be a good example of a closure

      my $printer = do { my $c; sub { print ++$c, ": $_\n" for @_; } }; $printer->(@stuff_to_print); $printer->(@more);


Re: Functions in Perl
by chanio (Priest) on May 24, 2004 at 01:59 UTC
    Some good things to do to aknowledge your best subs structure:
    • Even though you won't frequently see here all the examples subs well docummented at the begining of them, I have noticed that every good programmer does it. Here it is assumed that most of the readers know most of the code exposed. So any further explanation is needless. But self documenting the subs helps a lot so that you could order your mind before writing every subrutine. You could specify: what does the following sub do, what are the arguments that it receives, and what are the variables that it returns. Some times, just by writing this part I change a lot of what the sub is going to do.
    • After you have proved that your script is working fine, you could try adding some different aproaches on the same code. Sometimes, by changing these concepts, you finish restructuring all your subroutines. After trying several times the same code with different changes (say, optimizing your code for different situations, or users, or needs) you surely reach to a perfect idea of what each subroutine should do, and what shouldn't.
    Hope that this helps!

    _`(___)' __________________________

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://355665]
Approved by blue_cowdawg
Front-paged by jonnyfolk
[LanX]: good
[LanX]: ;-p
[Eily]: good mere part of the day to you too
[karlgoethebier]: good #metoo

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (8)
As of 2018-02-20 10:42 GMT
Find Nodes?
    Voting Booth?
    When it is dark outside I am happiest to see ...

    Results (269 votes). Check out past polls.