r2 - 02 Jul 2009 - RonaldoLima
NOME
constant - pragma de Perl para declarar constantesSINOPSE
use constant PI => 4 * atan2(1, 1);
use constant DEBUG => 0;
print "Pi equals ", PI, "...\n" if DEBUG;
use constant {
SEC => 0,
MIN => 1,
HOUR => 2,
MDAY => 3,
MON => 4,
YEAR => 5,
WDAY => 6,
YDAY => 7,
ISDST => 8,
};
use constant WEEKDAYS => qw(
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
);
print "Today is ", (WEEKDAYS)[ (localtime)[WDAY] ], ".\n";
DESCRIÇÃO
Este pragma irá declarar um símbolo como uma constante com o valor dado. Quando você declara uma constante comoPI utilizando o método mostrado acima, cada computador que seu programa seja executado poderá ter tantos dígitos quanto o computador possa utilizar. O seu programa será mais fácil de ler, mais fácil de ser (corretamente) mantido.
Quando uma constante é utilizada em uma expressão, Perl a substitui com seu valor em tempo de compilação, e pode então optimizar a expressão. Em particular, qualquer bloco de código como if (CONSTANTE) será optimizada se a constante for falsa.
NOTAS
Como em todas as diretivasuse, a definição de uma constante acontece em tempo de compilação. Então, é incorreto colocar a declaração de uma constante dentro de uma condicional (como if ($foo) { use constant ... }).
Constantes definidas utilizando este módulo não podem ser interpoladas em variáveis como strings normais. Entretanto, pode ser concatenada:
print "Pi equals PI...\n"; # ERRADO: não expande "PI"
print "Pi equals ".PI."...\n"; # certo
Mesmo que uma referência possa ser declarada como uma constante, a referência pode apontar para um dado que pode ser modificado, como mostra este código:
use constant ARRAY => [ 1,2,3,4 ];
print ARRAY->[1];
ARRAY->[1] = " be changed";
print ARRAY->[1];
Dereferenciar incorretamente uma referência declarada como constante (como utilizar um array em uma constante cuja referência aponte para um hash, ou vice versa) será percebido em tempo de compilação.
As constantes pertencem ao pacote que elas são definidas. Para referenciar a uma constante definida em outro pacote, especifique o pacote, como em Algum::Pacote::CONSTANT. Constantes podem ser exportadas por módulos, e também podem ser chamadas como métodos de instância ou classe. Isto é, como Algum::Pacote->CONSTANT ou como $obj->CONSTANT onde $obj é uma instância de Algum::Pacote. Subclasses podem definir suas próprias constantes e sobrescrever aquelas definidas em sua classe base.
A utilização de todas letras maiúsculas para nomes de constantes é apenas uma mera convenção, porém é recomendada para ajudar a prevenir colisões com outras palavras reservadas e nomes de funções. Nomes de constantes devem começar com uma letra ou um '_'. Nomes que iniciam com dois '_' são reservados. Algumas más escolhas para nomes irão gerar avisos, caso warnings esteja habilitado em tempo de compilação.
Listas constantes
Constantes podem ser listas de mais (ou menos) de um valor. Uma constante com nenhum valor será interpretado comoundef no contexto escalar. Note que constantes com mais de um valor não retornarão seu último valor no contexto escalar como esperado. Atualmente é retornado o número de valores, porém isto pode ser modificado no futuro. Não utilize constants com múltiplos valores em contexto escalar.
NOTA: Isto implica em que a expressão que define o valor de uma constante seja executada em contexto de lista. Isto pode produzir algumas surpresas:
use constant TIMESTAMP => localtime; # Errado!
use constant TIMESTAMP => scalar localtime; # certo
A primeira linha acima atribui a TIMESTAMP como uma lista de 9 elementos, como retornado por localtime() no contexto de listas. Para atribuir o valor retornado por localtime() em um contexto escalar, deverá ser explicitamente utilizado scalar.
Listas constantes são listas, não arrays. Para iterar ou parti-las, elas devem ser colocadas entre parênteses:
my @workdays = WEEKDAYS[1 .. 5]; # Errado!
my @workdays = (WEEKDAYS)[1 .. 5]; # certo
Definindo múltiplas constantes em uma vez
Ao invés de escrever múltiplas chamadas ause constant, você pode definir múltiplas constantes em um único comando informando, ao invés de um nome de constante, uma referência para um hash onde suas chaves são os nomes das constantes a serem definidas. Obviamente, todas constantes definidas utilizando este método devem ter um único valor.
use constant {
FOO => "A single value",
BAR => "This", "won't", "work!", # Erro!
};
Isto é fundamentalmente uma limitação imposta pela maneira que os hashes são construídos em Perl. As mensagens de erros produzidas quando isto acontece serão bem crípticas -- na pior das hipóteses não haverá alguma, e você irá apenas verificar que algo está errado.
Quando você definir diversas constantes, você não poderá utilizar os valores de outras constantes definidas na mesma declaração. Isto acontece porque o pacote que está executando a chamada não conhece constante alguma até que o comando esteja finalizado.
use constant {
BITMASK => 0xAFBAEBA8,
NEGMASK => ~BITMASK, # Erro!
};
Constantes mágicas
Valores mágicos e referências podem ser transformadas em constantes em tempo de compilação, permitindo coisas interessantes como estas. (Estes números de erros não são totalmente portáveis.)
use constant E2BIG => ($! = 7);
print E2BIG, "\n"; # something like "Arg list too long"
print 0+E2BIG, "\n"; # "7"
Você não pode produzir uma constante tied apenas informando uma escalar tied como valor. Contudo, referências para variáveis tied podem ser utilizadas como constantes sem problema algum.
NOTAS TÉCNICAS
Na implementação atual, constantes escalares são atualmente subrotinas inline. Como na versão 5.004 do Perl, a constante escalar apropriada é inserida diretamente no lugar de alguma chamada de subrotina, porém salvando o overhead de uma chamada de subrotina. Veja Constant Functions in the perlsub manpage para detalhes de como e quando isto acontece. Nos raros casos onde você necessita descobrir em tempo de execução se uma constante particular foi declarada através de algum módulo, você pode examinar o hash%constant::declared nesta função. Se o nome da constante não inclui um pacote, o pacote corrente está sendo utilizado.
sub declared ($) {
use constant 1.01; # Não omita isto!
my $name = shift;
$name =~ s/^::/main::/;
my $pkg = caller;
my $full_name = $name =~ /::/ ? $name : "${pkg}::$name";
$constant::declared{$full_name};
}
BUGS
Na versão atual do Perl, listas constantes não são inline e alguns símbolos podem ser redefinidos sem gerar um aviso. Não é possível ter uma subrotina ou uma palavra chave com o mesmo nome de uma constante, no mesmo pacote. Isto é provavelmente uma boa coisa (Good Thing(tm)). Uma constante com o nome desta listaSTDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG não é permitida em lugar algum a não ser no pacote main::, por razões técnicas.
Diferentemente de constantes em algumas linguagens, estas não podem ser sobrescritas via linha de comando ou variáveis de ambiente.
Você pode ter problemas caso você utilize constantes em um contexto onde automaticamente interprete palavras não chaves como strings (isto vale também para qualquer subrotina). Por exemplo, você não pode utilizar $hash{CONSTANT} porque CONSTANT irá ser interpretada como uma string. Utilize $hash{CONSTANT()} ou $hash{+CONSTANT} para prevenir que a constante seja interpretada de maneira errada. Do mesmo modo que o operador => transforma a palavra à sua esquerda em string, você deve utilizar CONSTANT() => 'value' (ou utilize simplesmente uma vírgula no lugar da seta) ao invés de CONSTANT => 'value'.

