[Rio-pm] variável $^H no Perl 5.16

breno breno em rio.pm.org
Quinta Maio 31 12:07:02 PDT 2012


2012/5/31 Aureliano Guedes <guedes_1000 em hotmail.com>:
> Infelizmente isso foi como andar pra traz, na minha opinião. Eu não sabia
> disso, alias ainda estou preso no perl 5.14.
>

Por quê? Como o Stan claramente apontou, é uma variável SOMENTE para
uso interno. No código demonstrado ele quebrou encapsulamento 2 vezes
(uma ao mexer no $^H e outra ao futucar no namespace dos outros no %^H
- e escrevendo, ainda?! Stan malvado! Stan malvado!). A verdade é que
ele sabia disso e por isso deixou claro que só queria entender o que
estava acontecendo, e não reclamando da mudança. Se você não modifica
o fonte do perl ou depura internas do feature.pm, não deveria estar
usando nada disso. Se, pelo contrário, você está usando a API pública
(que por sinal não só é mais clara como tem menos caracteres
envolvidos):

   use feature 'say';

ou

   use feature ':5.10';

ou ainda:

   use v5.14;

tudo continua funcionando normalmente.

> Caso haja algum motivo para essa mudança, quando alguem descobrir me
> explique.
>

O Fernando tem razão e isso está relacionado com a nova feature (essa
sim pública) do 5.16, que ativa somente as features de uma determinada
versão. Mais especificamente, ao fato de que agora escrever "use
VERSAO" carrega as features daquela versão sem precisar carregar o
"feature.pm" (ou o strict.pm, no caso de >= 5.14)

Aos mais curiosos que quiserem continuar lendo, cuidado: algumas
entranhas serão expostas :)

Antes de começar vale lembrar que estamos falando de duas variáveis
diferentes, $^H (que contém dicas para o interpretador na forma de
flags) e %^H (para implementação de pragmas em escopo léxico,
armazenando valores de estado na optree).

A mudança aconteceu no final do ano passado. A idéia, até onde
entendi, é que o compilador agora reserva 3 bits no $^H para definição
dos chamados "feature bundles". Ou seja, se eu tenho "use v5.16" ele
vai passar a dica que, dentro daquele escopo léxico, somente
determinadas features estarão ativas. Quais são ativadas e quais não
são é o que fica nas chaves (privadas) 'feature_X' dentro do %^H.
Agora, portanto, o $^H precisa indicar ao interpretador se ele deve
usar as features definidas no %^H ou não. Se você não define, ele
entende como se não estivesse ativando feature alguma, independente do
que está no %^H. O valor é 0x1c000000 pq "ativa" 3 bits sequenciais em
binário (11100000000000000000000000000), usados para definir a máscara
padrão. Note, por exemplo, que se você colocar em $^H um outro valor
que também ative a flag de features, elas funcionarão normalmente via
%^H:

perl -e 'BEGIN { $^H |= 0x1e2aff0d; $^H{feature_say} = 1; }; say $^V'
v5.16.0

Mais especificamente, se você definir um bundle padrão diferente da
máscara, ele vai escolher o bundle conforme o valor posicional do
número deslocado 26 bits para a direita (o tamanho da máscara) em
@feature::hint_bundles, que hoje vale qw( default 5.10 5.11 5.15 ). Ou
seja, podemos fazer:

perl -e 'BEGIN { $^H |= 0x08000000; $^H{feature_say} = 1; }; say $^V'
v5.16.0

Já que 0x08000000 (hexa) é 1000000000000000000000000000 (binário) e
isso >> 26 vale 10 (2, em decimal), indicando que vai usar as features
do $hint_bundles[2], ou seja, 5.11. Analogamente, não ter a flag
definida é o mesmo que definir $^H{feature_say} com a máscara
'default' (000) ativa.

Na prática, o feature.h (também gerado pelo regen/feature.pl) usa
essas flags para definir quais features estão ativas em um determinado
momento (macros FEATURE_BUNDLE_CUSTOM e CURRENT_FEATURE_BUNDLE). Se
você não usar um feature bundle, ele assume o default, que no momento
é ativar apenas a feature 'array_base' (independente do que esteja no
%^H). Outra interessante consequência dessas modificações é permitir
que uma nova versão do perl desative determinada feature. Por exemplo,
escrever "use v5.16" desativa a variável $[ (disponível em versões
anteriores). Caso realmente precise usá-la, basta fazer "use v5.16;
use feature qw(array_base);"

Quem quiser ver as modificações, estão em torno do commit 23a52d6b1d1.
Os arquivos pertinentes - lib/feature.pm e feature.h - são gerados
pelo regen/feature.pl, chamado via regen.pl.

Espero ter ajudado :)

[]s

-b


Mais detalhes sobre a lista de discussão Rio-pm