2010-06-25 2 views
5

Ci-dessous mon code (ne vous inquiétez pas, il y a un USUW en haut du module)Quelqu'un peut-il m'expliquer cette exception en lecture seule?

Je teste si une référence à un tableau est en lecture seule, et si tel est le cas, alors je suis le copier dans un autre tableau ref. Les tests montrent que le tableau n'est pas en lecture seule, mais lorsqu'il s'exécute, il échoue avec cette erreur. (Pour ceux qui ne connaissent pas avec moi ou Smart::Comments --those ### sont Smart::Comments.)

### readonly($arg_ref) : readonly($arg_ref) 
### readonly(@$arg_ref) : readonly(@$arg_ref) 
my @ro = map { readonly($_) } @$arg_ref; 
### @ro 
if (readonly $arg_ref) { 
    $arg_ref = [ @$arg_ref ]; 
} 
return map { my $val = shift @$arg_ref; 
      $_ => $val 
      } @_ 
      ; 

Ceci est la sortie que je reçois:

### readonly($arg_ref) : 0 
### readonly(@$arg_ref) : 0 

### @ro: [ 
###  0, 
###  0, 
###  0, 
###  0, 
###  0 
###  ] 

Mais voici l'erreur:

Modification of a read-only value attempted at ....pm line 247. 

(247 est:

return map { my $val = shift @$arg_ref; 

)

Quelqu'un connaît-il ce problème? Nous utilisons Perl 5.8.7. Une idée sur la façon de l'aborder?

+0

D'où vient le symbole 'readonly'? Je ne pense pas que le module Readonly en fournisse un. – Ether

+0

@Ether c'est ['Scalar :: Util :: readonly'] (http://search.cpan.org/perldoc?Scalar::Util#readonly) – Axeman

+0

Comment' $ arg_ref' obtient-il sa valeur? –

Répondre

0

Il ne ressemble pas le résultat de Scalar::Util::readonly peut être confiance utilisé comment vous voulez l'utiliser. Témoin:

perl -MScalar::Util=readonly -MReadonly -wle' 
    Readonly my $arg_ref => [ qw(a b c)]; 
    print readonly $arg_ref; 
    $arg_ref = 1;' 

impressions:

0 
Modification of a read-only value attempted at -e line 1. 

(Testé sous perl5.8.8 avec Readonly 1,03, Scalar :: Util 1,23)

+1

C'est dommage - et dans un module de base aussi ... – Axeman

+0

Je viens d'exécuter le test ci-dessus sur perl5.12.1 et j'ai obtenu le même résultat. :( – Ether

+0

C'est parce que Readonly et readonly sont des choses différentes. :) Voir ma réponse pour pourquoi. –

2

Si la référence de DBI::fetchrow_arrayref revient en lecture seule, en essayant de le remplacer ne sera pas utile: la référence est en lecture seule, pas le thingie (dire, le tableau avec des valeurs de colonne). Faites votre propre copie à la source si vous avez besoin de mises à jour destructrices, par exemple.,

my $arg_ref = [ $sth->fetchrow_array ]; 
+0

@Axeman Mais si '$ arg_ref' peut être en lecture seule, les opérations destructives telles que' shift' ne conviennent pas, ce que vous avez observé. –

+0

en effet et une partie de la programmation résout des problèmes. Une file d'attente est * transportable * un "flux de liste" ne l'est pas à moins que vous ne souhaitiez rassembler une combinaison de liste et d'emplacement actuel dans la liste. Mais cela ne ferait jamais plus qu'une bonne vieille file d'attente que vous obtenez gratuitement avec un tableau Perl. Maintenant, je pourrais * toujours * le copier, mais un "weenie de performance et d'efficacité" comme moi obtient des ruches pensant ne pas faire seulement ce qui est nécessaire. – Axeman

+0

@Axeman Réponse mis à jour de manière destructive, même! –

1

Readonly et readonly sont différents. (Remarquez la R majuscule et minuscule r ;-).)

Voir la documentation Scalar::Util pourquoi cela est vrai:

readonly SCALAR

Returns true if SCALAR is readonly.

sub foo { readonly($_[0]) } 
$readonly = foo($bar);    # false 
$readonly = foo(0);     # true 

Ceci est plus sur les alias (tels que ceux qui sont passés via des boucles foreach ou . @_, et non le module Readonly

+0

Alors, est-il possible de vérifier si une variable a été déclarée Readonly avec un R majuscule? – Ether

+2

Readonly :: XS et l'implémentation XS de readonly reposent tous deux sur le même indicateur (SvREADONLY), ils doivent donc être les mêmes (si vous utilisez les versions XS, ce que vous devriez faire). Je sens un bogue ici. –

+1

@Ether, IIUC, 'ref (tied (A_VARIABLE)) = ~/^ Readonly :: /' devrait faire l'affaire, et vous aurez envie de revenir à vérifier 'Scalar :: Util :: readonly' si ce contrôle c'est faux. – pilcrow

1

Je pense que je l'ai pensé à Robert P avait raison, mais il n'obtenu la moitié de la réponse. Readonly et readonly faire des choses différentes si elles devraient faire la même chose, le fait qu'ils ne sont pas un bug, je vais essayer d'expliquer ce qui se passe

Readonly a deux implémentations pour: un scalaires (Readonly::XS) qui est basée sur le drapeau SvREADONLY et un (Readonly :: Scalar) en fonction des liens qui émule le drapeau SvREADONLY.

readonly a également deux implémentations, une en Perl (qui fait l'auto-affectation et vérifie si elle déclenche une exception ou non), et une en XS (toujours basée sur le drapeau SvREADONLY).

Il y a 4 combinaisons possibles, et malheureusement celle qui est la plus commune (pure perl Readonly et XS readonly) est la seule qui ne fonctionne pas comme annoncé.

Voici le crux: sub Readonly::Readonly n'utilise en fait pas Readonly::XS, seulement sub Readonly::Scalar. Ceci est probablement un bug. readonlycorrectement signale que la variable n'est pas une variable en lecture seule: sa lecture est faussée par un lien.

C'est Readonly qui est en faute ici IMO, il devrait faire la bonne chose quand il peut et documenter quand il ne peut pas. En ce moment, il ne fait aucun de ceux-là.

+0

De mon point de vue, il n'y a aucun problème avec Readonly, nous ne l'avons même pas installé dans notre environnement. La seule chose qui m'inquiète est l'impossibilité de 'Scalar :: Util :: readonly' de me dire qu'un tableau référençant une référence de tableau est en lecture seule jusqu'à ce que j'essaie de passer dessus. – Axeman

+0

En fait, il semble que ce n'est pas le tableau * reference * n'est pas en lecture seule, mais le tableau auquel il se réfère. Une différence subtile mais importante. –

+0

Ce comportement contredit clairement la documentation - il est dit que quand Readonly :: XS est installé, il est utilisé dans tous les cas pour les scalaires (mais pas pour les tableaux et les hachages). Bummer. (Alors, qui va déposer un bug, ou encore mieux soumettre un patch?) :) – Ether