Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

constant vector

by wbirkett (Acolyte)
on Aug 01, 2017 at 10:57 UTC ( [id://1196430]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, Perl Monks- I'm looking for a better way to make a constant vector. Here is my current approach:
# constants use constant D50 => [96.42, 100, 82.49]; # ICC D50 XYZ
At this point, the vector elements can be changed, so I make them read-only using the 'Internals' module.
use Internals qw(SetReadOnly); # set constant array elements to be read-only for (@{(D50)}) {SetReadOnly(\$_)}
This seems to work fine, but now I read from 'Internals.pod':

'In practice people have come to depend on these over the years, despite being historically undocumented, so we will provide some level of forward compatibility for some time. Nevertheless you can assume that any routine documented here is experimental or deprecated and you should find alternatives to their use.'

So, is there a better alternative for making a constant vector?

Replies are listed 'Best First'.
Re: constant vector (updated x2)
by haukex (Archbishop) on Aug 01, 2017 at 11:07 UTC

    Either replace

    use constant D50 => [96.42, 100, 82.49];

    with

    sub D50 () { [96.42, 100, 82.49] }

    because this will do the same thing as constant (it creates an inlineable sub), but the sub will return a new arrayref every time, or do this:

    use Readonly; Readonly::Array my @D50 => (96.42, 100, 82.49); print $D50[0], "\n"; $D50[0]++; __END__ 96.42 Modification of a read-only value attempted at ...

    But I've also had some strange problems with Readonly (Update: link), so my approach nowadays to constants is simpler: make their names uppercase and assume people know this convention. (But I did need some time to get used to this idea, since I do tend to code defensively.)

    Update: Sorry, B::Deparse seems to say that I was incorrect and the sub I showed does not seem to get inlined. Will update when I know more. Update 2: So testing seems to show the equivalent code to what constant is doing (with the same problem that the array may be modified!) is this:

    BEGIN { my $x = [96.42, 100, 82.49]; *D50 = sub () { $x }; }

    While other forms, such as simply my $x = [96.42, 100, 82.49]; sub D50 () { $x }, don't get inlined. And I believe the reason sub D50 () { [96.42, 100, 82.49] } doesn't get inlined is exactly what I said above: it constructs a new arrayref on each call, thereby it is not constant. I made this mistake because of the equivalence of use constant FOO => "bar"; and sub FOO () { "bar" }. As LanX points out in the reply, my first suggestion will still work, but just not be as fast as an inlined sub. As another possible alternative, note that constant also allows list constants:

    use constant D50 => (96.42, 100, 82.49);

    Which you then have to access like so: (D50)[0]

    Update 3: While it's fairly well known that the output of B::Deparse can be inaccurate, I think it's still noteworthy that it is misleading in this case in particular.

    $ perl -MO=Deparse -e 'use constant X=>[1]; print X->[0]++; print X->[ +0]++' use constant ('X', [1]); print [1]->[0]++; print [1]->[0]++; $ perl -le 'use constant X=>[1]; print X->[0]++; print X->[0]++' 1 2
      > Sorry, B::Deparse seems to say that I was incorrect and the sub I showed does not seem to get inlined. Will update when I know more.

      I think that's because inlining rejects dynamic values, you'd need to always return the same array ref, which of course contradicts your intention.

      But your idea still works if you don't care about the speed benefit of inlining.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

Re: constant vector
by LanX (Saint) on Aug 01, 2017 at 11:13 UTC
      The 'Readonly' module uses the now-deprecated 'Internals' module to set/clear the scalar read-only flag.
        The 'Readonly' module uses the now-deprecated 'Internals' module to set/clear the scalar read-only flag.

        Well, so does the core pragma constant, but it does seem like P5P might change the API in the future. For reference, here is the discussion that led to the creation of Internals.pod.

        > uses the now-deprecated Internals module to set/clear the scalar read-only flag.

        well it might currently use the "Internals" module.

        IMHO Readonly and constant are far too basic to become deprecated soon.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Log In?
Username:
Password:

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

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

    No recent polls found