Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Re: LVALUE refs

by BrowserUk (Patriarch)
on Feb 13, 2003 at 22:22 UTC ( [id://235122]=note: print w/replies, xml ) Need Help??


in reply to Re: LVALUE refs
in thread LVALUE refs

Okay. Thanks Elian. I can see why I was fooled into thinking it was one per string. If I take an LVALUE ref to one string and save it. Then an LVALUE ref to another string and save it and then print the targets of both, they seem independant. Further investigation after your clarification shows that whilst I can still reference both independantly, only the latter remains a real LVALUE, the former having been converted to a standard scalar containing whatever the LVALUE was pointing at when the second LVALUE is taken.

It's kind of a shame that it works that way, I had hoped to use an array of lvalue refs to acheive efficiencies in fixed record processing. Sort of emulating COBOL style storage overlays. I can see how it would mean major changes to allow this though.


Examine what is said, not who speaks.

The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Replies are listed 'Best First'.
Re: Re: Re: LVALUE refs
by Elian (Parson) on Feb 13, 2003 at 22:45 UTC
    While this could be done, I think you'd find it not actually worth the effort, as it'll take more space and more time. The only real win would be in programmer efficiency.

    Given that programmer efficiency isn't at all a bad thing, you can duplicate substr's functionality--just write your own (presumably overriding the core substr) and have it return tied scalars that substitute back in the original. You could even enforce same-size replacement this way if you want.

Re: Re: Re: LVALUE refs
by Juerd (Abbot) on Feb 14, 2003 at 08:54 UTC

    package Tie::Substr; use base 'Exporter'; @EXPORT = 'substr'; sub TIESCALAR { bless [ $_[1], 0 ], $_[0]; } sub FETCH { $_[0][1] = 1; @{ $_[0][0] } == 2 and return substr($_[0][0][0], $_[0][0][1]); @{ $_[0][0] } == 3 and return substr($_[0][0][0], $_[0][0][1], $_[0][0][2]); @{ $_[0][0] } == 4 and return substr($_[0][0][0], $_[0][0][1], $_[0][0][2], $_[0][0][3]); die; } sub STORE { $_[0][1] = 1; @{ $_[0][0] } == 2 and return substr($_[0][0][0], $_[0][0][1]) = $_[1]; @{ $_[0][0] } == 3 and return substr($_[0][0][0], $_[0][0][1], $_[0][0][2]) = $_[1]; eval 'substr($foo, 0, 0, 0) = ""'; die; } sub DESTROY { $_[0]->FETCH unless $_[0][1]; } sub substr : lvalue { tie my $foo, 'Tie::Substr', \@_; $foo }
    Doesn't always give an error when used in void context (fails substr.t tests 120 and 121) and doesn't report the correct line numbers, because I was too lazy to wrap everything in evals. This substr of course doesn't support $[, of course, causing substr.t tests 8..14 to fail. But you shouldn't set $[ anyway. And the thing uses a tied variable, so don't expect lightening speeds.

    Apart from those small and insignificant differences, it's compatible with normal substr, but with an lvalue per substr call :)

    For testing, I used perl 5.8.0 with its own substr.t.

    Juerd
    - http://juerd.nl/
    - spamcollector_perlmonks@juerd.nl (do not use).
    

      Neat code! (Though a few named constants would make it a little more readable:)

      I had thought that when processing fixed-length records, rather than having to unpack every record into seperate scalars, operate upon them and then repack them, I could

      1. Set up a buffer
      2. Grab some Lvalue refs into the sections of the buffer
      3. Read or lvalue assign the record directly into that buffer.
      4. Operate upon the named (lvalue) sections.
      5. Write the record out.
      6. Repeat from 3 till done.

      Something like this: (only shows one field, but that's the perl limitation I encountered).

      #! perl -sw use strict; my $buf = ' 'x70; my $genus = \substr($buf, 40, 10); while( <DATA>) { substr($buf,0) = $_; $$genus = uc($$genus); print $buf; } #23456789012345678901234567890123456789012345678901234567890123456789 __DATA__ 00001 fox brown indian Vulpes Bengalensis 00002 fox blanford quick Vulpes Cana 00003 fox brown cape Vulpes Chama 00004 fox grey tree Vulpes Cinereoargenteus 00005 fox brown quick Vulpes Corsac 00006 fox brown tibetian Vulpes Ferrilata 00007 fox grey quick Vulpes Littoralis 00008 fox pale quick Vulpes Pallida 00009 fox brown quick Vulpes Ruppelli 00010 fox brown swift Vulpes Velox 00011 fox red quick Vulpes Vulpes 00012 fox brown quick Vulpes Zerda 00013 fox white arctic Alopex Lagopus 00014 fox Culpeo Dusicyon Culpaeus 00015 fox Grey Argentine Dusicyon Griseus 00016 fox Azara Dusicyon Gymnocercus 00017 fox small eared Dusicyon Microtis 00018 fox Sechuran Dusicyon Sechurae 00019 fox crab eating Dusicyon Thous 00020 fox Hoary Dusicyon Vetulus 00021 fox bat eared Octocyon Megalotis

      Output

      00001 fox brown indian VULPES Bengalensis 00002 fox blanford quick VULPES Cana 00003 fox brown cape VULPES Chama 00004 fox grey tree VULPES Cinereoargenteus 00005 fox brown quick VULPES Corsac 00006 fox brown tibetian VULPES Ferrilata 00007 fox grey quick VULPES Littoralis 00008 fox pale quick VULPES Pallida 00009 fox brown quick VULPES Ruppelli 00010 fox brown swift VULPES Velox 00011 fox red quick VULPES Vulpes 00012 fox brown quick VULPES Zerda 00013 fox white arctic ALOPEX Lagopus 00014 fox Culpeo DUSICYON Culpaeus 00015 fox Grey Argentine DUSICYON Griseus 00016 fox Azara DUSICYON Gymnocercus 00017 fox small eared DUSICYON Microtis 00018 fox Sechuran DUSICYON Sechurae 00019 fox crab eating DUSICYON Thous 00020 fox Hoary DUSICYON Vetulus 00021 fox bat eared OCTOCYON Megalotis

      Somewhat COBOLish, but possibly useful for efficiency, especially if long records are involved.

      Whilst it can be achieved using tie'd scalar as you've shown, as Elian pointed out above, the costs of tie pretty much negate the benefits of the idea.

      I think it's probably more efficient to set up HoA's something like

      my %fields = ( record_num =>[0,10], characteristic_1 =>[10,10], characteristic_2 =>[20,10], genus =>[30,10], subspecies =>[40,20], ); substr($buf, @{$fields{genus}}) = uc(substr($buf, @{$fields{genus}});

      but that's nowhere near as nice as the equivalent line above.

      unpacking to named scalars and then repacking them is much cleaner.

      I also hoped that creating an array of lvalue refs to a string instead of using split to create an array of 1 char scalars from that string, would allow me to treat a string as an array of char.

      my @str = map{ \substr($str, $_, 1) } 0..length($s)-1; $str[3] = 'b' if $str[7] eq 'N';

      This is a feature that I think perl deserves and really hope that it will be available in Perl6. It irks me everytime that I use

      my @c = split'',$str; $c[3] = 'b' if $c[7] eq 'N'; $str=join'',@c;

      I can do this with substr but using an array of lvalues would allow me the syntax I desire. It would still need to be wrapped into a tie'd scalar with the penalties that involves.

      With perl's current use of sigils, it isn't possible to add the syntactic sugar that would allow $str[n] to mean the nth char of $str as there is no way to distinguish this from accessing the nth element of the array @str. And there is no clean way to provide that syntax using overload or a tied scalar as far as I can tell.

      I'm hoping that the powers that be will allow this syntax once references to @str will always start with @ in perl 6. Then $str[3] and @str[3] will be clearly distinct things and then $str[3..7] could be the equivalent of substr($str, 3, 5) which I think would be much more usable as I often know the start and end positions and have to perform (unintuative) math to translate this into a start/length pair. I quite like the idea of $str[3,5,6,7] = $str[5,3,7,6]; as a similar concept to an array slice operation on a string, but I can see problems with it.

      The nice thing about not being Mr. Wall et al, is that you can have such random, speculative dreams without having to consider all the details:).


      Examine what is said, not who speaks.

      The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

        I'm hoping that the powers that be will allow this syntax once references to @str will always start with @ in perl 6. Then $str3 and @str3 will be clearly distinct things and then $str3..7 could be the equivalent of substr($str, 3, 5) which I think would be much more usable as I often know the start and end positions and have to perform (unintuative) math to translate this into a start/length pair. I quite like the idea of $str3,5,6,7 = $str5,3,7,6; as a similar concept to an array slice operation on a string, but I can see problems with it.
        Probably not. I don't think slices will get quite that much support, and it's distinctly possible that it'll be considered acceptable for slices to be done programmatically via iteration, rather than in a single delegated call to the variables. (Yeah, I know that it'd be cool to get your tie code handed the entire slice, but it's a lot of work and makes some other things more difficult)

        There'll be other tricks you can do that, while they don't solve this problem, can make other things nifty. Specifically for $foo[1][2][3][4]{z}, $foo will, if its tied, get handed the entire subscript list, and can do whatever it wants with them. In the common case it'll take the leftmost one and pass the rest on, but it doesn't have to--if $foo was a 4D array it could snag the first four and pass the rest, in this case the hash subscript, on to whatever it fetches.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-25 14:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found