Lvalues revisited: what's *not* an lvalue?

8 views
Skip to first unread message

John Nolan

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
If I can say these:

a) substr($a, 0, 3) = "Tom";

b) ($pluralstem = $singular) =~ s/[^aeo]y$/ie/;

c) ($input =~ /^y/i ? $yesses : $nos) ++;

Then why can't I say this?:

d) <FILEHANDLE> = @lines;

I'm pretty sure the answer is "Well, that's the way it is,"
but I'm just curious, in case the real answer is more involved
than I think. How was it decided which functions and operators
would get to be l-values sometimes? How come you can do this
with "=", "substr()" and "?:", but not with "<>" ? If you can't
assign to angle brackets, how come you can assign to "substr()" ?

If it were OK to write to a filehandle this way, there would be a
certain symmetry to it:

e) @lines = <INFILE>;
f) <OUTFILE> = @lines;

...isn't it pretty?

Alas, it ain't so.
--
##--------------------------------
## John Nolan
## j...@n2k.com
##--------------------------------

Mark-Jason Dominus

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
In article <361BA65B...@n2k.com>, John Nolan <j...@n2k.com> wrote:
>If I can say these:
> a) substr($a, 0, 3) = "Tom";
> b) ($pluralstem = $singular) =~ s/[^aeo]y$/ie/;
> c) ($input =~ /^y/i ? $yesses : $nos) ++;
>
>Then why can't I say this?:
> d) <FILEHANDLE> = @lines;

I always have a problem with these `why can't I say this' questions.
They always seem to assume that the meaning of the new construct is
obvious, but it almost never is.

For example, in this case I first thought that you meant that
FILEHANDLE was open for writing, and that `<FILEHANDLE> = @lines'
would be the same as `print FILEHANDLE @lines;'

Then I changed my mind and thought that you meant the FILEHANDLE was
open for reading, and that the `assignment' would push the lines back
into the buffer so that they would be read by subsequent $line =
<FILEHANDLE> assignments, followed by whatever would have been read
from FILEHANDLE if you had not assigned to it. But then I thought
maybe you wanted the @lines to completely replace the input that would
normally have been read from FILEHANDLE.

Finally I decided I didn't know what you meant. I would suggest that
next time you accompany the question with a sentence like

``I want it to be synonymous with ....''

But I can still discuss the question in a general context.

In Lisp, there is a a function called `setf'. You call it like this:

(setf EXPRESSION VALUE)

EXPRESSION is any Lisp expression that would normally have located a
value in memory and returned it. When you use `setf', it sets a new
value instead of returning the old one. For example, in Lisp, the
expression

somelist

returns the value of the variable `somelist', and

(setf somelist 1)

sets the value of `somelist' to 1. The expression

(car somelist)

returns the value of the first element of the list `somelist'
(supposing that it is a list). The expression

(setf (car somelist) 1)

sets the first element of the list to `1'.

The implementation of `setf' is very simple. Normally, a Lisp
expression evaluates to a pointer, which is dereferenced to return the
value of the expression. For example, to compute `(car somelist)',
Lisp must come up with a pointer to the first element. When the
expression is part of a `setf' form, the only thing different is that
Lisp stores the new value through the pointer instead of retrieving
the old value.

There is an essential point here: The expression must return something
that can be referred to with a pointer. In C terminology, this kind
of thing is called an `object': It is a well-defined region in the
computer's memory. The Perl term `lvalue' comes from C, where the
meaning of `lvalue' is `an expression that refers to an object'.
The `L' in `lvalue' is for `left', because lvalue expressions are
exactly those which can appear on the left-hand side of the =
operator, which is C's version of `setf'.

As we saw, in Lisp, `somelist' and `(car somelist)' refer to objects.
In Perl, `$x' and `@x' refer to objects. In Perl, `substr($a,0,3)'
also refers to an object: It refers to the three bytes of memory that
hold the first three characters of the string value of $a.

Here are the usual examples of expressions that are *not* lvalues,
because they do *not* refer to objects:

4
and $x+1

4 is not an object because it is not stored in the computer's memory;
it is implicit in the code segment of the program somewhere, or maybe
it is temporarily on the stack, or there might not be a 4 anywhere in
the run-time version of the program at all. similarly the result of
$x+1 need not be stored anywhere.

All this is the reason why statements like

4 = EXPR;
and $x+1 = EXPR;

are illegal; those things are not lvalues because they do not refer to
a specific part of the computer's memory. In general, the result of
any computation is not going to be an lvalue for just this reason.
Just as $x+1 is not an lvalue, neither are

$x*2
cos $x
reverse $x
stat $x

etc. It's easy to see why `substr($a,0,3)' is an exception here; it returns
something that makes sense as a contiguous region of memory. It's
easy to see why ($b = $a) is an exception; it returns $b, which is an
lvalue. It's easy to see why ($input =~ /^y/i ? $yesses : $nos) is an
exception; it returns one of $yesses or $nos, and both those are
already lvalues. But it would be very bizarre for

sqrt($x) = 3

to assign 9 to x. It could probably be made to work somehow, but it
would require smoe ledgerdemain behind the scenes. It cannot work
naturally the way ${SCALAR_REF_EXPR} = 3 does. It would be strange,
because it would suggest first that sqrt($x) was actually a location
that you could store data in, which it isn't, and second that the
sqrt($x) location and the $x location were somehow associated so that
modifynig one of these would also modify the other.

Similarly, what would

<FILEHANDLE> = @lines

mean? <FILEHANDLE> means to read one or more lines from the
filehandle, and to return the lines. The lines are not stored
anywhere; they are not an object. You could even imagine that the
optimizer might not read them at all, if they occurred in an
expression like

($firstline) = <FILEHANDLE>;
# Optimized to:
# $firstline = <FILEHANDLE>;
# seek FILEHANDLE, 0, 2;

There is no permanent memory allocated for the result of <FILEHANDLE>,
so there is nowhere to store the lines from @lines. Sure, you can
allocate some:

(@filehandle = <FILEHANDLE>)

And if you do this, then it becomes an lvalue:

(@filehandle = <FILEHANDLE>) = @lines;

Perhaps this isn't what you wanted, but since you didn't say what you
wanted, I guess it is good enough.

Anyway, I hope this sheds some light on your question.

Dave Lorand

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
In article <361BA65B...@n2k.com>, j...@n2k.com wrote:

> If I can say these:
>
> a) substr($a, 0, 3) = "Tom";
>
> b) ($pluralstem = $singular) =~ s/[^aeo]y$/ie/;
>
> c) ($input =~ /^y/i ? $yesses : $nos) ++;
>
> Then why can't I say this?:
>
> d) <FILEHANDLE> = @lines;
>

> I'm pretty sure the answer is "Well, that's the way it is,"

My answer is "it doesn't make the same kind of sense."

> but I'm just curious, in case the real answer is more involved
> than I think. How was it decided which functions and operators
> would get to be l-values sometimes? How come you can do this
> with "=", "substr()" and "?:", but not with "<>" ? If you can't
> assign to angle brackets, how come you can assign to "substr()" ?

Your examples a-c are all things which resolve to a variable or a piece of
a variable (characters 0-3 of $a, $pluralstem, and either $yesses or $nos,
respectively). You're not assigning to functions or operators, you're
assigning to their result, which in those cases is an lvalue.

There is no variable associated with <FILEHANDLE> except in the magic case
of while (<FILEHANDLE>) { ... }, where you're assigning to $_. Outside of
that, what variable would you want associated with it?

> If it were OK to write to a filehandle this way, there would be a
> certain symmetry to it:
>
> e) @lines = <INFILE>;
> f) <OUTFILE> = @lines;
>
> ...isn't it pretty?

Oh ... that's what you'd want. It seems to me that violates the spirit of
Perl, because I can't think of another case where you can assign to
something which is not a variable or a substring of one. (But maybe the
spirit of Perl will have a conversion experience; who knows ...)

Regards,

Dave

____________________________________________________________
| Dave Lorand | da...@spc.uchicago.edu |
| Programmer/Analyst | 773-702-3792 |
| Social Science Research Computing | 773-702-0793 (dept.) |
| University of Chicago | 773-702-2101 (fax) |
+-----------------------------------+------------------------+

Graham Barr

unread,
Oct 7, 1998, 3:00:00 AM10/7/98
to
Well I would agree it would be nice, but let me try to explain the examples
you gave.

Let's start with b)

The result of any assignment is what was assigned, but it is not a copy,
more like an implicit reference. If you look at the examples in
the camel for select() you will see something like

select($rout=$rin,0,0,undef);

as select will modify it's arguments this allows you to keep the value
of $rin and $rout will be modified.

The ()'s are need due to precidence ie do the assignment and then
do the substitution on the result, if you think of all operators a subs
then this would be

subst($pluralstem = $singular, /[^aeo]y$/ie/);

c) This is similar ?: just chhoses which variable is passed to the
++ operator

a) substr is a bit different. substr returns a scalar with some MAGIC
attached, this magic contains a reference to the original string
and where to start/stop. This is so that the data is not copied until
it needs to be. So ask yourself the question "what would you like
assignment to this type of scalar to do" ?

Now we come to d)

a,b and c are all based on assignment to a scalar or operation on a scalar
which is the result of some operation, assignment or selection. ie non
of the operators are really doing anything different just because they are
being used as an lvalue

But <> actually does something, it reads from the filehandle, for

<FH> = @lines

to work this would have to change, <> would need to know that it is
in an lvalue context. But perl does not have any such context.

I hope this helps.

On Wed, Oct 07, 1998 at 01:35:23PM -0400, John Nolan wrote:
> If I can say these:
>
> a) substr($a, 0, 3) = "Tom";
>
> b) ($pluralstem = $singular) =~ s/[^aeo]y$/ie/;
>
> c) ($input =~ /^y/i ? $yesses : $nos) ++;
>
> Then why can't I say this?:
>
> d) <FILEHANDLE> = @lines;
>
> I'm pretty sure the answer is "Well, that's the way it is,"

> but I'm just curious, in case the real answer is more involved
> than I think. How was it decided which functions and operators
> would get to be l-values sometimes? How come you can do this
> with "=", "substr()" and "?:", but not with "<>" ? If you can't
> assign to angle brackets, how come you can assign to "substr()" ?
>

> If it were OK to write to a filehandle this way, there would be a
> certain symmetry to it:
>
> e) @lines = <INFILE>;
> f) <OUTFILE> = @lines;
>
> ...isn't it pretty?
>

> Alas, it ain't so.

--
Graham Barr <gb...@ti.com>
For every action, there is an equal and opposite criticism.

Larry Wall

unread,
Oct 8, 1998, 3:00:00 AM10/8/98
to
j...@n2k.com writes:
: If it were OK to write to a filehandle this way, there would be a
: certain symmetry to it:
:
: e) @lines = <INFILE>;
: f) <OUTFILE> = @lines;
:
: ...isn't it pretty?

Sure, now tell us what

<FILE> =~ s/foo/bar/;

is supposed to mean.

: Alas, it ain't so.

Not so very alas as all that, really. I actually considered making <>
work that way at the beginning of Perl, but decided on print instead.

The first language I ever wrote (for a compiler class some time in the
1970's) had single terminal I/O operator of #. It behaved as either
an lvalue or an rvalue. So it's not as if it wasn't thunk of.

Symmetry is overrated. Overrated is symmetry.

Larry

Mark-Jason Dominus

unread,
Oct 8, 1998, 3:00:00 AM10/8/98
to
In article <6vhq4r$a...@kiev.wall.org>, Larry Wall <la...@kiev.wall.org> wrote:
>The first language I ever wrote (for a compiler class some time in the
>1970's) had single terminal I/O operator of #. It behaved as either
>an lvalue or an rvalue. So it's not as if it wasn't thunk of.

And of course SNOBOL and APL both do it that way. (Were you familiar
with SNOBOL? Perl shows plenty of SNOBOL influence, but it might all
have been inherited rom places like awk.)

It actually makes some sense to do it that way. In C and Perl, we
have ?:, which is like an expression version of if-else; it's
convenient when you want to embed a conditional into an expression.
If printing is an experssion, as it is in SNOBOL and APL, you can
embed a print anywhere into an expression.

Also, there are many places in SNOBOL where assignment to some
variable is implicit, and it's easy enough to have it assign to OUTPUT
to have it print the result out instead of doing a real assignment.

Of cuorse, if you want that feature in Perl, it's easy to get it:

package Snobol_OUTPUT;

sub TIESCALAR {
my $pack = shift;
my $fh = shift || *STDOUT;
bless { Handle => $fh } => $pack;
}

sub STORE {
my $self = shift;
my $value = shift;
print {$self->{Handle}} $value;
}

sun import {
my $pack = shift;
my $caller = caller;
tie ${$caller . '::OUTPUT'} => $pack;
}

1;


Then you can say SNOBOLish things like

use Snobol_OUTPUT;

while (<STDIN>) {
chomp;
($col1, $OUTPUT, $col3) = split;
# Column 2 has already been printed.
# Now do something with col1 and col3.
}

Jaime Metcher

unread,
Oct 9, 1998, 3:00:00 AM10/9/98
to
Mark-Jason Dominus wrote:
>
[A great deal of interesting stuff. Go read his post *now*!]

It seems, however, that not everything that can be referred to by a
pointer, or is an "object" as you say, is an lvalue. Cf (from an
earlier thread "What is an lvalue (in perl)?"):

Jim Woodgate wrote:
> > I believe that in both cases
>
> ($a=5) = $a++;
> ($a=5) = ++$a;
>
> the order is the same (has to be, pre and post increment have the same
> precedence) I'm guessing that what is important here is what is
> returned by the right hand side. post-increment returns the "value"
> of $a, then increments $a. It appears that the pre-increment actually
> returns $a, so they could both be rewritten as so:
>
> ($a=5) = 10;
> ($a=5) = $a;
>
> At this point you get the same results (10 and 5), that using post and
> pre increment give you.
>

++$a ends up as an object in the above example, but is not an lvalue.

--
Jaime Metcher

Howard S. Modell

unread,
Oct 9, 1998, 3:00:00 AM10/9/98
to
Larry Wall wrote:
>
> j...@n2k.com writes:
> : If it were OK to write to a filehandle this way, there would be a
> : certain symmetry to it:
> :
> : e) @lines = <INFILE>;
> : f) <OUTFILE> = @lines;
> :
> : ...isn't it pretty?
>
> Sure, now tell us what
>
> <FILE> =~ s/foo/bar/;
>
> is supposed to mean.

actually, as a fan of Snobol4 and similar languages, sure I can.

If FILE is tied to a file for Input purposes, it means "read a
record/line
from the file whose handle is FILE, replace all instances of 'foo' with
'bar'
in-place in the input buffer, and because the buffer hasn't been
assigned
to a variable, it will 'go away' at the next reference to <FILE>".

If FILE is tied to a file for Output purposes, <FILE> is effectively the
null string.

I mean, suppose I code up:
open(FILE, ">foo.lst");
$x = <FILE>;

what is the value of $x?

>
> Larry


--
"this .sig is buzzword-compliant, real-time, O-O, and internet-ready"
---------------------------------------------------------------------
Howard S. Modell http://warlok.ds.boeing.com/~howie/
Mac Evangelist http://warlok.ds.boeing.com/MacEvangelism.html

Larry Wall

unread,
Oct 12, 1998, 3:00:00 AM10/12/98
to
In article <6vj9id$2f0$1...@monet.op.net>, Mark-Jason Dominus <m...@Op.Net> wrote:
>In article <6vhq4r$a...@kiev.wall.org>, Larry Wall <la...@kiev.wall.org> wrote:
>>The first language I ever wrote (for a compiler class some time in the
>>1970's) had single terminal I/O operator of #. It behaved as either
>>an lvalue or an rvalue. So it's not as if it wasn't thunk of.
>
>And of course SNOBOL and APL both do it that way. (Were you familiar
>with SNOBOL? Perl shows plenty of SNOBOL influence, but it might all
>have been inherited rom places like awk.)

Well, actually, it was from APL, via my brother-in-law Mark Biggar, who
was writing an APL interpreter under RSTS for his honors project. He
and I did the compiler class together, so he probably suggested the
two-way I/O operator. I didn't know about SNOBOL at the time.

About the only direct influence SNOBOL had on Perl was that I liked
the way that failure tended to be handled out to the right of the
"real" code. Everything else was through awk, sed, grep, et al...

Larry

Reply all
Reply to author
Forward
0 new messages