Hi there, I intended to write a little module that would make a Perl variable read-only (without the help of tie() of course). I thought this would be easy, but not so obviously! I am using Attribute::Handlers to allow such a thing:
my $var : Readonly("I'm immutable"); In Readonly.pm: sub Readonly :ATTR(SCALAR) { my ($var, $data) = @_[2, 4]; # set value than make it readonly via XS $$var = $data; _ro_scalar($$var); } In Readonly.xs: void _ro_scalar (var) SV * var; PREINIT: struct ufuncs uf; MAGIC *m; CODE: uf.uf_val = &get_val; uf.uf_set = &set_val; uf.uf_index = 0; sv_magic(var, 0, 'U', (char*)&uf, sizeof(uf)); //--------> /* valus has been set: now change magic to let svt_set() croak */ m = mg_find(var, 'U'); if (m == NULL) printf("no magic\n"); else /* redefine */ m->mg_virtual->svt_set = &croak_set_val; set_val is functionally a no-op: I32 set_val (IV i, SV* s) { printf("SETTING: %i - %s\n", i, SvPV_nolen(s)); return 1; } croak_set_val: int croak_set_val (SV *s, MAGIC *mg) { Perl_croak("\nAttempt to set read-only variable"); return 1; } If the part on from '//--------->' in _ro_scalar() is not there, set_val() is already called from 'Readonly :ATTR(SCALAR)'. So basically I need two different svt_set function pointers: one for the initial setting of the value in Readonly.pm: $$var = $data; and one later (croak_set_val()) when the variable should really be read-only. Why is this so? In the following code: $$var = $data; _ro_scalar($$var); I would assume that the value is first set (which should be no problem since no magic has yet been attached to $$var) and then any attempt to re-set the value should invoke set_val. But to me it appears as though _ro_scalar() is invoked before assigning $data to $$var. My current workaround is to change mg_virtual->svt_set from &set_val() to croak_set_val() which works fine. But why do I have to do this? I also tried it with 'Reload :ATTR(SCALAR, BEGIN)' to let it happen at compile-time, but to no avail. Can anyone help? Tassilo -- $_=q!",}])(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({ pam{rekcahbus;})(rekcah{lrePbus;})(lreP{rehtonabus;})(rehtona{tsuJbus!; $_=reverse;s/sub/(reverse"bus").chr(32)/xge;tr~\n~~d;eval;