List Separator $, behaving oddly

S

sharma__r

hello all,

when we set the $, punctuation variable two different ways we get
different behaviors.

perl -e '
# this does not work
local *{"::,"} = \do{q[:]};
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- ABC are not separated by colon, even though
$, is set to a colon.
printf "\n";
';

perl -e '
# this works
local ${*{"::,"}} = q[:];
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- A:B:C are colon separated & ok.
printf "\n";
';

Why does this happen? Is this a bug.

Using: perl, v5.8.8 built for i686-linux.

--rakesh
 
R

RedGrittyBrick

when we set the $, punctuation variable two different ways we get
different behaviors.

perl -e '
# this does not work
local *{"::,"} = \do{q[:]};
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- ABC are not separated by colon, even though
$, is set to a colon.
printf "\n";
';

perl -e '
# this works
local ${*{"::,"}} = q[:];
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- A:B:C are colon separated& ok.
printf "\n";
';

Why does this happen? Is this a bug.

C:\> perl -e "{local $,=':'; print qw(A B);} print qw(C D),qq(\n)"
A:BCD

It seems to me your question is more about your (to me) strange way of
writing a simple assignment and localising the result's scope. Avoiding
using bits of Perl I know I don't understand well (random example:
typeglobs) has served me well.

Presumably your real code has some pressing need to use
local *{"::,"} = \do{q[:]};

It might help if you explain what you intend that to do.

Or just wait for a more clever person to notice your question.
 
P

Peter J. Holzer

when we set the $, punctuation variable two different ways we get
different behaviors.

perl -e '
# this does not work
local *{"::,"} = \do{q[:]}; [...]
';

perl -e '
# this works
local ${*{"::,"}} = q[:]; [...]
';

Why does this happen?

May I ask why you set $, in such a wierd way? Why don't you just use

local $, = q[:];

?

hp
 
S

sharma__r

when we set the $, punctuation variable two different ways we get
different behaviors.
perl -e '
# this does not work
local *{"::,"} = \do{q[:]}; [...]

perl -e '
# this works
local ${*{"::,"}} = q[:]; [...]

Why does this happen?

May I ask why you  set $, in such a wierd way? Why don't you just use

    local $, = q[:];

?

        hp


I am trying to alter the punctuation variables inside a sub, like as
show below.

The idea is to make the sub immune from any settings of punctuation
variables that may be in effect
AND
also if we want to supersede the local punctuation inside a sub, we
may supply it from outside via a
hash whose keys are the punctuation variable symbols.

#!/usr/local/bin/perl
use strict;
use warnings;

local $, = q{/}; # <--- top-level setting of list separator
print "Before \$,=[$,] ";
print qw(A B C);
printf "\n";
my %h = (
',' => '+',
);

sub klm {
my %h = %{$_[0]};
local $, = q{=}; # <--- setting inside the sub(use this if not forced
from outside)
no strict 'refs';
${*{"::$_"}} = $h{$_} for keys %h; # <--- this works, meaning proper
$, takes effect as also print shows proper separtors
# *{"::$_"} = \$h{$_} for keys %h; # <--doesn't work, meaning
proper $, takes effect but print does not show proper separtion
print "Inside \$,=[$,] ";
print qw(A B C);
printf "\n";
}

klm \%h;

print "After \$,=[$,] ";
print qw(A B C);
printf "\n";
__END__
 
C

C.DeRykus

hello all,

when we set the $, punctuation variable two different ways we get
different behaviors.

perl -e '
# this does not work
local *{"::,"} = \do{q[:]};
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- ABC are not separated by colon, even though
$, is set to a colon.
printf "\n";
';

perl -e '
# this works
local ${*{"::,"}} = q[:];
print "\$,=[$,]\n";
print "A", "B", "C"; #<--- A:B:C are colon separated & ok.
printf "\n";
';

Why does this happen? Is this a bug.

Using: perl, v5.8.8 built for i686-linux.

Hm, a later version works...

perl -v
This is perl 5, version 12, subversion 2 (v5.12.2) built
for MSWin32-x86-multi-thread

perl -wle "local *{'::,'} = \do{q[:]};print qq{\$,=[$,]};print
'A','B','C'"
$,=[:]
A:B:C
 
P

Peter J. Holzer

when we set the $, punctuation variable two different ways we get
different behaviors.
perl -e '
# this does not work
local *{"::,"} = \do{q[:]}; [...]

perl -e '
# this works
local ${*{"::,"}} = q[:]; [...]

Why does this happen?

May I ask why you  set $, in such a wierd way? Why don't you just use

    local $, = q[:];

?


I am trying to alter the punctuation variables inside a sub, like as
show below.

The idea is to make the sub immune from any settings of punctuation
variables that may be in effect
AND
also if we want to supersede the local punctuation inside a sub, we
may supply it from outside via a
hash whose keys are the punctuation variable symbols.
[...]

sub klm {
my %h = %{$_[0]};
local $, = q{=}; # <--- setting inside the sub(use this if not forced
from outside)
no strict 'refs';
${*{"::$_"}} = $h{$_} for keys %h; # <--- this works, meaning proper
$, takes effect as also print shows proper separtors
# *{"::$_"} = \$h{$_} for keys %h; # <--doesn't work, meaning
proper $, takes effect but print does not show proper separtion

[please avoid wrapped lines in example code: It makes the code hard to
read and it cannot be executed as is]

${$_} = $h{$_} for keys %h;

seems to work, too.

hp
 
I

Ilya Zakharevich

when we set the $, punctuation variable two different ways
Nope.

we get different behaviors.
# this does not work
local *{"::,"} = \do{q[:]};

You are not setting a variable here. You are replacing a container.
After this, a lookup for $, would return not the magic container
usually associated with $, but the container created by q() inside
your do{}. Contrast this with setting a variable, which is changing
what is INSIDE the container.

All the magic properties of $, are lost after your operation (unless
somebody stored $oldComma = \$, somewhere, and now accesses the old
container via $$oldComma.
# this works
local ${*{"::,"}} = q[:];

Here the LHS is an alias for $::,

Hope this helps,
Ilya
 
S

sharma__r

when we set the $, punctuation variable two different ways
Nope.

we get different behaviors.
# this does not work
local *{"::,"} = \do{q[:]};

You are not setting a variable here.  You are replacing a container.
After this, a lookup for $, would return not the magic container
usually associated with $, but the container created by q() inside
your do{}.  Contrast this with setting a variable, which is changing
what is INSIDE the container.

All the magic properties of $, are lost after your operation (unless
somebody stored $oldComma = \$, somewhere, and now accesses the old
container via $$oldComma.
# this works
local ${*{"::,"}} = q[:];

Here the LHS is an alias for $::,

Hope this helps,
Ilya


This has left me confused.
So what you are implying is that Perl looks at the "address" of $,
to enable its magic. But it isn't documented.
And why doesn't this behavior impacting the Exporter ?

--Rakesh
 
I

Ilya Zakharevich

So what you are implying is that Perl looks at the "address" of $,
to enable its magic.

Do not think it is a productive way to describe the situation.

The ACTUAL way things happen is that nobody ever reads $, . A certain
container is attached to a "scalar" slot of *, ; Perl internals read
THIS CONTAINER when print() happens. *foo = \BAR reassign the scalar
slot of *foo.
And why doesn't this behavior impacting the Exporter ?

It is not clear what are you asking. After
*foo = \$, ;
assignments to $foo would change the same container as assignments to
$, .
perl -wle "*foo = \$, ; $foo = 12; print 1,2"
1122

Ilya
 
S

sharma__r

Do not think it is a productive way to describe the situation.

The ACTUAL way things happen is that nobody ever reads $, .  A certain
container is attached to a "scalar" slot of *, ; Perl internals read
THIS CONTAINER when print() happens.  *foo = \BAR reassign the scalar
slot of *foo.


It is not clear what are you asking.  After
  *foo = \$, ;
assignments to $foo would change the same container as assignments to
$, .

  > perl -wle "*foo = \$, ; $foo = 12; print 1,2"
  1122

Ilya


How do we explain what is going on in this scenario:


#!/usr/local/bin/perl
use strict; use warnings;

print "Before:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); #< -- AB

no strict 'refs';
*{"::,"} = \do{":"};
use strict 'refs';
print "After1:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); # <---- AB

$, = "+";
print "After2:...";
print "\$,=[$,]";
print "\\\$,=",\$,; #
print qw(A B); # <--- AB
__END__


Even when $, is reassigned as "+" the print is not taking it. This is
maybe coz container is still pointing to the do{":}" even now.
That means perl has stored the address of the "original" container of
$, and looks at that when print() is invoked. And that is
an undocumented feature.

--Rakesh
 
C

C.DeRykus

Do not think it is a productive way to describe the situation.
The ACTUAL way things happen is that nobody ever reads $, .  A certain
container is attached to a "scalar" slot of *, ; Perl internals read
THIS CONTAINER when print() happens.  *foo = \BAR reassign the scalar
slot of *foo.
It is not clear what are you asking.  After
  *foo = \$, ;
assignments to $foo would change the same container as assignments to
$, .
  > perl -wle "*foo = \$, ; $foo = 12; print 1,2"
  1122

How do we explain what is going on in this scenario:

#!/usr/local/bin/perl
use strict; use warnings;

print "Before:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); #< -- AB

no strict 'refs';
        *{"::,"} = \do{":"};
use strict 'refs';
print "After1:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); # <---- AB

        $, = "+";
print "After2:...";
print "\$,=[$,]";
print "\\\$,=",\$,; #
print qw(A B); # <--- AB
__END__

Even when $, is reassigned as "+" the print is not taking it. This is
maybe coz container is still pointing to the do{":}" even now.
That means perl has stored the address of the "original" container of
$, and looks at that when print() is invoked. And that is
an undocumented feature.


What version? Program output is considerably
different with modern Perl versions:


This is perl, v5.10.1 (*) built for amd64-freebsd
=================================================
Before:...
Use of uninitialized value $, in concatenation (.)
or string...
$,=[]
\$,=SCALAR(0x9054ca8)
AB
After1:...
$,=[:]
\$,=SCALAR(0x9054e28)
AB
Modification of a read-only value attempted...


This is perl 5, version 12, subversion 2 (v5.12.2)
built for MSWin32-x86-multi-thread
==================================================
Before:...
Use of uninitialized value $, in concatenation (.)
$,=[]
\$,=SCALAR(0x1a8028c)
AB
After1:...
$,=[:]
\$,=:SCALAR(0x90af74)
A:B
After2:...
$,=[+]
\$,=+SCALAR(0x90af74)
A+B
 
S

sharma__r

How do we explain what is going on in this scenario:
#!/usr/local/bin/perl
use strict; use warnings;
print "Before:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); #< -- AB
no strict 'refs';
        *{"::,"} = \do{":"};
use strict 'refs';
print "After1:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); # <---- AB
        $, = "+";
print "After2:...";
print "\$,=[$,]";
print "\\\$,=",\$,; #
print qw(A B); # <--- AB
__END__
Even when $, is reassigned as "+" the print is not taking it. This is
maybe coz container is still pointing to the do{":}" even now.
That means perl has stored the address of the "original" container of
$, and looks at that when print() is invoked. And that is
an undocumented feature.

What version?  Program output is considerably
different with modern Perl versions:

   This is perl, v5.10.1 (*) built for amd64-freebsd
   =================================================
   Before:...
   Use of uninitialized value $, in concatenation (.)
   or string...
   $,=[]
   \$,=SCALAR(0x9054ca8)
   AB
   After1:...
   $,=[:]
   \$,=SCALAR(0x9054e28)
   AB
   Modification of a read-only value attempted...

   This is perl 5, version 12, subversion 2 (v5.12.2)
   built for MSWin32-x86-multi-thread
   ==================================================
   Before:...
   Use of uninitialized value $, in concatenation (.)
   $,=[]
   \$,=SCALAR(0x1a8028c)
   AB
   After1:...
   $,=[:]
   \$,=:SCALAR(0x90af74)
   A:B
   After2:...
   $,=[+]
   \$,=+SCALAR(0x90af74)
   A+B

printf("perl v%vd OS %s\n",$^V, $^O);
$, = '_';
my $sep = '*';
*{"::,"} = \$sep;
print "ok", "[$,]\n";
#---------------------- Displays results shown below:

perl v5.8.9 OS linux
ok_[*]


########################################################################################################
My question is basically the following:

"print" when it spits out a list, separates the list elements by the
$, variable's value.

Now, in the print statement I have above, one of the list elements is
$, itself. When it prints
$, it picks '*' (that's coz $, has been aliased to $sep).
But the elements are separated by '_' which is the original value of
$,

Why does print not use the new aliased value of $, for separating the
list elements? Could it be the print has squirreled away
the value of $, at compile time, which it'll use at run time to
separate the elements?
#############################

--Rakesh
 
C

C.DeRykus

On Feb 20, 6:16 pm, (e-mail address removed) wrote:
So what you are implying is that Perl looks at the "address" of $,
to enable its magic.
Do not think it is a productive way to describe the situation.
The ACTUAL way things happen is that nobody ever reads $, .  A certain
container is attached to a "scalar" slot of *, ; Perl internals read
THIS CONTAINER when print() happens.  *foo = \BAR reassign the scalar
slot of *foo.
And why doesn't this behavior impacting the Exporter ?
It is not clear what are you asking.  After
  *foo = \$, ;
assignments to $foo would change the same container as assignments to
$, .
  > perl -wle "*foo = \$, ; $foo = 12; print 1,2"
  1122
Ilya
How do we explain what is going on in this scenario:
#!/usr/local/bin/perl
use strict; use warnings;
print "Before:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); #< -- AB
no strict 'refs';
        *{"::,"} = \do{":"};
use strict 'refs';
print "After1:...";
print "\$,=[$,]";
print "\\\$,=",\$,;
print qw(A B); # <---- AB
        $, = "+";
print "After2:...";
print "\$,=[$,]";
print "\\\$,=",\$,; #
print qw(A B); # <--- AB
__END__
Even when $, is reassigned as "+" the print is not taking it.
maybe coz container is still pointing to the do{":}" even now.
That means perl has stored the address of the "original" container of
$, and looks at that when print() is invoked. And that is
an undocumented feature.
[snip]



printf("perl v%vd OS %s\n",$^V, $^O);
$, = '_';
my $sep = '*';
*{"::,"} = \$sep;
print "ok", "[$,]\n";
#---------------------- Displays results shown below:

perl v5.8.9 OS linux
ok_[*]

########################################################################################################
My question is basically the following:

"print" when it spits out a list, separates the list elements by the
$, variable's value.

Now, in the print statement I have above, one of the list elements is
$, itself. When it prints
$, it picks '*' (that's coz $, has been aliased to $sep).
But the elements are separated by '_' which is the original value of
$,

Why does print not use the new aliased value of $, for separating the
list elements? Could it be the print has squirreled away
the value of $, at compile time, which it'll use at run time to
separate the elements?
#############################


I'm suggesting that Perl's approach has evolved away from
the quirkiness of pre-5.10 versions (ie, your 5.89) and
how they dealt with '$,'. And if I understand correctly
what Ilya was saying, '$,' was special cased so that '$,'
glob accesses dealt only with the scalar slot and not the
entire glob.

My speculation is that there was a change to make '$,'
glob behavior more consistent with what you'd expect.
That is, you should be able to assign references to the
glob and have the appropriate parts of the glob change.

perl -wle'local *foo = \do{"bar"}; print $foo'
--> bar

Symmetrically, in your case:

perl -wle 'local *{"::,"} = \do{q[:]}; print $,'
--> :

And this expected behavior does occur in 5.10 and higher
but not your 5.89 distro.


--
Charles DeRykus

P.s. If you look at the 5.10/5.12 examples I cited, there's
even some differing behavior between 5.10 and 5.12 so there's
still some evolution it seems.
 
I

Ilya Zakharevich

You did not alias $, - you aliased TO $,. After this "THAT" $, is not
magical - it is just an alias for something "normal".
???

what Ilya was saying, '$,' was special cased so that '$,'
glob accesses dealt only with the scalar slot and not the
entire glob.

??? All is said is that no globs are (were?) magic. What may (have)
be(en) magic is a container referenced by the glob. (At least,
referenced at the Perl startup.)

I do not see much reason to document results of symbol table
manipulation. ("One is not supposed to do this" is quite enough. ;-)
Symmetrically, in your case:

perl -wle 'local *{"::,"} = \do{q[:]}; print $,'
--> :

And this expected behavior does occur in 5.10 and higher
but not your 5.89 distro.

This is a different topic: the last $, is (was?) compiled to ${*{'::,'}},
then *{'::,'} was pre-calculated at compile time (a very important
optimization, since hash access in Perl is painfully slow).

One may want to remember that access to non-lexical scalar has two
redirections: first *{P::NAME} is calculated, then ${ *{P::NAME} }; in
other words: first a 'P::NAME' slot of the symbol table (one gets a
glob), then the scalar slot of this glob.

Both slots may be reset: the first one with
*{P::NAME} = *new_foo; # sp?
the second one with
*{P::NAME} = \$new_bar;

Well, to be completely honest, the slot of symbol table is also
calculated in several steps (first %{main::}{P::}, then
${main::}{P::}{NAME}, so there are many other slots to redirect in
between...

Ilya
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top