Na maioria das linguagens de codificação (se não todas), você precisa declarar variáveis. Por exemplo, em C #, se for um campo numérico,
int PhoneNumber
Se eu estiver usando o idioma inglês normal, não preciso declarar PhoneNumber
como int
usá-lo. Por exemplo, se eu pedir ao meu amigo Sam para me dar seu número de telefone, digo:
"Sam me dê o número do telefone"
Eu não diria
"Char (20) Sam me dê o int phoneNumber"
Por que precisamos especificar o tipo de dados?
programming-languages
Dick Smith
fonte
fonte
Respostas:
Essas são duas perguntas independentes:
Aliás, a resposta para ambos é: nós não.
Existem muitas linguagens de programação com tipos estatísticos em que você não precisa declarar tipos. O compilador pode inferir os tipos do contexto circundante e do uso.
Por exemplo, em Scala, você pode dizer
ou você poderia apenas dizer
Os dois são exatamente equivalentes: o compilador inferirá o tipo a
Int
partir da expressão de inicialização23
.Da mesma forma, em C♯, você pode dizer um desses, e ambos significam exatamente a mesma coisa:
Esse recurso é chamado de inferência de tipo , e muitos idiomas além de Scala e C♯ o possuem: Haskell, Kotlin, Ceilão, ML, F♯, C ++, o nome dele. Até o Java possui formas limitadas de inferência de tipo.
Nas linguagens de programação de tipo dinâmico, as variáveis nem têm tipos. Os tipos existem apenas dinamicamente no tempo de execução, não estaticamente. Somente valores e expressões têm tipos e somente em tempo de execução, as variáveis não têm tipos.
Por exemplo, no ECMAScript:
E, finalmente, em muitos idiomas, você nem precisa declarar variáveis. por exemplo, em Ruby:
De fato, esse último exemplo é válido em várias linguagens de programação. A mesma linha de código exata também funcionaria em Python, por exemplo.
Tão,
fonte
auto i = 1 // i is inferred to type int
,vector<int> vec; auto itr = vec.iterator(); // itr is inferred to type vector<int>::iterator
e assim por diante. Se você quiser saber exatamente como isso funciona, consulte as especificações.Quando você usa a linguagem natural para se referir a informações, ela não é muito precisa e, em particular, não se comunica muito com os outros sobre sua intenção. Problemas semelhantes ocorrem ao tentar fazer contas em linguagem natural: simplesmente não é preciso o suficiente.
A programação é complexa; erros são muito fáceis de encontrar. Os tipos fazem parte de um sistema de verificações projetadas para impedir estados ilegais de programas, detectando condições de erro. Idiomas diferentes usam tipos de maneira diferente: alguns idiomas usam tipos fortemente para detectar erros no tempo de compilação. Quase todos os idiomas têm alguma noção de tipos incompatíveis como um erro de tempo de execução. Geralmente, um erro de tipo indica um erro de algum tipo no programa. Quando permitimos que os programas continuem apesar dos erros, provavelmente obtemos respostas muito ruins. Preferimos interromper o programa em vez de obter respostas ruins ou incorretas.
Dito de outra maneira, os tipos expressam restrições no comportamento do programa. As restrições, quando aplicadas por algum mecanismo, fornecem garantias. Tais garantias limitam a quantidade de raciocínio necessário para pensar sobre o programa, simplificando a tarefa de ler e manter o programa para os programadores. Sem tipos e suas implicações de ferramentas (ou seja, o compilador) que detectam erros de tipo, a carga de programação é consideravelmente maior e, portanto, mais cara.
É verdade que (muitos) humanos distinguem facilmente entre um número de telefone europeu, norte-americano e internacional. No entanto, o computador realmente não "pensa" e, se informado, discaria um número de telefone dos Estados Unidos na Europa ou vice-versa. Tipos, por exemplo, são uma boa maneira de distinguir entre esses casos, sem ter que ensinar ao computador como "pensar". Em alguns idiomas, podemos obter um erro no tempo de compilação ao tentar misturar um número de telefone europeu em um sistema telefônico americano. Esse erro indica que precisamos modificar nosso programa (talvez convertendo o número de telefone em uma seqüência de discagem internacional ou, usando o número de telefone na Europa) antes mesmo de tentar executar o programa.
Além disso, como o computador não pensa, o nome do campo ou variável (por exemplo
phonenumber
) não significa nada para o computador. Para o computador, esse nome de campo / variável é apenas "blah123". Pense em como seria o seu programa se todas as variáveis fossem "blahxxx". Caramba. Bem, é isso que o computador vê. Fornecer um tipo fornece ao computador uma noção do significado da variável que ele simplesmente não pode deduzir apenas do nome.Além disso, como diz o @Robert, em muitos idiomas modernos, não precisamos especificar os tipos tanto quanto antigamente, pois idiomas como o C # realizam "inferência de tipo", que é um conjunto de regras para determinar o tipo apropriado para uma variável no contexto. O C # apenas fornece inferência de tipo em variáveis locais, mas não em parâmetros formais ou campos de classe ou instância.
fonte
Types are part of a system of checks that ...
uma vez que responde diretamente o OP emWhy do we have to specify data type at all?
..static member add x y = x + y
,member x.Append s = x.Text + s
. No primeiro caso,x
ey
será deduzido serint
s por causa da adição. No segundo caso, eles serão válidos dependendo do tipo dex.Text
- se for umstring
, tambéms
será umstring
. Eu concordo que as anotações de tipo são documentação, no entanto.Além das outras respostas, há uma coisa que deve ser incluída. Lembre-se de que os computadores são apenas bits. Digamos que eu lhe forneça os bytes:
O que isso significa ? É armazenado dessa maneira pelo computador, mas sem nenhuma interpretação, são apenas bits . Pode ter 4 caracteres ascii. Pode ser um número inteiro. Pode haver alguns bytes em uma matriz. Pode ser parte de um objeto. Pode ser um indicador de onde o vídeo do gato está armazenado em buffer. Praticamente todas as linguagens de programação, desde a montagem em diante, precisam de algo para saber como interpretar os bits para fazê-los realizar cálculos significativos.
E como o computador não pode saber o significado desses bits, ele precisa ser informado - explicitamente por meio de anotações de tipo ou implicitamente por mecanismos de inferência de tipo mencionados nas outras respostas.
fonte
A resposta para o motivo pelo qual os computadores precisam dessas informações está relacionada à representação de dados .
O nome do "tipo de dados" é uma referência a regras que ajudam o computador a armazenar e recuperar informações do estado bruto de 0 e 1 na memória do computador.
Por exemplo, seu caractere ASCII de 8 bits comum seria armazenado na memória do computador (RAM ou disco) como
01000001
(o caractere maiúsculo "A", código ASCII 65) ou00001000
(o sinal de porcentagem) ou qualquer combinação de 0 e 1 nesses 8 bits.Por outro exemplo, algum número inteiro não assinado de 8 bits pode ser armazenado como
00000101
(o número 5) ou00001000
(o número 8)Observe como a representação binária de 8 e o caractere% podem ser os mesmos, mas eles significam coisas diferentes porque seus tipos são diferentes.
Mesmo nos idiomas que inferem o tipo de dados, eles podem não ter a regra de que "todos os tipos de variáveis devem ser declarados pelo programador", eles têm regras como "se sua série de caracteres estiver entre aspas, é uma string" e muito mais regras para cada tipo de dados.
Portanto, mesmo esses precisam de tipos de dados para entender o significado dos zeros e zeros, para que eles possam, por exemplo, executar a função de concatenação de strings se você tentar "adicionar" dois caracteres ou fazer adição de números inteiros se tentar adicionar dois inteiros. .
Também na sua história , digamos que você não pediu o número de telefone para Sam, mas Sam fornece um pedaço de papel com "1123581321" escrito. Você não podia ter certeza se Sam é apenas um fã dos oito primeiros números de Fibonacci ou se é um número de telefone. Para adivinhar, você terá que levar em consideração o contexto e as dicas disponíveis, como talvez você tenha pedido um número de telefone para Sam há um dia atrás ou a nota seja "Ligue para mim" ou se você contar os dígitos e encontrar ele corresponde aos padrões da maioria dos números de telefone. Só então você saberia que é um número de telefone para o qual você pode ligar e não alguns dígitos que você digitaria em uma calculadora.
Observe como essas dicas que levaram você a supor que o número era um número de telefone são semelhantes a como as dicas levam uma linguagem de computador que não requer declaração para deduzir o tipo de um valor.
fonte
Em alguns idiomas, você não precisa especificar o tipo de dados.
Os idiomas que suportam a inferência de tipo geralmente podem descobrir o tipo de dados do seu uso. Por exemplo,
é digitado internamente como uma sequência, porque o valor é cercado por aspas.
Alguns idiomas também não exigem que você declare a variável; a variável é criada quando é usada pela primeira vez. No entanto, é considerado uma prática recomendada declarar especificamente suas variáveis por vários motivos importantes; principalmente porque fazê-lo melhor expressa sua intenção.
fonte
var name = "Ali"
estilo é realmente comum para linguagens modernas de tipo estaticamente . Nas linguagens de tipo estaticamente, o tipo é fixo na criação, mas ainda pode ser determinado pelo inicializador. A definição de uma linguagem digitada dinamicamente é que os tipos se anexam a valores, não a variáveis. Atribuir um valor a uma variável, portanto, define o tipo das variáveis também.var x = 5; x = "";
porque a primeira instrução fazx
com que o tipo "Number" seja associadox
? Tipo de conflitos com a digitação dinâmica . E se não, qual o efeito do tipo associado à variável, além da associação do tipo ao valor?x = "";
altera o tipo de x para string, mesmo que fosse um número anteriormente.Porque é isso que o design da linguagem especifica. Portanto, para responder sua pergunta, precisamos examinar a intenção por trás da digitação explícita em linguagens como C # e C ++. (Bem, o C # faz isso porque o C ++ faz porque o C faz, por isso precisamos examinar a intenção dessa época).
Primeiro, a digitação explícita e estática fornece rigor na codificação - especificar uma variável como um número inteiro significa que o compilador e o software devem ser surpreendidos e gerar um erro ao atribuir um caractere ou sequência à variável. A digitação dinâmica pode causar dores de cabeça para os incautos (basta olhar para a abordagem PHP ou javascripts da veracidade de coisas como matrizes e cadeias vazias).
Você pode ter estática com a digitação implícita - inicializar uma variável como uma string significa que a variável deve ser apenas uma string, mas minha sensação é de que isso pode causar problemas para os humanos que leem o código (eu tendem a assumir a digitação dinâmica quando há uma digitação implícita )
Além disso, é possível, em alguns idiomas, escrever algo como esse pseudocódigo para inicializar uma classe a partir de uma entrada de string:
Segundo, a digitação explícita também anda de mãos dadas com a alocação de memória. Um int é sempre tantos bytes. Um número de telefone tem tantos bytes. O compilador pode atribuir um bloco de memória de tamanho apropriado que pode ser usado posteriormente sem precisar ver quanto espaço será necessário quando você atribui um valor.
Finalmente, remove a confusão ... 123 é um número inteiro ou um número inteiro não assinado? Eles precisam do mesmo número de bytes, mas o valor máximo armazenado nas variáveis de qualquer tipo é muito diferente ...
Isso não significa que explícito é melhor que implícito - mas o design da linguagem se baseia nesses tipos de opções, e o C # funcionaria de maneira diferente com a digitação implícita. PHP e javascript funcionariam de maneira diferente com a digitação explícita.
fonte
Porque Sam é mais esperto que os compiladores. Por exemplo, quando você diz que me fornece o número de telefone, não especifica se deseja o prefixo do país ou o código de área, se é o número comercial em que apenas os últimos 4 dígitos são necessários. Além disso, se você pedir o número da junta de pizza local, poderá lidar com a resposta "pizza4u".
Sam, descobre isso a partir do contexto. Enquanto o compilador também pode descobrir isso a partir do contexto, Sam será melhor nisso (e é capaz de interromper o processo para solicitar esclarecimentos).
Existem duas abordagens básicas para tipos e variáveis: a variável tem um tipo; nesse caso, as ações que não são permitidas pelo tipo são proibidas e impedem a compilação, ou o valor tem um tipo e as ações que não são permitidas pelo tipo são capturados em tempo de execução.
Cada abordagem tem suas vantagens e desvantagens. Em geral, os criadores de compiladores tentam minimizar as desvantagens e maximizar as vantagens. É por isso que o C #, por exemplo, permite
var phoneNumber = GetPhoneNumber();
e deduz o tipo de phoneNumber da assinatura de GetPhoneNumber. Isso significa que você deve declarar o tipo do método, mas não a variável que recebe o resultado. Por outro lado, existem vários tipos de dica / aplicação de projetos para javascript. Tudo é uma troca.fonte
É uma questão de como os dados são armazenados. Sua interação com Sam faria uma comparação melhor se você estivesse perguntando para que você pudesse anotá-la, mas tivesse apenas oito caracteres em papel.
Portanto, a maioria dos idiomas faz com que você declare um tipo, para que ele saiba e se prepare com antecedência:
Fica ainda mais inchado quando você olha para as formas fundamentais reais de armazenamento dos dados. Se você é como eu, tem um caderno com anotações diversas, números apenas rabiscados, sem contexto ou etiqueta para nada, e não tem idéia do que isso significa três dias depois. Este é um problema para computadores muitas vezes também. Muitos idiomas têm tipos "int" (int, long, short, byte) e "float" (float, double). Por que isso é necessário?
Bem, primeiro vamos ver como um número inteiro é armazenado e geralmente representado dentro do computador. Você provavelmente está ciente de que, no nível básico, é tudo binário (1 e 0). Binário é na verdade um sistema numérico que funciona exatamente como o nosso sistema numérico decimal. Em decimal, você conta de 0 a 9 (com zeros iniciais implícitos infinitos que você não escreve), depois reverte para 0 e incrementa o próximo dígito para obter 10. Você repete até rolar de 19 para 20, repita até rolar de 99 para 100 e assim por diante.
Binário não é diferente, exceto que, em vez de 0 a 9, você conta de 0 a 1. 0, 1, 10, 11, 100, 101, 110, 111, 1000. Portanto, quando você digita 9, na memória gravada em binário como 1001. Este é um número real. Pode ser adicionado, subtraído, multiplicado, etc., exatamente dessa forma. 10 + 1 = 11. 10 + 10 = 100 (passe 1 para 0 e carregue o 1). 11 x 10 = 110 (e equivalente 11 + 11 = 110).
Agora, na memória real (registradores incluídos), há uma lista, matriz, como você quiser chamá-lo, de bits (1 ou 0 potencial) próximos um do outro, e é assim que ele mantém esses bits logicamente organizados para criar um número maior que 1. O problema é o que você faz com decimais? Você não pode simplesmente inserir um pedaço de hardware entre os dois bits no registro, e custaria muito adicionar "bits decimais" entre cada par de bits. Então o que fazer?
Você o codifica. Geralmente, a arquitetura da CPU ou do software determinará como isso é feito, mas uma maneira comum é armazenar um sinal (+ ou -, geralmente 1 é negativo) no primeiro bit do registro, uma mantissa (seu número mudou no entanto, muitas vezes é necessário livrar-se do decimal) para o seguinte número X de bits e um expoente (o número de vezes que você precisou alterá-lo) para o restante. É semelhante à notação científica.
Digitar permite que o compilador saiba o que está olhando. Imagine que você tenha armazenado o valor 1.3 no registrador 1. Vamos criar o nosso próprio esquema de codificação sofisticado aqui, 1 bit para sinal, 4 para mantissa, 3 para expoente (1 bit para sinal, 2 para magnitude). Como é um número positivo, o sinal é positivo (0). Nossa mantissa seria 13 (1101) e nosso expoente seria -1 (101 (1 para negativo, 01 = 1)). Então, armazenamos 01101101 no registro 1. Agora, não digitamos essa variável; portanto, quando o tempo de execução vai usá-la, ele diz "claro, este é um número inteiro, por que não", portanto, quando imprime o valor, vemos 109 (64 + 32 + 8 + 4 + 1), o que obviamente não está certo.
Porém, nem todo idioma exige que você digite explicitamente. O C # tem uma palavra-chave "var" que faz com que o tipo de uma variável seja interpretado em tempo de compilação, e outros idiomas como Javascript são totalmente digitados dinamicamente, a ponto de você poder armazenar um número inteiro em uma variável e atribuí-lo a um booleano. atribua-o novamente a uma string e o idioma acompanhará tudo.
Mas é muito mais fácil no compilador, no intérprete ou no tempo de execução - e geralmente resulta em um programa mais rápido, pois ele não precisa gastar recursos valiosos classificando a digitação de tudo - para perguntar ao programador que tipo de dados que você está fornecendo.
fonte
Existem linguagens de programação nas quais você não precisa declarar tipos de dados para suas variáveis. Existem até linguagens de programação em que você não precisa declarar variáveis com antecedência; você pode usá- los imediatamente.
O problema de não declarar nomes de variáveis é que, se você digitar o nome de uma variável acidentalmente, agora criará acidentalmente uma nova variável completamente não relacionada. Então, quando você executa seu programa, não consegue descobrir por que diabos essa variável que você configurou repentinamente não tem nada ... Até que, depois de muitas horas de depuração, você percebe que digitou o nome errado! GRRR !!
Então eles fizeram isso, então você deve declarar os nomes das variáveis que você usará antes. E agora, quando você digita um nome errado, recebe um erro em tempo de compilação, que informa imediatamente exatamente onde está o erro, antes mesmo de o programa ser executado. Isso não é muito mais fácil?
O mesmo acordo com os tipos de dados. Existem linguagens de programação nas quais você não precisa declarar que tipo de coisa deve ser. Se você tem uma
customer
variável que na verdade é apenas o nome de um cliente, não o objeto inteiro do cliente, tentar buscar o endereço do cliente a partir de uma sequência comum simples ... não vai funcionar. O ponto principal da digitação estática é que o programa não será compilado; ele reclamará alto, apontando para o local exato onde está o problema. Isso é muito mais rápido do que executar seu código e tentar descobrir por que diabos não está funcionando.Todos esses são recursos para informar ao compilador o que você pretendia fazer, para que ele possa verificar o que você realmente fez e se certificar de que faz sentido. Isso possibilita ao compilador localizar automaticamente erros para você, o que é um grande problema.
(No passado distante, você não precisava declarar sub-rotinas . Você faria apenas
GOSUB
com um número de linha específico. Se desejasse passar informações entre sub-rotinas, definiria variáveis globais específicas, chamaria sua sub-rotina e inspecionaria outras quando a sub-rotina retorna. Mas isso torna assustadoramente fácil inicializar um dos parâmetros. Agora, quase todas as linguagens de programação modernas exigem que você declare quais parâmetros reais uma sub-rotina exige, para que possamos verificar se você especificou todos eles. )fonte
var x=1
com resultados semelhantes. Mas isso não é nada; em Haskell, você pode escrever seu programa inteiro sem assinaturas de tipo em tudo, mas tudo é digitado estaticamente, e você ainda receber erros se você cometer um erro ... (Não exatamente convencional embora.)for (auto i=0; i<SomeStdVector.size(); ++i)
seu linter irá reclamar porque deduziu um tipo assinado e você o comparará a um tipo não assinado. Você precisa escreverauto i=0ul
(colocando as informações de tipo explicitamente novamente, portanto, basta escreversize_t i=0
em primeiro lugar).Vá para o MathOverflow ou para a Teoria da Ciência da Computação e leia por um tempo para ter uma idéia de como os humanos se comunicam com alogritmos quando querem garantir que não há possibilidade de mal-entendidos. Ou leia o padrão para alguma linguagem de programação madura.
Você descobrirá que definir que tipos de valores são permitidos para um termo faz parte de uma prática de comunicação realmente precisa, mesmo de humano para humano.
O que você notou é que as interações diárias são razoavelmente regulares e humanas são bastante tolerantes a falhas; portanto, um mal-entendido sobre números de telefone geralmente é evitado pelo conhecimento compartilhado dos participantes.
Mas você já tentou anotar um número de telefone para alguém em outro país? Eles disseram explicitamente quantas vezes você deve pressionar zero para chegar ao endereçamento internacional? Eles disseram o código do país? Você reconheceu isso como tal? Quantos dígitos você esperava? Quantos você conseguiu? Você sabia como agrupar os dígitos? Ou mesmo se o agrupamento tiver significado?
De repente, o problema é muito mais difícil e você provavelmente tomou muito mais cuidado para verificar explicitamente se o número recebido foi entendido da maneira que o remetente queria.
fonte
Outro motivo para declarar tipos é eficiência. Enquanto um número inteiro pode ser armazenado em 1 byte, 2 bytes ou 4, um programa que usa um número muito grande de variáveis pode usar 4 vezes a memória necessária, dependendo do que está sendo feito. Somente o programador sabe se um espaço de armazenamento menor é viável, para que ele possa dizer isso declarando o tipo.
Além disso, objetos digitados dinamicamente permitem muitos tipos possíveis em tempo real. Isso pode resultar em sobrecarga "oculta", diminuindo a velocidade do programa em comparação com a persistência de um tipo o tempo todo.
fonte
Várias linguagens de programação anteriores (especialmente o Fortran) não exigiam que você declarasse variáveis antes do uso.
Isso levou a uma série de problemas. Uma realmente óbvia é que o compilador não pode mais capturar erros tipográficos simples com a mesma confiabilidade. Se você possui um código que deveria modificar uma variável existente, mas possui um erro de digitação, ainda possui um código perfeitamente legítimo que acabou de criar (e atribuir um valor a) uma nova variável:
Agora, analisando isso isoladamente, com o fato de eu já ter mencionado um erro de digitação como a fonte do problema, provavelmente é muito fácil encontrar o erro de digitação e o problema aqui. Em um programa longo, onde isso está oculto no meio de muitos outros códigos, é muito mais fácil perder.
Mesmo atualmente com muitos idiomas de tipo dinâmico, você ainda pode obter o mesmo problema básico com bastante facilidade. Alguns têm alguma facilidade para avisá-lo se você atribuir a uma variável, mas nunca a leem (que heuristicamente detecta alguns problemas como esse), outros não têm essas coisas.
fonte
Quando você declara qualquer variável, algum espaço é alocado na memória, mas a máquina (neste caso, o computador) ainda não sabe quanto espaço deve ser alocado para essa variável.
Exemplo: - você cria um programa que solicita que o usuário insira qualquer número; nesse caso, é necessário especificar um tipo de dados para armazenar esse número; caso contrário, a máquina não pode julgar por si mesma que deve alocar 2 bytes ou 2 gigabytes , se tentar fazer alocação por si só, isso pode resultar em uso ineficiente de memória. Por outro lado, se você especificar o tipo de dados em seu programa, após a compilação, a máquina alocará o espaço adequado de acordo com a necessidade.
fonte