Escopo (computação): diferenças entre revisões

Conteúdo apagado Conteúdo adicionado
Alch Bot (discussão | contribs)
Linha 1:
Em [[Ciência da Computação]] '''escopo''' é um contexto delimitado em que os valores e expressões estão associadas. Várias linguagens de programação têm vários tipos de escopos. O tipo de escopo determina o tipo de entidades que podem conter e como isso afeta eles-ou sua [[Semântica formal|semântica]]. Normalmente, o escopo é utilizado para definir o grau de ocultação da informação, isto é, a visibilidade e acessibilidade das variáveis em diferentes partes do programa. Escopos podem:
 
* Conter [[Declaração (informática)|declarações]] ou definições de [[identificador|identificadores]]es;
* Conter [[Instrução (computação) |instruções]] e/ou [[Expressão (computação)|expressões]], que definem um [[algoritmo]] executável ou parte dele;
* aninhar ou ser aninhados.
 
Um [[Espaço de nomes|espaço de nomes]] é um escopo que usa a natureza envolvente do escopo para agrupar identificadores relacionados logicamente sob um identificador único. Assim, os escopos podem afetar a [[resolução de nomes]] pelo seu conteúdo.
 
[[Variável (programação)|Variáveis são associadas com os escopos]]. Diferentes tipos de escopo afetam como variáveis locais são [[Vinculação de nomes (computação)|vinculadas]]. Isto tem conseqüências diferentes dependendo se a linguagem tem escopo estático (léxico) ou escopo dinâmico.
 
== História ==
 
O escopo léxico foi utilizado pela [[linguagem de programação Algol|ALGOL]] e foi seguida pela maioria das outras linguagens de programação, desde então. O escopo estático (ou léxico) também foi introduzida em LISP 1.5 (Através do dispositivo de [[Funarg]] (Functional argument) desenvolvido por [[Steve Russell]], trabalhando com [[John McCarthy]]). O interpretador Lisp original (1960) e os primeiros [[Lisp (linguagem de programação)|Lisps]] usavam escopo dinâmico, mas os descendentes das linguagens de escopo dinâmico muitas vezes adotaram o escopo estático; A linguagem [[Common Lisp]] tem tanto escopo estático quanto dinâmico, enquanto [[Scheme]] usa exclusivamente escopo estático. [[Perl]] é uma outra linguagem com escopo dinâmico, que acrescentou escopo estático mais tarde. Linguagens como o [[Pascal (linguagem de programação)|Pascal]] e [[C (linguagem de programação)|C]] sempre tiveram escopo léxico, uma vez que ambas são influenciadas pelas idéias surgidas com a [[ALGOL 60]]<ref name="sebesta">{{Citar livro|nome=Robert W.|sobrenome=Sebesta|título=Concepts of Programming Languages|subtítulo=|idioma=inglês|edição=7ª|local=Boston|editora=Addison Wesley|ano=2006|páginas=228-239|volumes=|volume=|id=ISBN 0-321-33025-0}}</ref> (embora C não não inclua funcões aninhadas lexicamente).
 
Linha 26 ⟶ 25:
{ // escopo do bloco mais interno por declarações executadas condicionalmente
// (Note que, ambos escopos de bloco estão sem nome.)
...
}
}
Linha 39 ⟶ 38:
O escopo léxico ou estático foi introduzido pela linguagem [[ALGOL 60]]. O escopo é assim denominado, porque pode ser determinado estaticamente, ou seja, antes da execução.<ref name="sebesta" /> O escopo léxico define o escopo em termos da estrutura léxica do programa.<ref name="guezzi">{{Citar livro|autor=GUEZZI, Carlo; JAZAYERI, Mehdi|título=Programming Languages Concepts|subtítulo=|idioma=inglês|edição=3ª|local=New York|editora=John Wiley & Sons|ano=1998|páginas=52|volumes=|volume=|id=ISBN 0-471-10426-4}}</ref> Com escopo léxico, um nome sempre se refere ao seu ambiente léxico (mais ou menos) local. Esta é uma propriedade do texto do programa e é feita independente da pilha de chamadas em tempo de execução pela implementação da linguagem. Ou seja, O escopo léxico de uma declaração é a parte do texto do programa, onde a utilização do identificador é uma referência a essa declaração particular do identificador.<ref name="pratt">{{Citar livro|autor=PRATT, Terrence W.; ZELKOWITZ, Marvin V|título=Programming Languages|subtítulo=Design and Implementation|idioma=inglês|edição=4ª|local=Upper Saddle River, New Jersey|editora=Prentice hall|ano=2001|páginas=364|volumes=|volume=|id=ISBN 0-13-027678-2}}</ref> Pelo fato de esta correspondência só exigir a análise do texto do programa estático, este tipo de delimitação de escopo é também chamado de escopo estático.
 
O escopo estático é padrão em todas as linguagens baseadas na [[ALGOL]], tais como [[Pascal (linguagem de programação)|Pascal]], [[Ada (linguagem de programação)|ADA]] e [[C (linguagem de programação)|C]], bem como em linguagens funcionais modernas, tais como [[ML (linguagem de programação)|ML]] e [[Haskell (linguagem de programação)|Haskell]], pois permite que o programador possa elaborar raciocínios sobre valores, parâmetros e referências a objetos (ou seja, variáveis, constantes, funções etc), como substituições de nome simples. Isso torna muito mais fácil fazer o código modular e se raciocinar sobre ele, já que a estrutura local de nomeação pode ser entendida isoladamente. Devido ao entendimento de que o escopo estático torna a programação mais confiável, há uma tendência a se rejeitar o escopo dinâmico..<ref name="maclennan">{{Citar livro|autor=MACLENNAN, Bruce J|título=Principles of Programming Languages|subtítulo=Design, Evaluation and Implementation|idioma=inglês|edição=3ª|local=Oxford|editora=Oxford University Press|ano=1999|páginas=109-111|volumes=|volume=|id=ISBN 0-19-511306-3}}</ref>. Em contraste, o escopo dinâmico força o programador a antecipar todos os possíveis contextos dinâmicos nos quais o código do módulo pode ser invocado.
 
Por exemplo, considere o seguinte fragmento de programa em Pascal:
Linha 76 ⟶ 75:
Além disso, poderia haver ainda outro procedimento C declarado no programa, fora do processo B. O lugar exato no programa em que C é chamado então determina qual procedimento C é chamado, e isto é precisamente análogo ao escopo de variáveis.
 
[[ImagemFicheiro:Escopo.png|thumb|500px|Cadeias estática e dinâmica após a chamada dos procedimentos A->B->D->CA→B→D→C]]
Uma das técnicas mais comuns de implementação do escopo estático é a cadeia estática.<ref name="pratt2">{{Citar livro|autor=PRATT, Terrence W.; ZELKOWITZ, Marvin V|título=Programming Languages|subtítulo=Design and Implementation|idioma=inglês|edição=4ª|local=Upper Saddle River, New Jersey|editora=Prentice hall|ano=2001|páginas=339-340|volumes=|volume=|id=ISBN 0-13-027678-2}}</ref> Esta cadeia mantém ponteiros em cada procedimento apontados para o pai estático. Quando uma referência a uma variável é encontrada em um procedimento, primeiro se procura no registro de ativação deste procedimento. Caso não se encontre a variável, se busca no próximo pai estático e assim por diante. No exemplo da figura ao lado (relativo ao código de exemplo em Pascal acima), após a chamada dos procedimentos A, B, D e C respectivamente, caso haja uma referência no procedimento C sobre a variável K, a variável usada é a que está declarada no procedimento B (K real).
 
Implementações corretas do escopo estático em linguagens com [[Subrotina aninhada|funções aninhadas]] de primeira classe (ou seja, funções que podem ser passadas como argumentos) podem ser sutis, pois se exige que cada valor da função leve com ele um registro dos valores das variáveis das quais ele depende (o par da função e deste ambiente é chamado de [[Closure|closure]]). Dependendo da implementação e da [[Arquitetura de computadores|arquitetura do computador]], a pesquisa de variável ''pode'' ficar ligeiramente ineficiente quando [[Subrotina aninhada|funções aninhadas]] léxicamente em muitos níveis são usadas. No entanto, para cada função aninhada que não se refere aos valores da ''variável'' dentro de seu encapsulamento, mas apenas aos parametros diretos e variáveis imediatamente locais, a posição relativa de cada valor pode ser conhecida em [[tempo de compilação]]. Nenhuma sobrecarga é, portanto efetuada com esse tipo de função aninhada. Naturalmente, o mesmo se aplica aos programas específicos, onde funções aninhadas não são utilizados e, claro, para programas escritos em uma linguagem onde as funções aninhadas não estão disponíveis (como a linguagem C).
 
=== Escopo dinâmico ===
 
Com escopo dinâmico, cada identificador tem uma [[Pilha (informática)|pilha]] global de [[vinculação (computação)|vinculações]]. Introduzindo uma variável local com o nome de ''x'' empilha uma vinculação na pilha global ''x'' (que pode estar vazia), que estará desempilhada quando o fluxo de controle deixar o escopo. Avaliar ''x'' em qualquer contexto sempre produz a vinculação mais ao topo. Em outras palavras, um identificador global refere-se ao identificador associado com o ambiente mais recente. Note-se que isso não pode ser feito em tempo de compilação, porque a pilha de vinculação só existe em tempo de execução, razão pela qual este tipo de delimitação é chamado de ''escopo dinâmico''.
 
Geralmente, alguns [[Bloco (computação)|blocos]] são definidos para criar vinculações cujo tempo de vida útil é o tempo de execução do bloco; isso adiciona algumas funcionalidades do escopo estático para o processo de escopo dinâmico. No entanto, como uma seção de código pode ser chamada de diferentes locais e situações, pode ser difícil determinar desde o início quais vinculações serão aplicadas quando uma variável for utilizada (ou se a sua existência naquele contexto). Isto pode ser benéfico. a aplicação do princípio do menor conhecimento sugere que o código evita, dependendo de razões para (ou circunstâncias) o valor de uma variável, simplesmente usando o valor de acordo com a sua definição. Esta interpretação restritiva de dados compartilhados pode fornecer um sistema muito flexível para adaptar o comportamento de uma função para o estado atual (ou política) do sistema. No entanto, este benefício depende da documentação cuidadosa de todas as variáveis usadas dessa maneira, bem como na prevenção cuidadosa das suposições sobre o comportamento de uma variável, e não prevê qualquer mecanismo para detectar interferências entre as diferentes partes de um programa. Como tal, o escopo dinâmico pode ser perigoso e poucas linguagens modernas o usam. Algumas linguagens, como o [[Perl]] e [[Common Lisp]], permitem que o programador escolha o escopo estático ou dinâmico, quando da definição ou redefinição de uma variável. [[John McCarthy]] projetou a linguagem [[Lisp]] com escopo dinâmico objetivando compartilhamento de código com variáveis livres.<ref name="appleby">{{Citar livro|autor=APPLEBY, Doris; VANDEKOPPLE, Julius J|título=Programming Languages|subtítulo=Paradigm and Practice|idioma=inglês|edição=2ª|local=New York|editora=McGraw-Hill|ano=1997|páginas=43|volumes=|volume=|id=ISBN 0-07-005315-4}}</ref> [[APL]],<ref name="appleby" />, [[Logo]] e [[Emacs lisp ]] são outros exemplos de linguagens que usam escopo dinâmico.
 
O escopo dinâmico é bastante fácil de implementar. Para encontrar o valor de um identificador, o programa poderia atravessar a pilha de execução, através da cadeia dinâmica, verificando cada [[Pilha_de_chamada#Estrutura|registro de ativação]] buscando um valor para o identificador. Na prática, isto torna-se mais eficiente através da utilização de uma [[lista de associação]], que é uma pilha de pares nome/valor. Pares são empilhados sempre que as declarações são feitas, e desempilhados no momento em que as variáveis deixam o escopo.<ref name="scott2">{{Citar livro|autor=SCOTT, Michael L|título=Programming Language Pragmatics|subtítulo=|idioma=inglês|edição=|local=San Francisco|editora=Morgam Kaufmann/Academic Press|ano=2000|páginas=132-137|volumes=|volume=|id=ISBN 1-55860-442-1}}</ref> Uma estratégia alternativa, que é consideravelmente mais rápida, é fazer uso de uma ''tabela central de referência'', que associa cada nome com seu significado atual. Isso evita uma busca linear durante a execução para encontrar um nome específico, embora a manutenção desta tabela seja mais complexa. <ref name="scott2" /> Note-se que ambas as estratégias assumem um ordenamento de vinculações em estrutura de pilha (LIFO) para qualquer variável; na prática, todas as vinculações são ordenadas desta forma.
 
=== Exemplos ===
Linha 102 ⟶ 100:
Com o escopo dinâmico, a pilha de vinculação para o identificador ''x'' conterá dois itens quando ''f'' é chamada de ''g'': a vinculação global a 0, e a vinculação a 1 introduzida em ''g'' (que ainda está presente na pilha uma vez que o fluxo de controle não deixou ''g'' ainda). Uma vez que a avaliação da expressão do identificador, por definição, sempre produz a vinculação superior, o resultado neste caso é 1.
 
Na linguagem [[Perl]], as variáveis podem ser definidas tanto com o escopo estático quanto o dinâmico. A palavra-chave "<code>my</code>" de Perl, define uma variável local de escopo ''estático'', enquanto a palavra "<code>local</code>" define uma variável local de escopo ''dinâmico''. <ref> [http://www.perl.com/doc/FAQs/FAQ/oldfaq-html/Q4.3.html Perl FAQ 4.3 Qual é a diferença entre escopo dinâmico e estático (lexical)?] </ref> Isso permite maior esclarecimento com exemplos práticos de cada modelo de escopo.
 
<source lang="perl">
Linha 127 ⟶ 125:
Módulos cujos nomes devam ser explicitamente importados são ditos escopos fechados ao passo que escopos que não requerem declarações expícitas de importação são ditos escopos abertos.<ref name="scott">{{Citar livro|autor=SCOTT, Michael L|título=Programming Language Pragmatics|subtítulo=|idioma=inglês|edição=|local=San Francisco|editora=Morgam Kaufmann/Academic Press|ano=2000|páginas=125|volumes=|volume=|id=ISBN 1-55860-442-1}}</ref> Módulos são fechados nas linguagens [[Modula-2]], [[Modula-3]] e [[Euclid]] e abertos em [[Ada (linguagem de programação)|ADA]].<ref name="scott" />
 
== {{Ver também}} ==
* [[Closure]]
* [[Variável global]]
Linha 144 ⟶ 142:
[[fr:Portée (informatique)]]
[[it:Visibilità]]
[[nl:Variabelenbereik]]
[[ja:スコープ]]
[[nl:Variabelenbereik]]
[[pl:Zasięg (programowanie)]]