lecture
in color
global scope and
unlimited lifetime (like in old-style BASIC!).
$i in a subroutine,
its value persists in global scope.
my
our
local
bless.
main'
package foo; $bar = 1;defines a variable
$foo::bar (package foo,
variable bar).
package foo;
sub strate {
$name = shift;
open(FILE, "<$name") or die "can't open $name: $!";
@content = (<FILE>);
close FILE;
return $content[0];
}
&strate('foo');
defines:
&foo::strate a function.
$foo::name a scalar.
$foo::FILE a filehandle.
@foo::content an array.
main::.
undef is 0.
undef is ''.
my $var; - lexical scoping and lifetime, local to a block,
{...}, automatically destroyed upon block exit.
our $var; - lexical scoping within a file, available
to all packages within the file, sort of a "localized global variable".
local $var; - dynamic scoping, block lifetime,
local to a block, automatically destroyed at block exit,
available to subroutines called within its scope as a global
variable. Package-sensitive; declarations can contain package name,
even a different package from the current one!
e.g. local $foo::debug;
my $var;our:
scope is whole file.
my: localizing variables to avoid
naming conflicts.
contents of perl_decl/my1.pl...
#! /var/local/couch/bin/perl
sub scriber {
my ($name,$value) = @_;
print "pay $name \$$value immediately\n";
}
&scriber('Couch', 20);
print "name=$name\n";
sub verted {
($name,$value) = @_;
print "pay $name \$$value immediately\n";
}
&verted('Couch', 20);
print "name=$name\n";
...end of perl_decl/my1.pl
This prints:
contents of perl_decl/my1.pl.out... pay Couch $20 immediately name= pay Couch $20 immediately name=Couch ...end of perl_decl/my1.pl.outThe
my declarations keep the subroutine arguments
from cluttering up global variable space.
my variables
are passed to subroutines:
contents of perl_decl/my2.pl...
#! /var/local/couch/bin/perl
{
my $var = "hi there";
sub stitute {
$var .= shift;
print "var=$var\n";
}
}
&stitute(" person");
&stitute(", how are you?");
print "var=$var\n";
...end of perl_decl/my2.pl
This prints:
contents of perl_decl/my2.pl.out... var=hi there person var=hi there person, how are you? var= ...end of perl_decl/my2.pl.outThe
my declaration defines a variable that acts like a global
variable for subroutines declared within its scope. So
this construction declares a static local variable for the subroutine!
our $var;my, whose
scope is always local to some block).
contents of perl_decl/our1.pl...
#! /var/local/couch/bin/perl
$name = "foo";
print "before our, name=$name\n";
package Foo;
print "before our, in Foo, name=$name\n";
package main;
{
our $name = "Couch";
print "inside block, name=$name\n";
}
print "outside block, name=$name\n";
package Foo;
print "in package Foo, name=$name\n";
sub verted {
print "in subroutine verted, name=$name\n";
}
&verted;
package main;
print "back in package main, name=$name\n";
...end of perl_decl/our1.pl
contents of perl_decl/our1.pl.out... before our, name=foo before our, in Foo, name= inside block, name=Couch outside block, name=Couch in package Foo, name= in subroutine verted, name= back in package main, name=Couch ...end of perl_decl/our1.pl.outThe variable isn't visible inside
package Foo but remains
visible when we hop back to package Main.
local $var;contents of perl_decl/local1.pl...
#! /var/local/couch/bin/perl
$debug = undef;
{ &debug ("hi there\n"); # this doesn't print
{ local $debug = 1;
&debug ("ho there\n"); # this does print
}
&tle;
&debug ("hello, hello, hello (hello)\n"); # this doesn't print
}
sub tle {
local $debug = 1; # shadows global declaration
&debug ("gripe gripe gripe...\n"); # this does print
}
sub debug {
printf @_ if $debug;
}
...end of perl_decl/local1.pl
This prints:
contents of perl_decl/local1.pl.out... ho there gripe gripe gripe... ...end of perl_decl/local1.pl.outThis is a typical use of
local: to temporarily override
a global default.
main)
was implicit. We could make it explicit as follows:
contents of perl_decl/local2.pl...
#! /var/local/couch/bin/perl
$main::debug = undef;
{ &main::debug ("hi there\n"); # this doesn't print
{ local $main::debug = 1;
&main::debug ("ho there\n"); # this does print
}
&main::tle;
&main::debug ("hello, hello, hello (hello)\n"); # this doesn't print
}
sub main::tle {
local $main::debug = 1; # shadows global declaration
&debug ("gripe gripe gripe...\n"); # this does print
}
sub main::debug {
printf @_ if $main::debug;
}
...end of perl_decl/local2.pl
contents of perl_decl/shadow.pl...
#! /var/local/couch/bin/perl
# shadowing demonstration
$foo = 'manny';
print "on outside, foo=$foo\n";
{
my $foo = 'moe';
}
sub version {
print "in version, foo=$foo\n";
local $foo = 'jack';
print "in version, foo=$foo\n";
&ject;
}
sub ject {
print "in ject, foo=$foo\n";
}
&version;
&ject;
print "on outside, foo=$foo\n";
...end of perl_decl/shadow.pl
contents of perl_decl/shadow.pl.out... on outside, foo=manny in version, foo=manny in version, foo=jack in ject, foo=jack in ject, foo=manny on outside, foo=manny ...end of perl_decl/shadow.pl.out
contents of perl_decl/scope1.pl...
#! /var/local/couch/bin/perl
# examples of scoping
sub checkit {
if (defined $i) {
print "inside checkit, \$i is $i\n";
} else {
print "inside checkit, \$i is undefined\n";
}
}
# my declaration inside a block limits $i to that block
print "\ntest \$i in STATIC scope\n";
{ my $i = 7;
if (defined $i) {
print "inside block \$i is $i\n";
} else {
print "inside block \$i is undefined\n";
}
&checkit;
}
if (defined $i) {
print "outside block \$i=$i\n";
} else {
print "outside block \$i is undefined\n";
}
# local declaration inside a block limits $i to that block
# and subroutines invoked in that block.
print "\ntest \$i in DYNAMIC scope\n";
{ local $i = 21;
if (defined $i) {
print "inside block \$i is $i\n";
} else {
print "inside block \$i is undefined\n";
}
&checkit;
}
if (defined $i) {
print "outside block \$i=$i\n";
} else {
print "outside block \$i is undefined\n";
}
# if no declaration, $i is global.
print "\ntest \$i in GLOBAL scope\n";
{ $i = 42;
if (defined $i) {
print "inside block \$i is $i\n";
} else {
print "inside block \$i is undefined\n";
}
&checkit;
}
if (defined $i) {
print "outside block \$i is $i\n";
} else {
print "outside block \$i is undefined\n";
}
...end of perl_decl/scope1.pl
contents of perl_decl/scope1.pl.out... test $i in STATIC scope inside block $i is 7 inside checkit, $i is undefined outside block $i is undefined test $i in DYNAMIC scope inside block $i is 21 inside checkit, $i is 21 outside block $i is undefined test $i in GLOBAL scope inside block $i is 42 inside checkit, $i is 42 outside block $i is 42 ...end of perl_decl/scope1.pl.out
my' whenever possible.
our' to declare global variables
that are local to packages and whose lifetime is all of execution.
local' sparingly and when justified;
main use is to temporarily override a global default.
(it is quite difficult to justify it, and cases are very rare).
use strict& on function calls.
use strict causes the language to
become "more demanding":
our or
referred to by their full names (package::var).
my.
use strict; no strict "refs";
strict "refs" in effect.
sub pi { 3.1415929 }
sub pies { 20 }
sub flavor { 'lemon merangue' }
declares some numeric and string constants &pi,
&pies, and &flavor, with
appropriate values.
$p = &pies * 40;as
$p = 800;during compilation, i.e., before actual execution.
sub (proto) {
...
}
\, to wit:
$: a scalar (including all predefined references).
\$: a scalar variable that will automatically be
converted to a reference during the invocation (and is not
a reference within the argument list).
@ : an array (must be last).
\@: an array variable that will automatically be
converted to a reference.
% :a hash table (must be last).
\%: a hash variable that will automatically be
converted to a reference.
* : a typeglob, filehandle, or other type.
& : a function or function block.
contents of perl_decl/proto1.pl...
#! /var/local/couch/bin/perl
sub printAddr (\@$$) {
my ($addr,$name,$phone) = @_;
print "name=$name\n";
print "phone=$phone\n";
print "addr=@$addr\n";
}
@addr = ('1600 Pennsylvania Ave', 'Washington', 'DC');
# invoke prototype
printAddr @addr, 'George Bush', '555-1212';
# override prototype
&printAddr(@addr,'George Bush', '555-1212');
...end of perl_decl/proto1.pl
contents of perl_decl/proto1.pl.out... name=George Bush phone=555-1212 addr=1600 Pennsylvania Ave Washington DC name=Washington phone=DC addr= ...end of perl_decl/proto1.pl.out
$addr is set to \@addr from outside,
so its value is ['1600 Pennsylvania Ave', 'Washington', 'DC'].
('1600 Pennsylvania Ave', 'Washington', 'DC', 'George Bush', '555-1212')
and then the first argument of
(@addr,$name,$phone)=@_consumes everything, leaving
$name and $phone empty.
sortcontents of perl_decl/apply.pl...
#! /var/local/couch/bin/perl
# this subroutine emulates LISP's apply, by applying a
# function to a list of arguments.
sub apply (&$) {
my $func = shift;
print "func=$func\n" ;
$_ = shift;
print "\$_=$_\n" ;
&{$func};
}
$foo = apply { $_*3 } 4;
print "foo=$foo\n";
...end of perl_decl/apply.pl
contents of perl_decl/apply.pl.out... func=CODE(0x8117b2c) $_=4 foo=12 ...end of perl_decl/apply.pl.out
:lvalue: function returns a location to which something
can be assigned.
:locked: in a multithreaded environment, only allow one
instance of this subroutine to execute at a time.
:locked :method: in a multithreaded environment, only allow
one instance of this subroutine to be active per object upon
which it operates (more about this later).
contents of perl_decl/lvalue1.pl...
#! /var/local/couch/bin/perl
$systime=0;
$usertime=0;
# works correctly
sub whichToChange :lvalue { shift==0 ? $systime : $usertime; }
whichToChange($<)=7;
print "systime=$systime usertime=$usertime\n";
...end of perl_decl/lvalue1.pl
This produces:
contents of perl_decl/lvalue1.pl.out... systime=0 usertime=7 ...end of perl_decl/lvalue1.pl.out
contents of perl_decl/lvalue2.pl...
#! /var/local/couch/bin/perl
$systime=0;
$usertime=0;
# non-functional!
sub whichToChange :lvalue {
if (shift==0) { return $systime }
else { return $usertime; }
}
whichToChange($<)=7;
print "systime=$systime usertime=$usertime\n";
...end of perl_decl/lvalue2.pl
doesn't compile.
bless
blessbless $ref,$package: assert that the value
of $ref is a member of the package $package.
bless is to define a scope for function
applicability to the value.
bless $var,'Goo';then
$var->something(@args)means (is translated into)
&Goo::something($var,@args)
bless $var,'Goo',
ref($var) is 'Goo'.
func Package(@args)means (is translated into)
&Package::func('Package',@args)
contents of perl_decl/bless1.pl...
#! /var/local/couch/bin/perl
# represent a named Complex number
package Complex ;
sub new {
my $p = shift;
bless { 'label'=>$_[0],'re'=>$_[1], 'im'=>$_[2] }, $p;
}
sub label:lvalue { $_[0]->{'label'} }
sub re:lvalue { $_[0]->{'re'} }
sub im:lvalue { $_[0]->{'im'} }
sub printLabel { ref($_[0]) . " " . $_[0]->label }
sub print {
my $self = shift;
print ref($self) . " " . $self->label
. " (real=" . $self->re
. ", imag=" . $self->im . ")\n";
}
package main;
$thing = new Complex("Fred", 1.0, 2.0);
# or &Complex::new('Complex',"Fred", 1.0, 2.0)
use Data::Dumper;
print Dumper($thing);
$thing->print;
$thing->re=3.7;
$thing->print;
$thing->label='George';
$thing->print;
print Dumper($thing);
...end of perl_decl/bless1.pl
contents of perl_decl/bless1.pl.out...
$VAR1 = bless( {
're' => '1',
'im' => '2',
'label' => 'Fred'
}, 'Complex' );
Complex Fred (real=1, imag=2)
Complex Fred (real=3.7, imag=2)
Complex George (real=3.7, imag=2)
$VAR1 = bless( {
're' => '3.7',
'im' => '2',
'label' => 'George'
}, 'Complex' );
...end of perl_decl/bless1.pl.out
$thing knows its type, and that type
determines which functions will be called on it using the
arrow notation.
contents of perl_decl/bless2.pl...
#! /var/local/couch/bin/perl
# represent a Point in the plane
package Point;
sub new { my $p = shift; bless { @_ }, $p } # cast to associative array
sub name:lvalue { $_[0]->{'name'} }
sub printName { ref($_[0]) . " " . $_[0]->name }
sub area { 0 };
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
# represent a Circle in the plane.
package Circle;
sub new { my $p = shift; bless { @_ }, $p } # cast to associative array
sub name:lvalue { $_[0]->{'name'} }
sub printName { ref($_[0]) . " " . $_[0]->name }
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
sub radius:lvalue { $_[0]->{'radius'} }
sub PI { 3.1415929 }
sub area { &PI * $_[0]->{'radius'} * $_[0]->{'radius'} }
# represent a Rectangle in the plane
package Rectangle;
sub new { my $p = shift; bless { @_ }, $p } # cast to associative array
sub name:lvalue { $_[0]->{'name'} }
sub printName { ref($_[0]) . " " . $_[0]->name }
sub x1:lvalue { $_[0]->{'x1'} }
sub y1:lvalue { $_[0]->{'y1'} }
sub x2:lvalue { $_[0]->{'x2'} }
sub y2:lvalue { $_[0]->{'y2'} }
sub area { abs(($_[0]->{'x1'}-$_[0]->{'x2'})*($_[0]->{'y1'}-$_[0]->{'y2'})); }
package main;
@stuff = (
new Point ("name"=>"Fred", "x"=> 1, "y"=>2),
new Rectangle ("name"=>"George", "x1"=>0, "y1"=>0, "x2"=>2, "y2"=>3),
new Circle ("name"=>"Amy", "x"=>3, "y"=>3, "radius"=>2)
);
use Data::Dumper;
print Dumper(\@stuff);
for my $s (@stuff) {
print $s->printName . " area is " . $s->area . "\n";
}
...end of perl_decl/bless2.pl
contents of perl_decl/bless2.pl.out...
$VAR1 = [
bless( {
'y' => 2,
'name' => 'Fred',
'x' => 1
}, 'Point' ),
bless( {
'y1' => 0,
'x2' => 2,
'name' => 'George',
'y2' => 3,
'x1' => 0
}, 'Rectangle' ),
bless( {
'y' => 3,
'radius' => 2,
'name' => 'Amy',
'x' => 3
}, 'Circle' )
];
Point Fred area is 0
Rectangle George area is 6
Circle Amy area is 12.5663716
...end of perl_decl/bless2.pl.out
contents of perl_decl/bless3.pl...
#! /var/local/couch/bin/perl
# represent an arbitrary object in the plane
package Thing;
sub new { my $p = shift; bless { @_ }, $p } # cast to associative array
sub name:lvalue { $_[0]->{'name'} }
sub printName { ref($_[0]) . " " . $_[0]->name }
sub area { 0 } # default area is 0
# represent a Point in the plane
package Point;
@Point::ISA = ('Thing'); # inherit methods
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
# represent a Circle in the plane.
package Circle;
@Circle::ISA = ('Thing'); # inherit methods
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
sub radius:lvalue { $_[0]->{'radius'} }
sub PI { 3.1415929 }
sub area { &PI * $_[0]->{'radius'} * $_[0]->{'radius'} }
# represent a Rectangle in the plane
package Rectangle;
@Rectangle::ISA = ('Thing'); # inherit methods
sub x1:lvalue { $_[0]->{'x1'} }
sub y1:lvalue { $_[0]->{'y1'} }
sub x2:lvalue { $_[0]->{'x2'} }
sub y2:lvalue { $_[0]->{'y2'} }
sub area { abs(($_[0]->{'x1'}-$_[0]->{'x2'})
*($_[0]->{'y1'}-$_[0]->{'y2'})); }
package main;
@stuff = (
new Point ("name"=>"Fred", "x"=> 1, "y"=>2),
new Rectangle ("name"=>"George", "x1"=>0, "y1"=>0, "x2"=>2, "y2"=>3),
new Circle ("name"=>"Amy", "x"=>3, "y"=>3, "radius"=>2)
);
use Data::Dumper;
print Dumper(\@stuff);
for my $s (@stuff) {
# print Dumper($s);
print $s->printName . " area is " . $s->area . "\n";
}
...end of perl_decl/bless3.pl
This works identically to the above example.
@ISA=('Thing'): inherit all methods from
package Thing.
@ISA) is a dynamic package parameter.
:lvalue subroutines.
:lvalue forces my subroutine to return a reference.
return
in returning a reference (it copies the value).
@_.
my, our, local control
data visibility.
bless controls function visibility, i.e.,
"makes functions bound to the data upon which they operate".
:lvalue, function visibility can
simulate data visibility.
die with your own
personal runtime error.
contents of perl_decl/bless4.pl...
#! /var/local/couch/bin/perl
# represent an arbitrary object in the plane
package Thing;
sub new { my $p = shift; bless { @_ }, $p } # cast to associative array
sub name:lvalue { $_[0]->{'name'} }
sub printName { ref($_[0]) . " " . $_[0]->name }
# represent a Point in the plane
package Point;
@Point::ISA = ('Thing'); # inherit methods
sub area { 0 };
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
sub print {
my $self = shift;
print ref($self) . " " . $self->name
. " (x=" . $self->x
. ", y=" . $self->y . ")\n";
}
# represent a Circle in the plane.
package Circle;
@Circle::ISA = ('Thing'); # inherit methods
sub x:lvalue { $_[0]->{'x'} }
sub y:lvalue { $_[0]->{'y'} }
sub radius:lvalue { $_[0]->{'radius'} }
sub PI { 3.1415929 }
sub area { &PI * $_[0]->{'radius'} * $_[0]->{'radius'} }
sub print {
my $self = shift;
print ref($self) . " " . $self->name
. " (radius=" . $self->radius
. ", x=" . $self->x
. ", y=" . $self->y . ")\n";
}
sub inside {
my $self = shift;
die "improper input " . ref($self) . " to Circle::inside"
if ref $self ne 'Circle';
my $point = shift;
die "improper argument to Circle::inside"
if ref $point ne 'Point';
die "too many arguments to Circle::inside"
if @_ != 0;
my $d = sqrt(
($point->x-$self->x)*($point->x-$self->x)
+ ($point->y-$self->y)*($point->y-$self->y)
);
return 1 if $d < $self->radius;
return undef;
}
package main;
use Data::Dumper;
$circ = new Circle ('name'=>'Amy', 'x'=>3, 'y'=>3, 'radius'=>2);
$point = new Point ('name'=>'Marsha', 'x'=>2, 'y'=>3);
print $point->printName . '=' . Dumper($point);
print $circ->printName . '=' . Dumper($circ);
if ( $circ->inside($point)) {
print $point->printName . " is inside " . $circ->printName . "\n";
} else {
print $point->printName . " is not inside " . $circ->printName . "\n";
}
if ( $circ->inside(3,4)) {
print $point->printName . " is inside " . $circ->printName . "\n";
} else {
print $point->printName . " is not inside " . $circ->printName . "\n";
}
...end of perl_decl/bless4.pl
contents of perl_decl/bless4.pl.out...
Point Marsha=$VAR1 = bless( {
'y' => 3,
'name' => 'Marsha',
'x' => 2
}, 'Point' );
Circle Amy=$VAR1 = bless( {
'y' => 3,
'radius' => 2,
'name' => 'Amy',
'x' => 3
}, 'Circle' );
Point Marsha is inside Circle Amy
improper argument to Circle::inside at bless4.pl line 42.
...end of perl_decl/bless4.pl.out
lecture
in color