Namespace - Namespace

Na computação , um namespace é um conjunto de sinais ( nomes ) que são usados ​​para identificar e se referir a objetos de vários tipos. Um namespace garante que todos os objetos de um determinado conjunto de objetos tenham nomes exclusivos para que possam ser facilmente identificados .

Os namespaces são comumente estruturados como hierarquias para permitir a reutilização de nomes em diferentes contextos. Como analogia, considere um sistema de nomenclatura de pessoas em que cada pessoa tem um nome próprio, bem como um sobrenome compartilhado com seus parentes. Se os primeiros nomes dos membros da família forem únicos apenas dentro de cada família, então cada pessoa pode ser identificada de maneira única pela combinação do primeiro nome e do sobrenome; há apenas uma Jane Doe, embora possa haver muitas Janes. No namespace da família Doe, apenas "Jane" é suficiente para designar essa pessoa de forma inequívoca, enquanto no namespace "global" de todas as pessoas, o nome completo deve ser usado.

Exemplos proeminentes de namespaces incluem sistemas de arquivos , que atribuem nomes aos arquivos. Algumas linguagens de programação organizam suas variáveis e sub - rotinas em namespaces. Redes de computadores e sistemas distribuídos atribuem nomes a recursos, como computadores, impressoras, sites da Web e arquivos remotos. Os sistemas operacionais podem particionar recursos do kernel por namespaces isolados para oferecer suporte a contêineres de virtualização .

Da mesma forma, os sistemas de arquivos hierárquicos organizam os arquivos em diretórios. Cada diretório é um namespace separado, de forma que os diretórios "cartas" e "faturas" podem conter um arquivo "to_jane".

Na programação de computadores , os namespaces são normalmente empregados com o propósito de agrupar símbolos e identificadores em torno de uma funcionalidade específica e para evitar colisões de nomes entre vários identificadores que compartilham o mesmo nome.

Na rede, o Sistema de Nomes de Domínio organiza sites (e outros recursos) em namespaces hierárquicos .

Conflitos de nome

Os nomes dos elementos são definidos pelo desenvolvedor. Isso geralmente resulta em um conflito ao tentar misturar documentos XML de diferentes aplicativos XML.

Este XML carrega informações da tabela HTML :

<table>
    <tr>
        <td>Apples</td>
        <td>Oranges</td>
    </tr>
</table>

Este XML carrega informações sobre uma mesa (ou seja, uma peça de mobiliário):

<table>
    <name>African Coffee Table</name>
    <width>80</width>
    <length>120</length>
</table>

Se esses fragmentos XML fossem adicionados juntos, haveria um conflito de nomes. Ambos contêm um <table>...</table>elemento, mas os elementos têm conteúdo e significado diferentes.

Um analisador XML não saberá como lidar com essas diferenças.

Solução via prefixo

Conflitos de nome em XML podem ser facilmente evitados usando um prefixo de nome.

O XML a seguir distingue entre as informações sobre a mesa e os móveis HTML prefixando "h" e "f" no início dos elementos.

<h:table>
    <h:tr>
        <h:td>Apples</h:td>
        <h:td>Oranges</h:td>
    </h:tr>
</h:table>

<f:table>
    <f:name>African Coffee Table</f:name>
    <f:width>80</f:width>
    <f:length>120</f:length>
</f:table>

Sistema de nomenclatura

Um nome em um namespace consiste em um nome de namespace e um nome local. O nome do namespace geralmente é aplicado como um prefixo ao nome local.

Na forma aumentada de Backus-Naur :

name = <namespace name> separator <local name>

Quando os nomes locais são usados ​​por si próprios, a resolução de nomes é usada para decidir a qual (se houver) nome particular é aludido por algum nome local específico.

Exemplos

Exemplos de nomes em um namespace
Contexto Nome Nome do namespace Nome local
Caminho /home/user/readme.txt readme.txt (nome do arquivo)
Nome do domínio www.example.com www (nome de domínio folha)
C ++ std :: array variedade
UN / LOCODE US NYC NYC (localidade)
XML xmlns: xhtml = " http://www.w3.org/1999/xhtml "
<xhtml: body>
corpo
Perl $ DBI :: errstr $ errstr
Java java.util.Date Encontro
Nome de recurso uniforme (URN) urn: nbn: fi-fe19991055 urn: nbn (Números da bibliografia nacional) fi-fe19991055
Sistema de manuseio 10.1000 / 182 10 (lidar com autoridade de nomenclatura) 1000/182 (lidar com o nome local)
Identificador de Objeto Digital 10.1000 / 182 10.1000 (editora) 182 (publicação)
Endereço MAC 01-23-45-67-89-ab 23-01-45 ( identificador único organizacional ) 67-89-ab (específico de NIC)
PCI ID 1234 abcd 1234 (ID do fornecedor) abcd (ID do dispositivo)
USB VID / PID 2341 003f 2341 (ID do fornecedor) 003f (ID do produto)
SPARQL dbr: Sydney dbr (ontologia previamente declarada, por exemplo, especificando @prefix dbr: < http://dbpedia.org/resource/ >) Sydney

Delegação

A delegação de responsabilidades entre as partes é importante em aplicativos do mundo real, como a estrutura da World Wide Web. Os namespaces permitem a delegação da atribuição de identificadores a várias organizações emissoras de nomes, mantendo a exclusividade global. Uma autoridade de registro central registra os nomes de namespace atribuídos alocados . Cada nome de namespace é alocado a uma organização que é subsequentemente responsável pela atribuição de nomes em seu namespace alocado. Essa organização pode ser uma organização emissora de nomes que atribui os próprios nomes ou outra autoridade de registro que delega partes de seu namespace a diferentes organizações.

Hierarquia

Um esquema de nomenclatura que permite subdelegação de namespaces para terceiros é um namespace hierárquico .

Uma hierarquia é recursiva se a sintaxe dos nomes de namespace for a mesma para cada subdelegação. Um exemplo de hierarquia recursiva é o sistema de nomes de domínio .

Um exemplo de hierarquia não recursiva é o Uniform Resource Name que representa um número da Autoridade para Atribuição de Números da Internet (IANA).

Divisão de namespace hierárquico para urn: isbn: 978-3-16-148410-0 , um identificador para o livro The Logic of Scientific Discovery de Karl Popper, 10ª edição.
Registro Registrador Identificador de Exemplo Nome do namespace Namespace
Nome de recurso uniforme (URN) Internet Assigned Numbers Authority urn: isbn: 978-3-16-148410-0 urna Namespace URN formal
Namespace URN formal Internet Assigned Numbers Authority urn: isbn: 978-3-16-148410-0 ISBN Números de livro padrão internacional como nomes de recursos uniformes
Número Internacional de Artigo (EAN) GS1 978-3-16-148410-0 978 Bookland
Número de livro padrão internacional (ISBN) Agência Internacional ISBN 3-16-148410-X 3 Países de língua alemã
Código de editor alemão Agentur für Buchmarktstandards 3-16-148410-X 16 Mohr Siebeck

Namespace versus escopo

Um nome de namespace pode fornecer contexto ( escopo na ciência da computação) para um nome, e os termos às vezes são usados ​​alternadamente. No entanto, o contexto de um nome também pode ser fornecido por outros fatores, como o local onde ele ocorre ou a sintaxe do nome.

Exemplos de sistemas de nomenclatura com escopo local e global, e com e sem namespaces
Sem um namespace Com um namespace
Escopo local Placa de matrícula do veículo Padrão de hierarquia do sistema de arquivos
Âmbito global Identificador universalmente único Sistema de Nome de Domínio

Em linguagens de programação

Para muitas linguagens de programação, o namespace é um contexto para seus identificadores . Em um sistema operacional, um exemplo de namespace é um diretório. Cada nome em um diretório identifica exclusivamente um arquivo ou subdiretório.

Como regra, os nomes em um namespace não podem ter mais de um significado; ou seja, significados diferentes não podem compartilhar o mesmo nome no mesmo namespace. Um namespace também é chamado de contexto , porque o mesmo nome em diferentes namespaces pode ter significados diferentes, cada um apropriado para seu namespace.

A seguir estão outras características de namespaces:

Bem como seu uso técnico de linguagem abstrata conforme descrito acima, algumas linguagens têm uma palavra-chave específica usada para controle de namespace explícito, entre outros usos. Abaixo está um exemplo de um namespace em C ++:

#include <iostream>

// This is how one brings a name into the current scope.  In this case, it's
// bringing them into global scope.
using std::cout;
using std::endl;

namespace box1 {
    int box_side = 4;
}

namespace box2 {
    int box_side = 12;
}

int main() {
    int box_side = 42;
    cout << box1::box_side << endl;  // Outputs 4.
    cout << box2::box_side << endl;  // Outputs 12.
    cout << box_side << endl;  // Outputs 42.
}

Considerações sobre ciência da computação

Um namespace em ciência da computação (às vezes também chamado de escopo de nome ) é um contêiner ou ambiente abstrato criado para manter um agrupamento lógico de identificadores ou símbolos únicos (ou seja, nomes). Um identificador definido em um namespace é associado apenas a esse namespace. O mesmo identificador pode ser definido de forma independente em vários namespaces. Ou seja, um identificador definido em um namespace pode ou não ter o mesmo significado que o mesmo identificador definido em outro namespace. As linguagens que oferecem suporte a namespaces especificam as regras que determinam a qual namespace um identificador (não sua definição) pertence.

Este conceito pode ser ilustrado com uma analogia. Imagine que duas empresas, X e Y, atribuam números de identificação a seus funcionários. X não deve ter dois funcionários com o mesmo número de identificação, da mesma forma para Y; mas não é um problema que o mesmo número de identificação seja usado em ambas as empresas. Por exemplo, se Bill trabalha para a empresa X e Jane trabalha para a empresa Y, então não é um problema para cada um deles ser o funcionário nº 123. Nessa analogia, o número de ID é o identificador e a empresa atua como o namespace. Não causa problemas para o mesmo identificador identificar uma pessoa diferente em cada namespace.

Em grandes programas de computador ou documentos, é comum ter centenas ou milhares de identificadores. Os namespaces (ou uma técnica semelhante, consulte Emulando namespaces ) fornecem um mecanismo para ocultar identificadores locais. Eles fornecem um meio de agrupar identificadores relacionados logicamente em namespaces correspondentes, tornando o sistema mais modular .

Dispositivos de armazenamento de dados e muitas linguagens de programação modernas oferecem suporte a namespaces. Os dispositivos de armazenamento usam diretórios (ou pastas) como namespaces. Isso permite que dois arquivos com o mesmo nome sejam armazenados no dispositivo, desde que sejam armazenados em diretórios diferentes. Em algumas linguagens de programação (por exemplo, C ++ , Python ), os identificadores que nomeiam os namespaces são eles próprios associados a um namespace delimitador. Assim, nessas linguagens, os namespaces podem se aninhar, formando uma árvore de namespaces . Na raiz dessa árvore está o namespace global sem nome .

Use em linguagens comuns

C

É possível usar estruturas anônimas como namespaces em C desde C99 .

// helper.c
static int _add(int a, int b) {
    return a + b;
}

const struct {
    double pi;
    int (*add) (int, int);
} helper = { 3.14, _add };

// helper.h
const struct {
    double pi;
    int (*add) (int, int);
} helper;

// main.c
#include <stdio.h>
#include "helper.h"

int main(){
    printf("3 + 2 = %d\n", helper.add(3, 2));
    printf("pi is %f\n", helper.pi);
}
C ++

Em C ++ , um namespace é definido com um bloco de namespace.

namespace abc {
    int bar;
}

Dentro desse bloco, os identificadores podem ser usados ​​exatamente como são declarados. Fora desse bloco, o especificador de namespace deve ser prefixado. Por exemplo, fora de namespace abc, bardeve ser escrito abc::barpara ser acessado. C ++ inclui outra construção que torna esse detalhamento desnecessário. Adicionando a linha

using namespace abc;

para um pedaço de código, o prefixo abc::não é mais necessário.

Os identificadores que não são declarados explicitamente em um namespace são considerados no namespace global.

int foo;

Esses identificadores podem ser usados ​​exatamente como são declarados ou, como o namespace global não tem nome, o especificador de namespace ::pode ser prefixado. Por exemplo, footambém pode ser escrito ::foo.

A resolução do namespace em C ++ é hierárquica. Isso significa que dentro do namespace hipotético food::soup, o identificador chickense refere food::soup::chicken. Se food::soup::chickennão existir, então se refere a food::chicken. Se food::soup::chickennem food::chickenexistir, chickenrefere-se a ::chickenum identificador no namespace global.

Os namespaces em C ++ são usados ​​com mais frequência para evitar colisões de nomenclatura . Embora os namespaces sejam usados ​​extensivamente no código C ++ recente, a maioria dos códigos mais antigos não usa esse recurso porque ele não existia nas versões anteriores da linguagem. Por exemplo, toda a C ++ Standard Library é definida dentro namespace std, mas antes da padronização muitos componentes estavam originalmente no namespace global. Um programador pode inserir a usingdiretiva para ignorar os requisitos de resolução de namespace e obter compatibilidade reversa com o código mais antigo que espera que todos os identificadores estejam no namespace global. No entanto, o uso da usingdiretiva por razões diferentes da compatibilidade com as versões anteriores (por exemplo, conveniência) é considerado contrário às boas práticas de código.

Java

Em Java , a ideia de um namespace está incorporada em pacotes Java . Todo código pertence a um pacote, embora esse pacote não precise ser nomeado explicitamente. O código de outros pacotes é acessado prefixando o nome do pacote antes do identificador apropriado, por exemplo class String, pode ser referido como (isso é conhecido como o nome de classe totalmente qualificado ). Como C ++, Java oferece uma construção que torna desnecessário digitar o nome do pacote ( ). No entanto, certos recursos (como reflexão ) exigem que o programador use o nome totalmente qualificado. package java.langjava.lang.Stringimport

Ao contrário do C ++, os namespaces em Java não são hierárquicos no que diz respeito à sintaxe da linguagem. No entanto, os pacotes são nomeados de maneira hierárquica. Por exemplo, todos os pacotes que começam com javafazem parte da plataforma Java - o pacote java.langcontém classes centrais para a linguagem e java.lang.reflectcontém classes centrais especificamente relacionadas à reflexão.

Em Java (e Ada , C # e outros), namespaces / pacotes expressam categorias semânticas de código. Por exemplo, em C #, namespace Systemcontém o código fornecido pelo sistema (o .NET Framework ). O quão específicas são essas categorias e a profundidade das hierarquias difere de idioma para idioma.

Os escopos de função e classe podem ser vistos como namespaces implícitos que estão inextricavelmente vinculados à visibilidade, acessibilidade e tempo de vida do objeto .

C #

Os namespaces são amplamente usados ​​na linguagem C #. Todas as classes do .NET Framework são organizadas em namespaces para serem usadas com mais clareza e evitar o caos. Além disso, os namespaces personalizados são amplamente usados ​​por programadores, tanto para organizar seu trabalho quanto para evitar conflitos de nomenclatura . Ao fazer referência a uma classe, deve-se especificar seu nome totalmente qualificado, o que significa namespace seguido pelo nome da classe,

System.Console.WriteLine("Hello World!");
int i = System.Convert.ToInt32("123");

ou adicione uma instrução using . Isso elimina a necessidade de mencionar o nome completo de todas as classes nesse namespace.

using System;

Console.WriteLine("Hello World!");
int i = Convert.ToInt32("123");

Nos exemplos acima, System é um namespace e Console e Convert são classes definidas em System .

Pitão

Em Python , os namespaces são definidos pelos módulos individuais e, como os módulos podem estar contidos em pacotes hierárquicos, os namespaces também são hierárquicos. Em geral, quando um módulo é importado, os nomes definidos no módulo são definidos por meio do namespace desse módulo e são acessados ​​a partir dos módulos de chamada usando o nome totalmente qualificado.

# assume modulea defines two functions : func1() and func2() and one class : Class1
import Modulea

Modulea.func1()
Modulea.func2()
a = Modulea.Class1()

A from ... import ...instrução pode ser usada para inserir os nomes relevantes diretamente no namespace do módulo de chamada, e esses nomes podem ser acessados ​​a partir do módulo de chamada sem o nome qualificado:

# assume Modulea defines two functions : func1() and func2() and one class : Class1
from Modulea import func1

func1()
func2() # this will fail as an undefined name, as will the full name Modulea.func2()
a = Class1() # this will fail as an undefined name, as will the full name Modulea.Class1()

Uma vez que importa nomes diretamente (sem qualificação), pode sobrescrever nomes existentes sem avisos.

Uma forma especial da instrução é from ... import *que importa todos os nomes definidos no pacote nomeado diretamente no namespace do módulo de chamada. O uso dessa forma de importação, embora seja compatível com o idioma, é geralmente desencorajado, pois polui o espaço de nomes do módulo de chamada e fará com que os nomes já definidos sejam substituídos no caso de conflitos de nomes.

Python também oferece suporte import x as ycomo forma de fornecer um alias ou nome alternativo para uso pelo módulo de chamada:

import numpy as np

a = np.arange(1000)
Namespace XML

Em XML , a especificação de namespace XML permite que os nomes de elementos e atributos em um documento XML sejam exclusivos, semelhante à função de namespaces em linguagens de programação. Usando namespaces XML, os documentos XML podem conter nomes de elementos ou atributos de mais de um vocabulário XML.

PHP

Os namespaces foram introduzidos no PHP a partir da versão 5.3. A colisão de nomes de classes, funções e variáveis ​​pode ser evitada. Em PHP , um namespace é definido com um bloco de namespace.

# File phpstar/foobar.php

namespace phpstar;

class FooBar
{
    public function foo(): void
    {
        echo 'Hello world, from function foo';
    }

    public function bar(): void
    {
        echo 'Hello world, from function bar';
    }
}

Podemos fazer referência a um namespace PHP das seguintes maneiras diferentes:

# File index.php

# Include the file
include "phpstar/foobar.php";

# Option 1: directly prefix the class name with the namespace
$obj_foobar = new \phpstar\FooBar();

# Option 2: import the namespace
use phpstar\FooBar;
$obj_foobar = new FooBar();

# Option 2a: import & alias the namespace
use phpstar\FooBar as FB;
$obj_foobar = new FB();

# Access the properties and methods with regular way
$obj_foobar->foo();
$obj_foobar->bar();

Emulando namespaces

Em linguagens de programação sem suporte de linguagem para namespaces, os namespaces podem ser emulados até certo ponto usando uma convenção de nomenclatura de identificador . Por exemplo, bibliotecas C como libpng geralmente usam um prefixo fixo para todas as funções e variáveis ​​que fazem parte de sua interface exposta. Libpng expõe identificadores como:

png_create_write_struct
png_get_signature
png_read_row
png_set_invalid

Essa convenção de nomenclatura fornece uma garantia razoável de que os identificadores são exclusivos e podem, portanto, ser usados ​​em programas maiores sem conflitos de nomenclatura . Da mesma forma, muitos pacotes originalmente escritos em Fortran (por exemplo, BLAS , LAPACK ) reservam as primeiras letras do nome de uma função para indicar a qual grupo ela pertence.

Essa técnica tem várias desvantagens:

  • Ele não se adapta bem a namespaces aninhados; identificadores tornam-se excessivamente longos, pois todos os usos dos identificadores devem ser totalmente qualificados para namespace .
  • Indivíduos ou organizações podem usar convenções de nomenclatura inconsistentes, potencialmente introduzindo ofuscação indesejada.
  • Operações compostas ou "baseadas em consulta" em grupos de identificadores, com base nos namespaces em que são declarados, são tornadas difíceis de manejar ou inviáveis.
  • Em linguagens com comprimento de identificador restrito, o uso de prefixos limita o número de caracteres que podem ser usados ​​para identificar o que a função faz. Este é um problema particular para pacotes originalmente escritos em FORTRAN 77 , que oferecia apenas 6 caracteres por identificador. Por exemplo, o nome da função BLASDGEMM indica que ela opera em números de precisão dupla ("D") e matrizes gerais ("GE"), e apenas os dois últimos caracteres mostram o que ela realmente faz: multiplicação matriz-matriz ( o "MM").

Existem várias vantagens:

  • Nenhuma ferramenta de software especial é necessária para localizar nomes em arquivos de código-fonte. Um programa simples como o grep é suficiente.
  • Não há conflitos de nome de namespace.
  • Não há necessidade de mutilar o nome e, portanto, não há problemas de incompatibilidade em potencial.

Veja também

Referências