[28987] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 231 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Fri Mar 16 11:14:18 2007

Date: Fri, 16 Mar 2007 08:14:11 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Fri, 16 Mar 2007     Volume: 11 Number: 231

Today's topics:
        Scope and Arrays <spiers_andrew@hotmail.com>
    Re: Scope and Arrays anno4000@radom.zrz.tu-berlin.de
    Re: Scope and Arrays <thepoet_nospam@arcor.de>
    Re: Scope and Arrays <spiers_andrew@hotmail.com>
    Re: Scope and Arrays <wahab-mail@gmx.de>
    Re: Scope and Arrays anno4000@radom.zrz.tu-berlin.de
    Re: Scope and Arrays <spiers_andrew@hotmail.com>
    Re: tr/ last char x$ <tadmc@augustmail.com>
    Re: Trouble with a file upload script <john.swilting@wanadoo.fr>
    Re: Use different modules based on variable anno4000@radom.zrz.tu-berlin.de
    Re: what's wrong with this OR statement syntax <tadmc@augustmail.com>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: 16 Mar 2007 05:45:36 -0700
From: "Andrew" <spiers_andrew@hotmail.com>
Subject: Scope and Arrays
Message-Id: <1174049136.666045.69970@d57g2000hsg.googlegroups.com>

If I start with the following code;

use strict;
use warnings;

my $message = "Hello";

displayPrint();

sub displayPrint {

   print "The message is $message.\n";

 }

When I run it, I get the following output;

The message is Hello.

I would like to loop through several messages, so I have changed the
code to;

my $message;
my @messages = ("Hello", "Goodbye");

foreach $message (@messages) {
  displayPrint();
}

sub displayPrint {

  print "My message is $message.\n";

}

Then I get the following error message from the print line;

 "Use of uninitialized value in concatenation (.) or string"

Can someone explain this to me ? From my understanding (obviously
wrong), $message is 'declared' at the start of the code so it should
be available for use within displayPrint.  If I put an extra print
statement inside the foreach loop but before the branch to
displayPrint, the right value is displayed. Why isnt the value of
$message pass into displayPrint ?

Thanks for any help you can give.



------------------------------

Date: 16 Mar 2007 13:19:33 GMT
From: anno4000@radom.zrz.tu-berlin.de
Subject: Re: Scope and Arrays
Message-Id: <55vjr5F25htp7U1@mid.dfncis.de>

Andrew <spiers_andrew@hotmail.com> wrote in comp.lang.perl.misc:
> If I start with the following code;
> 
> use strict;
> use warnings;
> 
> my $message = "Hello";
> 
> displayPrint();
> 
> sub displayPrint {
> 
>    print "The message is $message.\n";
> 
>  }
> 
> When I run it, I get the following output;
> 
> The message is Hello.
> 
> I would like to loop through several messages, so I have changed the
> code to;
> 
> my $message;
> my @messages = ("Hello", "Goodbye");
> 
> foreach $message (@messages) {
>   displayPrint();
> }
> 
> sub displayPrint {
> 
>   print "My message is $message.\n";
> 
> }
> 
> Then I get the following error message from the print line;
> 
>  "Use of uninitialized value in concatenation (.) or string"
> 
> Can someone explain this to me ? From my understanding (obviously
> wrong), $message is 'declared' at the start of the code so it should
> be available for use within displayPrint.  If I put an extra print
> statement inside the foreach loop but before the branch to
> displayPrint, the right value is displayed. Why isnt the value of
> $message pass into displayPrint ?

The variable in "foreach" is implicitly localized, as "perldoc perlsyn"
puts it.  That means, the values from the list are only visible inside
the loop.  Your sub "displayPrint" was compiled outside that scope,
so it doesn't get to see the values.

The actual problem is that your sub relies on a global variable
(the file-globa lexical $message) for its parameter.  Unless there
is a compelling reason, the better practice is to pass the parameter
whith the sub call.  What you are seeing is one of the problems
that can be avoided that way.  Rewrite "displayPrint" as

    sub displayPrint {
        my $message = shift;
        print "My message is $message.\n";
    }

and call it like this

    foreach my $messsage ( @messages ) {
        displayPrint( $message);
    }

or just

    displayPrint( $_) for @messages;

Code untested, but that should work as planned.

Anno


------------------------------

Date: Fri, 16 Mar 2007 14:20:28 +0100
From: Christian Winter <thepoet_nospam@arcor.de>
Subject: Re: Scope and Arrays
Message-Id: <45fa9993$0$6400$9b4e6d93@newsspool2.arcor-online.net>

Andrew wrote:
> If I start with the following code;
> 
> use strict;
> use warnings;
> 
> my $message = "Hello";
> 
> displayPrint();
> 
> sub displayPrint {
> 
>    print "The message is $message.\n";
> 
>  }
> 
> When I run it, I get the following output;
> 
> The message is Hello.
> 
> I would like to loop through several messages, so I have changed the
> code to;
> 
> my $message;
> my @messages = ("Hello", "Goodbye");
> 
> foreach $message (@messages) {
>   displayPrint();
> }
> 
> sub displayPrint {
> 
>   print "My message is $message.\n";
> 
> }
> 
> Then I get the following error message from the print line;
> 
>  "Use of uninitialized value in concatenation (.) or string"
> 
> Can someone explain this to me ? From my understanding (obviously
> wrong), $message is 'declared' at the start of the code so it should
> be available for use within displayPrint.  If I put an extra print
> statement inside the foreach loop but before the branch to
> displayPrint, the right value is displayed. Why isnt the value of
> $message pass into displayPrint ?


foreach() localises the iterator variable. Your loop is equivalent
to the following:

foreach (@messages ) {	# implicit $_ loop iterator
   local $message = $_;
   displayPrint();
}

The localised $message is declared in the loop block's scope, which
isn't visible from the sub that is declared in a different scope.
So the sub still sees the (still undefined) $message from the bigger
scope.

This behaviour is special to foreach and documented in "perldoc
perlsyn".

-Chris


------------------------------

Date: 16 Mar 2007 06:40:21 -0700
From: "Andrew" <spiers_andrew@hotmail.com>
Subject: Re: Scope and Arrays
Message-Id: <1174052421.237814.166020@e65g2000hsc.googlegroups.com>

On Mar 16, 1:19 pm, anno4...@radom.zrz.tu-berlin.de wrote:

> The variable in "foreach" is implicitly localized, as "perldoc perlsyn"
> puts it.  That means, the values from the list are only visible inside
> the loop.  Your sub "displayPrint" was compiled outside that scope,
> so it doesn't get to see the values.
>
> The actual problem is that your sub relies on a global variable
> (the file-globa lexical $message) for its parameter.  Unless there
> is a compelling reason, the better practice is to pass the parameter
> whith the sub call.  What you are seeing is one of the problems
> that can be avoided that way.  Rewrite "displayPrint" as
>
>     sub displayPrint {
>         my $message = shift;
>         print "My message is $message.\n";
>     }
>
> and call it like this
>
>     foreach my $messsage ( @messages ) {
>         displayPrint( $message);
>     }
>
> or just
>
>     displayPrint( $_) for @messages;
>
> Code untested, but that should work as planned.

Anno,

Thanks for the answer. My challenge is that the code I am changing is
not as simple as my example. It has 10 subs within the loop and some
have variables pass in already. For example;

foreach $message (@messages) {
  callSub1;
  callSub2;
  callSub3("param1");
  callSub4;
  ...
}

Now I understand the reason for the code behaving in that way, I can
start to look at the solution.

Regards,

Andrew



------------------------------

Date: Fri, 16 Mar 2007 14:51:36 +0100
From: Mirco Wahab <wahab-mail@gmx.de>
Subject: Re: Scope and Arrays
Message-Id: <ete7ni$1o8$1@mlucom4.urz.uni-halle.de>

Andrew wrote:
> Thanks for the answer. My challenge is that the code I am changing is
> not as simple as my example. It has 10 subs within the loop and some
> have variables pass in already. For example;
> 
> foreach $message (@messages) {
>   callSub1;
>   callSub2;
>   callSub3("param1");
>   callSub4;
>   ...
> }
> 
> Now I understand the reason for the code behaving in that way, I can
> start to look at the solution.

You could make a very simple change then:



  my $message;   # if 'inter package' calls => our $message
  my @messages = ('Hello', 'Goodbye');

  foreach my $actual (@messages) {
    $message = $actual;              # <== here
    callSub1();
    callSub2();
    callSub3('param1');
    callSub4();
  }

  sub callSub1 {  print "1: $message. - @_\n"  }
  sub callSub2 {  print "2: $message. - @_\n"  }
  sub callSub3 {  print "3: $message. - @_\n"  }
  sub callSub4 {  print "4: $message. - @_\n"  }



Regards

M.



------------------------------

Date: 16 Mar 2007 14:05:06 GMT
From: anno4000@radom.zrz.tu-berlin.de
Subject: Re: Scope and Arrays
Message-Id: <55vmgiF26bbmfU1@mid.dfncis.de>

Andrew <spiers_andrew@hotmail.com> wrote in comp.lang.perl.misc:
> On Mar 16, 1:19 pm, anno4...@radom.zrz.tu-berlin.de wrote:
> 
> > The variable in "foreach" is implicitly localized, as "perldoc perlsyn"
> > puts it.  That means, the values from the list are only visible inside
> > the loop.  Your sub "displayPrint" was compiled outside that scope,
> > so it doesn't get to see the values.
> >
> > The actual problem is that your sub relies on a global variable
> > (the file-globa lexical $message) for its parameter.  Unless there
> > is a compelling reason, the better practice is to pass the parameter
> > whith the sub call.  What you are seeing is one of the problems
> > that can be avoided that way.  Rewrite "displayPrint" as
> >
> >     sub displayPrint {
> >         my $message = shift;
> >         print "My message is $message.\n";
> >     }
> >
> > and call it like this
> >
> >     foreach my $messsage ( @messages ) {
> >         displayPrint( $message);
> >     }
> >
> > or just
> >
> >     displayPrint( $_) for @messages;
> >
> > Code untested, but that should work as planned.
> 
> Anno,
> 
> Thanks for the answer. My challenge is that the code I am changing is
> not as simple as my example. It has 10 subs within the loop and some
> have variables pass in already. For example;
>
> foreach $message (@messages) {
>   callSub1;
>   callSub2;
>   callSub3("param1");
>   callSub4;
>   ...
> }
> 
> Now I understand the reason for the code behaving in that way, I can
> start to look at the solution.

Bad design then.  You should refactor the subs to take parameters if
at all possible.

As an intermediate step, you could add a single argument (a hashref)
to all subs, where the hash holds the values of the (former) global
variables.  That should be a straightforward process.  You'd have a
single global hash, say %param, and then the calls become

    foreach $message (@messages) {
      callSub1( \ %param);
      callSub2( \ %param);
      callSub3("param1", \ %param);
      callSub4( \ %param);
      ...
    }

Of course, all subs must be adapted, but that would be the same
rather mechanical process for all of them.  No fun, but doable
and probably worth it.

Anno


------------------------------

Date: 16 Mar 2007 07:06:23 -0700
From: "Andrew" <spiers_andrew@hotmail.com>
Subject: Re: Scope and Arrays
Message-Id: <1174053983.169775.306500@p15g2000hsd.googlegroups.com>

On 16 Mar, 13:51, Mirco Wahab <wahab-m...@gmx.de> wrote:

>
> You could make a very simple change then:
>
>   my $message;   # if 'inter package' calls => our $message
>   my @messages = ('Hello', 'Goodbye');
>
>   foreach my $actual (@messages) {
>     $message = $actual;              # <== here
>     callSub1();
>     callSub2();
>     callSub3('param1');
>     callSub4();
>   }
>
>   sub callSub1 {  print "1: $message. - @_\n"  }
>   sub callSub2 {  print "2: $message. - @_\n"  }
>   sub callSub3 {  print "3: $message. - @_\n"  }
>   sub callSub4 {  print "4: $message. - @_\n"  }
>
> Regards
>
> M.

Thanks for the reply. That was exactly the solution I came up with
myself after reading Annos post.

Thanks for all the help.

Andrew




------------------------------

Date: Fri, 16 Mar 2007 06:18:07 -0500
From: Tad McClellan <tadmc@augustmail.com>
Subject: Re: tr/ last char x$
Message-Id: <slrnevkv7f.afo.tadmc@tadmc30.august.net>

ash <aisling.cronin@gmail.com> wrote:
> I am trying to substitute the last char in each array of strings,
> could some please explain why the tr/ function is not replacing just
> the last char (see below)


Because tr/// does not use regular expressions!


> $ts_roundup[$x]=~ tr/0$1$2$3$4$5$6$7$8$9$a$b$c$d$e$/1$2$3$4$5$6$7$8$9$a
> $b$c$d$e$f$/;


Dollar sign is a regex metacharacter, but since tr does not use
regular expressions, a dollar sign is just a dollar sign.


-- 
    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas


------------------------------

Date: Fri, 16 Mar 2007 14:55:58 +0100
From: "john.swilting" <john.swilting@wanadoo.fr>
Subject: Re: Trouble with a file upload script
Message-Id: <45faa1f2$0$27386$ba4acef3@news.orange.fr>

Mumia W. wrote:

> On 03/15/2007 06:22 AM, Suk wrote:
>> Hi
>> 
>> I am experimenting with a very simple file upload script.
>> 
>> I cannot understand why the script below doesnt work:
>> My web server log shows:
>> 
>> Modification of a read-only value attempted at /var/apache/cgi-bin/
>> uploader.cgi line 94.
>> 
>> Line 94 is:      while ( <$upload_filehandle> )
>> Here is the script.....
>> 
>> #/usr/local/bin/perl
>> #
>> use strict;
>> use CGI qw(:standard);
>> 
>> our $upload_dir = "/tmp";
>> our ($upload_file,$success,$successfully_uploaded,$count);
>> 
>> foreach ("new","outstanding","weekly","year") {
>> 
>>        if (param("$_") ne "") {
>> 
> 
> At this point, $_ is an alias for "new" which is a constant (read-only)
> string.
> 
>>                &upload_and_install("$_");
>>        }
>> }
>> 
>> print header();
>> print <<END_HTML;
>> 
>> <HTML>
>> <HEAD>
>> <TITLE>Thanks!</TITLE>
>> </HEAD>
>> 
>> <BODY>
>> 
>> <P>Thanks for uploading your file</P>
>> 
>> </BODY>
>> </HTML>
>> 
>> END_HTML
>> 
>> sub upload_and_install {
>> 
>>         my ($filename,$upload_filehandle);
>> 
>>         $filename = param($_[0]);
>>         $filename =~ s/.*[\/\\](.*)/$1/;
>>         $upload_filehandle = upload($_[0]);
>> 
>>         open UPLOADFILE, ">$upload_dir/$filename";
>> 
>>         binmode UPLOADFILE;
>> 
>>         while ( <$upload_filehandle> )
> 
> This attepts to put the data read from the file-handle into $_ which is
> aliased to the "new" string above, and since that string is read-only,
> the operation fails.
> 
> To solve this problem, at the top of upload_and_install, put this line:
> 
>      local $_;
> 
> That creates a block-local $_ for you to play with without interfering
> with the for loop's $_.
> 
> Do this to get more information about "local":
> Start->Run->"perldoc -f local"
> 
> This is also an opportunity for you to decide to use named variables
> rather than the default $_, e.g:
> 
> while (my $part = <$upload_filehandle>) {
> ...
> }
> 
> Note, I haven't run your program. My assumption of the error comes from
> a quick perusal of the program.
> 
> 
>>         {
>>           print UPLOADFILE;
>>         }
>> [...]
use CGI::UploadEasy its very nice and simple


------------------------------

Date: 16 Mar 2007 11:32:25 GMT
From: anno4000@radom.zrz.tu-berlin.de
Subject: Re: Use different modules based on variable
Message-Id: <55vdi9F25u459U1@mid.dfncis.de>

 <anno4000@radom.zrz.tu-berlin.de> wrote in comp.lang.perl.misc:
> Uri Guttman  <uri@stemsystems.com> wrote in comp.lang.perl.misc:
> > > 
> > > Prepare two modules Module1.pm and Module2.pm that implement the
> > > different versions of your function(s).  Load both without importing
> > > anything into your namespace.  Then, in your main program, you can
> > > define a function switch_version that imports the necessary functions
> > > at run time.  This is how it might look:
> > > 
> > > The main script:
> > > 
> > >     use Module_1 ();
> > >     use Module_2 ();
> > > 
> > >     sub switch_version {
> > >         my $version = shift;
> > >         my @functions = qw( gick);
> > >         for ( @functions ) {
> > >             no strict 'refs';
> > >             no warnings 'redefine';
> > >             *$_ = \ &{ join '::', "Module_$version", $_ };
> > >         }
> > >     }
> 
> Hey, what happened to your quote indicator? [fixed]
> 
> > that is way to complex IMO for this task. once you have separated the
> > namespaces, it is trivial to handle the different calls with a dispatch
> > table or similar polymorphism:
> > 
> > 	my %chooser = (
> > 
> > 		v1	=> \&Module_1::gick,
> > 		v2	=> \&Module_2::gick,
> > 	) ;
> > 
> > if you need more than 1 function then a multilevel hash is perfect:
> > 
> > 	my %chooser = (
> > 
> > 		v1	=> {
> > 				foo	=> \&Module_1::foo,
> > 				bar	=> \&Module_1::bar,
> > 		},
> > 		v2	=> {
> > 				foo	=> \&Module_2::foo,
> > 				bar	=> \&Module_2::bar,
> > 		},
> > 	) ;
> > 
> > 
> > 	my $vfunc = $chooser{$vers}{$func} or
> > 		die "bad version/func $vers/$func" ;
> > 	$vfunc->() ;
> > 
> > no strict issues, no symbol table hacking, etc.
> 
> Well, the difference is really just whether you assign/reassign to
> lexical coderefs (you) or package typeglobs (me).  Whether you use an
> intermediate hash is immaterial.
> 
> I was going for a solution that does exactly what the OP had in mind:
> Make it behave (for a while) as if "use Module_1" had been run, and
> switch (at runtime) to behave as if it had been "use Module_2".  The
> rest of the code can stay as it is.  Your solution requires changes at
> the call site.  Cleanliness comes at a price :)

Okay... here is a variant that combines the merits of both solutions.
The interface is as the OP described it, so that function calls are
like calls of imported functions.  You'll be happy to see your beloved
dispatch table re-emerge :)

    use Module_1 ();
    use Module_2 ();

    {
        my $version = 'v1';
        sub switch_version { $version = shift }

        my %gick = (
            v1 => \ &Module_1::gick,
            v2 => \ &Module_2::gick,
        );

        my %gack = (
            # ...
        );

        sub gick {
            goto $gick{ $version} || die "invalid version: $version";
        }

        sub gack {
            # ...
        }
    }

    gick;
    switch_version( 'v2');
    gick;

The use of "goto" makes sure that this works correctly even for
caller-sensitive functions.  With just two versions, the symbol
table isn't really necessary.

    goto $version eq 'v1' ? # etc

would have done.

Anno


------------------------------

Date: Fri, 16 Mar 2007 06:21:08 -0500
From: Tad McClellan <tadmc@augustmail.com>
Subject: Re: what's wrong with this OR statement syntax
Message-Id: <slrnevkvd4.afo.tadmc@tadmc30.august.net>

levinepw@yahoo.com <levinepw@yahoo.com> wrote:

> I wanted a shorthand to
>
> my $color='red';
>
> if($color eq 'blue' || $color eq 'red' || $color eq 'green'))
> {
> 	print "cool\n";
> }
>

> simpler way to write the statement.


   if ( grep $color eq $_, 'blue', 'red', 'green' )


-- 
    Tad McClellan                          SGML consulting
    tadmc@augustmail.com                   Perl programming
    Fort Worth, Texas


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

#The Perl-Users Digest is a retransmission of the USENET newsgroup
#comp.lang.perl.misc.  For subscription or unsubscription requests, send
#the single line:
#
#	subscribe perl-users
#or:
#	unsubscribe perl-users
#
#to almanac@ruby.oce.orst.edu.  

NOTE: due to the current flood of worm email banging on ruby, the smtp
server on ruby has been shut off until further notice. 

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

#To request back copies (available for a week or so), send your request
#to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
#where x is the volume number and y is the issue number.

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 231
**************************************


home help back first fref pref prev next nref lref last post