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

I was looking for a way to lock a SCALAR, soo the user won't be able to change it's value.

I know that exits constant functions at Perl:

sub my_const() { 123 }
But this really need to be done in the SCALAR, and I haven't found anything about that!.

Graciliano M. P.
"Creativity is the expression of the liberty".

Replies are listed 'Best First'.
Re: There is a way to LOCK a SCALAR?
by Zaxo (Archbishop) on Dec 18, 2003 at 19:27 UTC
    $ perl -e'$foo=\"I am immutable"; $$foo="fie!";' Modification of a read-only value attempted at -e line 1. $

    Is that what you want?

    Update: Better yet,

    $ perl -e'*foo=\"I am immutable"; $foo="fie!";' Modification of a read-only value attempted at -e line 1. $

    After Compline,
    Zaxo

      And for lexical variables, you can use the Lexical::Alias module:

      $ perl use Lexical::Alias 'alias_r'; my $s; alias_r \"I am immutable", \$s; $s = "fie!"; ^D Modification of a read-only value attempted at - line 6. $

      Update: I don't think it's documented behaviour. It just happens to work, probably because of the way the module is implemented (I am by no means a perlguts expert - and I haven't studied the source). Here's a snippet from the module documentation:

      alias_r(\src, \dst)

      Makes dst (which must be lexical) an alias to src (which can be either lexical or a package variable). src and dst must be the same data type (scalar and scalar, array and array, hash and hash). This is not exported by default.

      Of course you can play by the rules:

      [...] my $s; { local $tmp; *tmp=\"I am immutable"; alias_r \$tmp, \$s; } [...]
Re: There is a way to LOCK a SCALAR?
by duff (Parson) on Dec 18, 2003 at 19:25 UTC

    Did you check CPAN for a module? If there isn't one, you could write one yourself to use the tie mechanism to subvert changing the value of the scalar. perldoc perltie

    Here's a quick implementation (untested):

    #!/usr/bin/perl package ConstScalar; sub TIESCALAR { my $class = shift; my $val = shift; return bless \$val, $class } sub STORE { } sub FETCH { my $self = shift; return $$self; } package main; my $pi; tie $pi, 'ConstScalar', 3.14159265358979323846; print "$pi\n"; $pi = 5; # no effect print "$pi\n";
      But the user still can do an UNTIE!
      package main; my $pi; tie $pi, 'ConstScalar', 3.14159265358979323846; print "$pi\n"; untie $pi ; #### NOW AS A NORMAL SCALAR $pi = 5; # effect! print "$pi\n";
      But thanks for the idea! ;-P

      Graciliano M. P.
      "Creativity is the expression of the liberty".

        This is perl mate, no matter what you do, it is extremely likely that anyone else writing code that uses it will be able to basically anything they want to it. Theres no harm in trying to create some guidelines and trying to enforce them at a basic level, but if they don't want to deal with them they can find a way around them. Think of it like 'use strict', its mostly helpful to catch mistakes but if you really need to do something it won't allow you can turn it off.
Re: There is a way to LOCK a SCALAR?
by ysth (Canon) on Dec 18, 2003 at 19:50 UTC
    With 5.8.0, there was added a builtin way to do this:
    Internals::SvREADONLY($your_scalar, 1);
    As the name reflects, it was added for internal use (by the restricted hash feature). Don't depend on it staying there or under that name in future perl releases.
Re: There is a way to LOCK a SCALAR?
by Juerd (Abbot) on Dec 18, 2003 at 20:08 UTC

    The user? The user doesn't use Perl, the developer uses Perl.

    Why do you want a scalar and not a sub?

    Anyway, others have already suggested assigning a reference to a literal (a literal is a readonly scalar variable, really!) to a typeglob, but there is a way to turn the readonly flag on during runtime, using xmath's Spy module, which unfortunately he never finished.

    use Spy; my $foo = 123; spy(\$foo)->readonly = 1; $foo++; # Modification of a read-only value attempted at - line 5.
    Note that with Spy you can do evil things. Some variables are supposed to always be read-only. Like undef (${\undef}), true (${\!0}) and false (${\!1}). It's fun to make them writable, though, so feel free to experiment.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      I just have looked the module Spy, and the author have implemented the module B::More, that can set the readonly flag.! Thanks for the tip.

      But I saw that already exists a module for that, Internals, that let you handle this things. Thanks monks!

      Graciliano M. P.
      "Creativity is the expression of the liberty".

      > The user? The user doesn't use Perl, the developer uses Perl.

      Duh! How a bout another Perl developer using the enverioment that I'm developing?!

      Well, I say that because I work building softwares for developers, not for end users.

      Graciliano M. P.
      "Creativity is the expression of the liberty".

        Duh! How a bout another Perl developer using the enverioment that I'm developing?! Well, I say that because I work building softwares for developers, not for end users.

        It is very un-perlish to lock something. You don't know what creative solutions others invent using your code, and I think it's better to free your code and let others use your code much the way you use Perl. Locking a scalar makes no sense. It's probably a sign that you need another "user" interface (API). Maybe you want OO with a protected property. Perhaps you just need a simple function that returns a value. But I seriously doubt you really need a scalar that is readonly.

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: There is a way to LOCK a SCALAR?
by davido (Cardinal) on Dec 19, 2003 at 01:20 UTC
    I know you're nervous about someone untieing a tied scalar, but I couldn't help but at least look into CPAN to see what I could turn up anyway.

    Tie::Scalar::RestrictUpdates is the first thing I found. Look at the POD, and you'll see that when you tie it, you tell the class how many times you'll allow that scalar to be updated or changed. After that number is reached (could even be 1 if you want), the scalar can no longer be modified.

    You're worried that someone would untie it, but realistically there isn't much someone couldn't do if he/she wanted. Someone could even completely rewrite your code, or abandon it altogether because of inflexibility. You can't really stop a developer from having his way with your code, if he has access to it. You may contrive an elaborate means of preventing a variable from being changed by a developer, but you can't lock him out of your code entirely, while at the same time giving him access to your code.


    Dave

Re: There is a way to LOCK a SCALAR?
by BrowserUk (Patriarch) on Dec 18, 2003 at 19:40 UTC

    Update: As sauoq++ and duff++ point out, my brain was in neutral:(

    The are several ways of approximating it, but the easiest to really create a simple, readonly scalar is Scalar::Util::readonly().

    It is even part of the standard distribution in the most recent versions.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

      How will that help? Scalar::Util::readonly() is for checking whether a scalar is readonly, not for creating a readonly scalar.

      I'd second the method that Zaxo suggests in his update. That's the "old-fashioned" way to create constants. Here's how to use Scalar::Util::readonly() to prove it works nicely...

      perl -MScalar::Util=readonly -le '*f = \"foo"; print readonly($f)' 8388608

      -sauoq
      "My two cents aren't worth a dime.";
      

      Doesn't Scalar::Util::readonly() just tell you if the scalar is readonly or not? I.e., you can't create a readonly scalar from it.

Re: There is a way to LOCK a SCALAR?
by indigo (Scribe) on Dec 19, 2003 at 18:30 UTC
    This is real easy to do.
    • Copyright your code
    • Hire a DMCA lawyer
    • Sue anyone who "reverse engineers" this scalar

    But seriously...in Perl, these things are best handled as a matter programming policy, not language mechanics.