Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

How to find out if an argument is an LVALUE ? (TinyPerl)

by harangzsolt33 (Chaplain)
on Nov 09, 2023 at 02:08 UTC ( [id://11155488]=perlquestion: print w/replies, xml ) Need Help??

harangzsolt33 has asked for the wisdom of the Perl Monks concerning the following question:

I feel confused. So, let me get this straight. An LVALUE is a value that is a literal like a "constant," therefore it cannot be modified. So, let's say we have a function called: MODIFY { $_[0] = 1; } which overwrites the first argument. If I do this MODIFY(4) that's going to throw an error. Technically, $X = 3; MODIFY($X + 3); print $X; should also throw an error, but it doesn't, and I get it... It's ok. lol

But now let's try this through a reference. Here we create a reference to an LVALUE: MODIFYRR(\3) where sub MODIFYRR { my $REF = $_[0]; $$REF = 1; } Now, do we get an error, because we try to modify the constant 3 ? NO, we don't! Why? Because the moment it created a reference, it also copied 3 in the memory somewhere. And the only way we can access that copy in the memory is through the reference we created. So, we can both read or write that memory location through the reference. And when trying to modify the value through that reference, it is no longer behaving like an lvalue. (In this example, MODIFYRR(\3) we don't even pass a reference to an lvalue; we actually pass a reference to a SCALAR.)

I've read that the ref() function will tell us what a reference is pointing to. For example, if something is a reference to a SCALAR or CODE or HASH or LVALUE or GLOB or whatever. So, that way we can figure out what type the $_[0] argument is. But it does not work! Why? Because we can't just do ref($_[0]) because it's not a reference, so it just returns an empty string, but if we create a reference to $_[0] by saying $REF = \$_[0]; and then try to see what type of reference it is: ref($REF), we only get a few possibilities: If it's a code reference, it will say 'CODE' or if it's a scalar reference, it will say 'SCALAR' but it will never say 'LVALUE' as the documentation claims. Why? Because the moment we try to make a reference to an lvalue, it copies the original lvalue into a scalar and then creates a reference TO THAT SCALAR. So, ref() will always say 'SCALAR' when we test an lvalue. So, I give up! How do you do this?? I want to know if an argument is lvalue or not. :(

#!/usr/bin/perl -w use strict; use warnings; my @S = ('a', 'b', 'c', 1, 2, 3); my $SCALAR = 555; my $SCALAR_REF = \"Hello World"; my $CODE_REF = sub { print "HI"; }; print "\n\n"; my $A = 3; MODIFY($A + 3); print " A = $A \n\n--------------"; # I want to print the TYPE of these arguments: AAA(@S, $SCALAR, $SCALAR + 3, 9999, \444, $SCALAR_REF, $CODE_REF); exit; sub AAA { foreach (@_) { my $REF = \$_; print "\nvalue: $_ \t\t type: ", ref($REF); MODIFYRR($REF); # MODIFY($_); } } sub MODIFY { $_[0] = 1; } sub MODIFYRR { my $REF = shift; $$REF = 1; }

Replies are listed 'Best First'.
Re: How to find out if an argument is an LVALUE ?
by ikegami (Patriarch) on Nov 09, 2023 at 06:46 UTC

    An LVALUE is a value that is a literal like a "constant," therefore it cannot be modified.

    An lvalue is something that can be used on the "l"eft of an assignment operator. It pretty much means "something modifiable", the opposite of what you said.

    ref returns LVALUE for references to PVLV scalars. PVLV scalars are returned by some operations which need to produce a scalar whose modification has side-effects. Those operators are keys, pos, substr and vec. (They only return a PVLV when used in an lvalue context.)

    For example,

    my $x = "def"; say ref( \substr( $x, 0, 0 ) ); # LVALUE substr( $x, 0, 0 ) = "abc"; say $x; # abcdef
    my $x = "def"; my $r = \substr( $x, 0, 0 ); say ref( $r ); # LVALUE $$r = "abc"; say $x; # abcdef

    Because we can't just do ref($_[0]) because it's not a reference

    True, but contrary to what you said, $REF = \$_[0]; ref( $REF ) does work.

    $ perl -Mv5.014 -e' sub f { my $REF = \$_[0]; say ref( $REF ); } f substr( "", 0, 0 ); ' LVALUE

    That said, all you need is ref( \$_[0] ).

    $ perl -Mv5.014 -e' sub f { say ref( \$_[0] ); } f substr( "", 0, 0 ); ' LVALUE
Re: How to find out if an argument is an LVALUE ?
by eyepopslikeamosquito (Archbishop) on Nov 09, 2023 at 09:12 UTC

    Hopefully, you're happy with ++ikegami's explanation of LVALUES.

    I still have a nagging concern that this is an XY Problem. That is, you're trying to do X, and you thought of solution Y (using LVALUES) ... yet there might be a better solution to X that doesn't require LVALUES, but we can't know that unless you describe what X is.

    👁️🍾👍🦟
      Well, first of all, I think, I had the definition of an lvalue all mixed up. Now, it's getting clearer.

      Secondly, I am unsure how you call a literal in a function call. When we pass a literal number, for example MODIFY(4), what do you call that?

      Thirdly, I am using Windows XP again with TinyPerl 5.8 now. So, do you think, there was a significant change in how Perl creates these references between versions 5.8 and 5.38? Because it seems to me that we're getting different error messages. I only get the "modification of read-only value attempt" error when I uncomment the line MODIFY($_); in my code. In other words, directly trying to modify the literal is not working, but when I try to do it through a reference, TinyPerl 5.8 gets away with it without an error message. Lol

        When we pass a literal number, for example MODIFY(4), what do you call that?
        I call it "argument", just as any non-literal argument. The difference is subtly hinted at in perlsub:
        In a subroutine that does not use signatures, any arguments passed in show up in the array @_. Therefore, if you called a function with two arguments, those would be stored in $_[0] and $_[1]. The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable).
        Maybe your original question stems from this, as "updatable" is more or less the same as "lvalue"?

        Maybe you found a bug in (Tiny)Perl 5.8.0. It's a bit too late for a bugreport, I'm afraid.

        Greetings,
        -jo

        $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
        Do you mean this?
        $ perl -E 'sub foo { $_[0]= 5 } foo(4)' Modification of a read-only value attempted at -e line 1.

        I would call '4' a "constant", though it appears perl calls it a "read-only value". You can find out whether one of your parameters is readonly like this:

        use Scalar::Util "readonly"; sub foo { printf "%s\n", readonly($_[0])? "readonly" : "writable"; $_[0]= 5 if !readonly($_[0]) } foo(4); foo(my $x= 4); print "$x\n";

        Maybe tinyperl's errors are different. If you had an error somewhere like "Can't use a constant as an LVALUE" I can see where that might have been confusing, but LVALUE is referring to "a thing which can be assigned-to", and that error would be saying basically that you can't use a read-only or constant on the left side of an equal sign.

        Thirdly, I am using Windows XP again with TinyPerl 5.8 now

        I have a feeling that I am going to regret asking...but I am rather intrigued...

        Why are you using an OS that was retired over a decade ago and what are you using a Perl version from two decades ago?

        Do you drive an Austin Allegro by any chance???

Re: How to find out if an argument is an LVALUE ?
by LanX (Saint) on Nov 09, 2023 at 02:42 UTC
    Your results look wrong, and your definition of lvalue definitly is.

    I tried to reproduce some snippets of your code on my mobile with perl 5.36 and I always get

    Modification of a read-only value attempted

    Which version of perl are you using?

    (Aren't you the guy with that obscure stone age tiny perl?)

    Anyway it's very late I'm going to bed now :)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      Aren't you the guy with that obscure stone age tiny perl?

      Yes he was (Perl 5.004 and TinyPerl 5.8 on Windows XP).

      However, he surprised us a week or two ago by asking How do I install a Perl module? on ubuntu 23.04 x64 on an old DELL desktop computer. Though I don't know the status of his new Linux adventure, I'm hoping he took my advice to build the latest perl v5.38 from source. :)

      👁️🍾👍🦟
      I'm using TinyPerl 5.8 now. I am surprised that there is such a big difference in how references are created in two distinct Perl versions. I mean 5.8 is not such an ancient version. I would say that Perl 4 is ancient. Nobody uses that anymore. lol
        A proper 5.8 may throw the right warnings.

        But according to the project page is Tiny Perl cutting off a lot of the code in order to condense the size to tiny (sic)

        And did you ever check if the constant/read-only values were really changed?

        Anyway please be kind and tag such posts in the title with Tiny Perl in the future, like the Perl4 and Raku folks do.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

        Perl 5.8 is listed as a Legacy version and is now over 20 years old.

        In my mind, that counts as ancient!

        I mean 5.8 is not such an ancient version. I would say that Perl 4 is ancient.

        Perl 4? Why not go all the way back to Perl 1? Now that you have a Linux box, you can build it from source a lot quicker than building a modern perl. Runs a lot faster too, without all those pesky modules slowing things down. ;-)

        👁️🍾👍🦟

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11155488]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2024-04-22 00:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found