Por que variáveis ​​precisam de um tipo?

10

Então escrevemos:

Customer c = new Customer();

Por que o design não é tal que escrevemos:

c = new Customer();
c.CreditLimit = 1000;

O compilador pode calcular pontos c para um cliente e permitir que os membros do cliente sejam chamados em c?

Eu sei que podemos escrever:

IPerson c = new Customer();
IPerson e = new Employee();

para poder escrever:

public string GetName(IPerson object)
{
    return object.Name
}

string name = GetName(c); // or GetName(e);

Mas se escrevêssemos:

c = new Customer();
e = new Employee();

ainda poderíamos escrever:

public string GetName(object)
{
    return object.Name
}    

string name = GetName(c); // or GetName(e);

O compilador pode reclamar do código imediatamente acima se o tipo de objeto c referenciado não suportar uma propriedade Name (pois pode verificar quais membros são usados ​​no argumento / parâmetro dentro do método) ou o tempo de execução pode reclamar.

Mesmo com a palavra-chave dinâmica do C #, ainda estamos usando uma variável 'type' (determinada em tempo de execução). Mas por que uma variável precisa de um tipo? Estou certo de que deve haver uma boa razão, mas não consigo pensar nisso!

sturdytree
fonte
12
É por isso que existem linguagens dinâmicas como Python e Ruby (e outras). Não há resposta para esta pergunta. É fato que alguns idiomas usam declarações de tipo e outros não.
10242 S.Lott
2
"variáveis ​​nesses idiomas não têm um tipo?" Corrigir. variáveis não têm um tipo em Python. Objetos têm um tipo e variáveis ​​são simplesmente referências a objetos. Sua pergunta é realmente apenas uma observação. Especificamente "nem todos os idiomas exigem declarações variáveis". Não há resposta. Portanto, é provável que ele seja fechado por não ser construtivo.
10243 S.Lott
11
Você pode dar uma olhada no Boo , que permite declarar variáveis ​​sem nenhuma declaração de tipo, mas usa inferência de tipo para descobrir tipos, para que você não sacrifique os benefícios de correção e desempenho da digitação forte.
Mason Wheeler
2
var x = 1; - você quis dizer número de 32 bits, 64 bits e 16 bits? byte? flutuador? Duplo? decimal? Isso é apenas lidar com primitivos.
Job
4
Você pode usar varem C # e ser informado sobre onde deseja declarar que uma variável é sempre boa.
11554 Daniel Little

Respostas:

22

Mas por que uma variável precisa de um tipo?

  1. Isso pode detectar bugs quando uma expressão inválida e digitada incorretamente é atribuída a uma variável. Alguns idiomas possuem digitação dinâmica , o que sacrifica as garantias de correção de um tipo por variável para o tipo de flexibilidade que você deseja.
  2. Tipos podem permitir que o compilador gere um código mais eficiente. Digitação dinâmica significa que as verificações de tipo devem ser executadas em tempo de execução.
Fred Foo
fonte
11
Por favor, explique o voto negativo.
Fred Foo
4
Além disso, a digitação dinâmica tem um custo de desempenho, porque as informações de tipo precisam ser verificadas durante o tempo de execução.
Charles Salvia
@ CharlesSalvia: bom ponto, acrescentou isso à resposta.
Fred Foo
2
@sturdytree: quanto a "se não tiver um tipo, não poderá ser digitado incorretamente" - no que diz respeito às regras de linguagem, isso é verdade. Mas a variável ainda pode ser atribuída ao tipo errado do ponto de vista semântico , por exemplo, você digitou incorretamente o nome de um construtor e o programa ainda é executado, mas não faz o que deseja.
Fred Foo
5
@sturdytree Embora seja verdade que não há línguas que têm verdadeiramente não-tipificados variáveis com verificação de tipo, há línguas que têm a inferência de tipos . Ou seja, o idioma examina o uso da variável e deduz o tipo do uso. Se houver um conflito (por exemplo, você executa a = new Bar()e depois chama um método da classe Baz), o compilador gera um erro. Idiomas como Haskell e OCaml foram pioneiros na inferência de tipo, mas está presente em C #, com a varpalavra - chave.
Quanticle
9

Você tem um ponto perfeitamente válido, os idiomas que não controlam o tipo de uma variável existem e são chamados de "tipo dinâmico". A categoria inclui idiomas como JavaScript, Perl, Lisp e Python.

A vantagem que obtemos de uma linguagem de tipo estaticamente é uma verificação adicional de erros em tempo de compilação.

Suponha, por exemplo, que você tenha o seguinte método:

public addCustomerContact(Customer client, Employee contact) {
   ...
} 

Seria possível, se você tiver um cliente bobe um funcionário jamesem seu código, ligar por engano addCustomerContact(james, bob), o que é inválido. Mas se o compilador não souber os tipos das variáveis, não será possível avisá-lo de que você fez uma chamada inválida. Em vez disso, ocorrerá um erro no tempo de execução ... e como os idiomas de tipo dinâmico não verificam o tipo de parâmetros transmitidos aos métodos, esse problema ocorre sempre que seu código tenta usar propriedades do jamesobjeto somente para clientes ou propriedades somente para funcionários do bobobjeto. Isso pode demorar muito depois que o par (james, bob) foi adicionado à lista de contatos do cliente.

Agora, você pode se perguntar, por que não pode o compilador ainda inferir o tipo de jamese bob, e ainda nos avisar? Às vezes, isso é possível, mas se as variáveis ​​realmente não tiverem tipo, poderíamos fazer o seguinte:

var james;
var bob;
if (getRandomNumber() > 0.5) {
   james = new Customer();
   bob = new Employee();
} else {
   james = new Employee();
   bob = new Customer();
}

É perfeitamente legal atribuir qualquer valor a qualquer variável, pois dissemos que as variáveis ​​não têm tipo. Isso também significa que nem sempre podemos saber o tipo de uma variável, porque ela pode ser de tipos diferentes, com base em diferentes caminhos de execução.

Em geral, linguagens de tipo dinâmico são usadas para linguagens de script, onde não há etapa de compilação e, portanto, não existem erros de compilação, o que significa que as teclas extras necessárias para fornecer o tipo de variáveis ​​não seriam muito úteis.

Também existem algumas vantagens distintas em linguagens dinamicamente tipadas, principalmente em termos de menos código para implementar o mesmo design: as interfaces não precisam ser escritas, porque tudo é "tipificado" (nós apenas nos importamos com os métodos / propriedades que um objeto possui , e não a qual classe o objeto pertence), as variáveis ​​não precisam receber um tipo explícito ... com a troca que descobrimos sobre um pouco menos de bugs antes de começarmos a executar nosso código.

Theodore Murdock
fonte
Obrigado Theodore. "Mas se o compilador não souber os tipos das variáveis, não será possível avisá-lo de que você fez uma chamada inválida". Como você mencionou, o compilador pode conhecer os tipos de objetos para os quais as variáveis ​​apontam.
11442 sturdytree
Theodore: No seu exemplo james / bob, como programadores, devemos saber como usamos nossas variáveis ​​(e a boa nomeação ajuda) e, portanto, não vejo problema com isso. Quando você diz "nem sempre sabemos o tipo de uma variável", presumo que você queira dizer que nem sempre sabemos o tipo de objeto para o qual a variável aponta, mas o compilador pode resolver isso e avisar sobre a ocorrência de membros incorretos. aplicado (ou seja, podemos ter verificação estática).
11442 sturdytree
2
Dei um exemplo acima, no qual você não pode conhecer estaticamente os tipos de objetos ... dependendo do caminho da execução, o tipo de objeto armazenado em uma variável sem informações de tipo pode ser diferente. Você pode ter uma linguagem como C # em que as informações do tipo em tempo de compilação podem ser inferidas, mas, até onde eu sei, não há linguagem com verificação de tipo estática e variáveis ​​verdadeiramente sem tipo, a complexidade computacional da análise estática provavelmente também é ótimo.
Theodore Murdock
Theodore, obrigado, você entendeu corretamente que o que estou falando é uma linguagem com verificação estática de tipo (com base no tipo de objeto) e variáveis ​​sem tipo. É triste ouvir que não há - me disseram que o Python tem variáveis ​​sem tipo, mas parece que não possui verificação estática de tipo.
11442 sturdytree
11
-1; a digitação forte / fraca é ortogonal à digitação estática / dinâmica. C é estaticamente fracamente tipado; Lisp e Python são dinamicamente fortemente tipados.
Fred Foo
5

Portanto, programadores profissionais não precisam descobrir se

10 + "10"

is "1010" or 20....

O que é um erro, em tempo de compilação com uma linguagem digitada estaticamente ou em tempo de execução com uma linguagem digitada dinamicamente. Bem são, de qualquer maneira.

Tony Hopkinson
fonte
2
Ou seja, Perl não é uma linguagem sã? :)
Fred Foo
5
@ Larsmans: de fato, não, não é. mas isso é puramente opinião.
NotMe
2
@ Chrishrively: Estou feliz que é uma questão de fato agora. Por favor, venha ao meu local de trabalho a qualquer momento para convencer meus colegas Perl-amorosas;)
Fred Foo
2
10 + "10" está usando um operador '+' no objeto do tipo inteiro e no objeto do tipo string. O compilador emitirá um erro. Minha pergunta é sobre o tipo de variável, não o objeto.
22812 Sturdytree
2
Ele é válido C: É a aritmética de ponteiro.
dan04
4

Supondo que você tinha uma variável one(definida como 1) e tentou avaliar one + one. Se você não tinha idéia do tipo, 1 + 1 será ambíguo. Você pode argumentar que 2 ou 11 podem ser respostas corretas. Torna-se ambíguo se o contexto não for fornecido.

Eu já vi isso acontecer no SQLite, onde os tipos de bancos de dados foram inadvertidamente definidos em VARCHARvez de INTe quando as operações foram concluídas, as pessoas estavam obtendo resultados inesperados.

Em c #, se o contexto inferir um tipo, você pode usar a varpalavra - chave.

var c = new Customer();
var e = new Employer();

Compilará c e e com os tipos inferidos em tempo de compilação.

Stephen Quan
fonte
11
No Python, 1 + 1sempre tem o tipo int, mas não há necessidade de declarar isso. A questão é por que as variáveis têm um tipo, não valores .
Fred Foo
Desculpe, você variablesnão viu valuesquando eu usei 1 + 1no meu exemplo. Eu acho que não estava claro.
Stephen Quan
Ainda assim, idiomas tipificados dinamicamente podem lidar com isso. No Python, one=1; print(one+one)imprime 2. one="1"; print(one+one)impressões 11. O exemplo do SQLite é mais convincente, mas o problema é de digitação fraca, por isso não é realmente relevante para C #.
Fred Foo
No meu esquema sugerido, um = 1 significa uma variável apontando para um tipo inteiro (não estou sugerindo nenhum tipo - os objetos teriam um tipo). um + pode-se então não ser ambígua (estamos a adicionar dois objectos inteiros / valores)
sturdytree
11
Oi @ dan04, eu vi isso ORDER BYinadvertidamente feito em um VARCHARcampo. Consulte stackoverflow.com/questions/9103313/… .
Stephen Quan
4

Uma variável não precisa ter um tipo associado. Os idiomas em que isso é verdade incluem Lisp, Scheme, Erlang, Prolog, Smalltalk, Perl, Python, Ruby e outros.

Também é possível que uma variável tenha um tipo, mas talvez você não precise escrever o tipo no programa. Isso geralmente é chamado de inferência de tipo. ML, Haskell e seus descendentes têm uma inferência poderosa de tipo; algumas outras linguagens o possuem em formas menores, como as autodeclarações de C ++ .

O principal argumento contra a inferência de tipo é que ela prejudica a legibilidade. Geralmente é mais fácil entender o código quando os tipos são escritos.

Ryan Culpepper
fonte
1

Quando você identifica o tipo que sua variável representa, está fazendo uma declaração sobre algumas coisas. Você está identificando os requisitos de alocação de memória para sua variável e definindo regras de compatibilidade e intervalo para sua variável. Ele fornece uma maneira de evitar confusões sobre suas intenções com relação aos dados que você está armazenando e fornecer um meio relativamente barato para identificar possíveis problemas em seu código em tempo de compilação.

Se você declarar as seguintes variáveis:

myVar      = 5;
myOtherVar = "C";

O que você pode deduzir sobre essas variáveis? ÉmyVar assinado ou não assinado? É de 8 bits, 64 bits ou algo assim? É myOtherVaruma String (efetivamente uma matriz) ou um Char? É ANSI ou Unicode?

Ao fornecer tipos de dados específicos, você fornece ao compilador pistas sobre como ele pode otimizar os requisitos de memória para seu aplicativo. Alguns idiomas não se preocupam muito com esse tipo de coisa, permitindo que esses assuntos sejam tratados em tempo de execução, enquanto outros idiomas permitem uma certa quantidade de digitação dinâmica, porque, analisando o código, os tipos de dados podem ser inferidos.

Outro ponto com linguagens fortemente tipadas é que ele evita a necessidade de fornecer instruções ao compilador toda vez que você usa uma variável. Você pode imaginar o quão horrível e ilegível seu código se tornaria se toda vez que você acessasse uma variável, você fosse forçado a convertê-lo efetivamente para informar ao compilador que tipo de valor era? !!

S.Robins
fonte
Bom ponto, embora o compilador possa usar apenas o tipo mais eficiente (por exemplo, int pequeno) com base no valor, posso ver que podemos querer que "C" seja um objeto de string em vez de char, para poder executar determinadas operações . Nesses casos, porém, poderíamos apenas especificar um = (string) "C". Isso cria um objeto de string e 'a' (variável sem tipo) apenas aponta para ele. Eu não vejo isso como mais horrível do que string a = "C";
11442 sturdytree
0

Um programa de computador é um gráfico de nós do processo que descreve o que uma "máquina", representada pelo tempo de execução do idioma (estendido com kits de ferramentas na maioria dos casos) deve fazer, em que ordem ou sob quais condições. Este gráfico é representado por um arquivo de texto (ou vários arquivos de texto) escrito em um idioma específico e (parcial ou totalmente) criado quando o compilador / intérprete lê (desserializa) esse arquivo. Além disso, existem alguns ambientes (UML ou ferramentas de geração de programas gráficos) em que você pode criar esse gráfico e gerar o código-fonte em um idioma de destino.

Por que eu digo isso? Porque isso leva à resposta à sua pergunta.

O texto do programa é suas instruções sobre como o computador deve resolver a tarefa real, contendo as etapas do processo (condições, ações) E a estrutura (quais componentes você usa na solução). O último significa que você obtém ou cria algumas instâncias de outros componentes, as coloca em caixas nomeadas (variáveis) e as utiliza: acesse seus dados e serviços.

Alguns idiomas oferecem caixas uniformes, nas quais apenas o rótulo é importante, mas você pode colocar qualquer coisa nelas, você pode até usar uma variável chamada "target" para armazenar uma "Person" no início e "Car" no final de o mesmo algoritmo. Outros exigem que você crie caixas "em forma", portanto caixas diferentes para uma Pessoa ou um Carro - embora elas ainda permitam que você crie uma "caixa genérica" ​​(Objeto Java, C / C ++ void *, "Objective C" id "...) e jogue como quiser. As linguagens digitadas permitem que você expresse sua estrutura com mais detalhes, criando "contratos de tipo" para suas variáveis ​​(embora você possa burlar essa limitação), enquanto as linguagens não tipificadas suportam a abordagem "certamente saberei o que coloquei nessa caixa dessa vez" como o padrão e único comportamento.

Ambas as abordagens são viáveis, possuem inteligência de compilador, muitos livros de programação, práticas e estruturas escritas usando-as (e outras toneladas de livros sobre essas estruturas) em diferentes níveis. Portanto, hoje a resposta parece ser mais uma questão de gosto e conhecimento da equipe real do programador do que uma declaração adequadamente fundamentada, medida e verificada sobre o uso ou não de tipos.

É desnecessário dizer que prefiro regras a truques, especialmente para projetos de longo prazo em grandes equipes (também conhecidos como "sérios"). Razão: até onde eu sei, as causas mais prováveis ​​de falha / escorregamento do projeto de SW são: requisitos pouco claros e design deficiente (80%! Por um estudo que conheço), e apenas uma porcentagem permanece para a codificação real. Todas as regras e contratos impõem um design mais limpo, pensando no futuro, e exigem que as decisões sejam tomadas mais cedo e pelas pessoas apropriadas. Tipos significam regras: menos "liberdade" e "frieza" - mais preparação, pensamento, padrões de codificação, trabalho em equipe controlado. Para mim, isso parece um fator necessário para o sucesso, e também "lar, doce lar".

Meus 2 centavos.

Lorand Kedves
fonte
-3

AFIAK todos os idiomas com digitação dinâmica são idiomas interpretados. Isso já é muito ineficiente, adicionar a ineficiência da digitação dinâmica não será uma grande perda de tempo. Uma linguagem compilada, no entanto, não estará se referindo a coisas pelo nome quando estiver em execução. (Exceto o uso ocasional de reflexão .net ou similares - recursos muito lentos em comparação com o idioma subjacente.) A busca por todos esses nomes será lenta, lenta, lenta.

Loren Pechtel
fonte
3
Você sabe errado. Existem muitos compiladores para linguagens de tipo dinâmico, e alguns deles são bastante rápidos. Exemplos incluem Common Lisp, Scheme e Erlang.
22612 Ryan Culpepper
3
Não existe uma "linguagem interpretada". Uma linguagem é um conjunto abstrato de regras matemáticas. Uma linguagem não é compilada nem interpretada. Uma linguagem simplesmente é. Compilação e interpretação são características da implementação, não a linguagem. Todo idioma pode ser implementado com um intérprete e todo idioma pode ser implementado com um compilador. E praticamente todas as linguagens têm implementado interpretações e compilações, por exemplo, existem intérpretes para C e compiladores para ECMAScript, Ruby e Python.
Jörg W Mittag
-4

As linguagens de tipo dinâmico são frequentemente apresentadas como "orientadas a objetos". Eles não são. Eles podem ser orientados a encapsulamento, mas nunca orientados a objetos. A orientação a objetos tem tudo a ver com tipos.

"O garoto anda de bicicleta do irmão até o supermercado e compra um pedaço de pão na mercearia". Usando a orientação a objetos, é possível escrever imediatamente um conjunto de classes (tipos) para descrever esse cenário do mundo real.

Em uma linguagem de tipo dinâmico, o cenário só pode ser representado da seguinte maneira:

"O objeto monta o objeto do objeto até o objeto e compra um objeto do objeto".

O poder da orientação a objetos está em sua capacidade de modelar o mundo em termos naturais, de modo que o desenvolvedor de software possa usar os dois lados do cérebro para escrever software e resolver problemas mais como um ser humano, menos como um programador de computador. Esse poder está ausente em idiomas de tipo dinâmico.

A digitação estática permite melhor eficiência de codificação, reutilização e manutenção, porque os ambientes de desenvolvimento integrados conhecem os tipos de variáveis. Conhecendo os tipos de variáveis, um IDE pode fornecer o preenchimento automático para que o programador não precise se referir novamente à definição da classe para lembrar se a propriedade do membro foi digitada "backlightControl" ou "backLightControl" ou "bkLightCtrl".

A digitação estática permite refatoração automatizada, porque o IDE conhece todos os lugares em que uma variável contém uma instância do objeto que está sendo refatorado.

A digitação estática permite maior reutilização e manutenção. A digitação dinâmica é melhor para código descartável. Suponha que um novo desenvolvedor saia da rua e analise um pedaço de código existente. Se o código for digitado estaticamente, o desenvolvedor poderá, com dois cliques do mouse, examinar a definição de classe de cada uma das variáveis ​​envolvidas, saber para que serve a classe, saber para que outros métodos e propriedades estão disponíveis. Se o código for digitado dinamicamente, o desenvolvedor precisará usar a pesquisa global para descobrir o que está acontecendo.

Charlie Hand
fonte
2
Receio ter que discordar de você na primeira parte do seu argumento. Linguagens de tipo dinâmico são geralmente "orientadas a objetos", mas não "orientadas a classes". Esta é uma distinção importante. No seu exemplo, você está realmente vivendo uma ilusão. Você pode ter uma Boyaula, mas duvido que possa fazer tudo o que um "garoto" do mundo real faz. No entanto, no seu exemplo dinâmico (O objeto monta ...), sabemos a única coisa importante sobre esse objeto "menino" - ele pode montar . Essa é a filosofia básica das linguagens de tipo dinâmico. Tem + ve se-ve. Qual você gosta é a sua opinião.
Chip