Esta pergunta foi feita aqui , mas recebeu respostas ruins e não esclareceu o problema. Acredito que justifique perguntar novamente.
Entendo que você pode digitar duck com linguagens dinamicamente ou com estaticamente (mas exemplos para isso são raros, como os modelos do C ++).
No entanto, não tenho certeza se existe algo como um idioma digitado dinamicamente sem a digitação do pato.
A digitação de pato significa que o tipo de um objeto é baseado nas operações e atributos que ele possui em um determinado momento. Existe uma maneira de digitar dinamicamente sem, inevitavelmente, oferecer suporte à digitação com patos?
Vamos dar uma olhada neste código Python para o exemplo:
def func(some_object)
some_object.doSomething()
something = Toaster()
func(something)
Nas linguagens digitadas dinamicamente, o tipo de um objeto é conhecido apenas em tempo de execução. Portanto, quando você tenta fazer uma operação (por exemplo some_object.doSomething()
), o tempo de execução tem apenas uma opção - verificar se o tipo de some_object
suporte doSomething()
é ou não , e é exatamente o que é digitação de pato.
Então, é possível ter um idioma digitado dinamicamente sem digitar o pato? Por favor explique.
fonte
1 + "1"
. No caso do Python, a disciplina de verificação está praticamente ausente e cabe à implementação do código do usuário verificar os tipos se o usuário (ao contrário do tempo de execução do Python) achar útil. Observe também que a tipagem do pato versus a não-pato é semelhante à tipagem estrutural e estrutural (consulte a Wikipedia).Respostas:
Primeiro, para ter certeza de que estamos falando das mesmas coisas, eu começaria com algumas definições.
Digitação estática significa que erros de tipo são relatados em tempo de compilação, enquanto digitação dinâmica significa que erros de tipo são relatados em tempo de execução.
Digitar Duck significa que um pedaço de código requer que um objeto suporte as operações que são usadas e nada mais.
A digitação estrutural requer que um objeto suporte um determinado conjunto de operações (mesmo que algumas delas não possam ser usadas).
A digitação nominal requer que o objeto seja exatamente do tipo especificado ou seja um subtipo desse tipo.
Portanto, como você pode ver, a tipagem estrutural é mais rígida que a tipagem duck e a tipagem nominal é mais rígida que a estrutural.
Agora, vou falar sobre a linguagem TypeScript , porque ilustra bem a maioria dessas opções.
Considere o seguinte programa TypeScript:
Como o objeto transmitido
greet
não possui aAge
propriedade, isso causa um erro de tempo de compilação, demonstrando que o TypeScript usa tipografia estrutural estática .Apesar do erro, o código acima realmente compila o seguinte JavaScript, que funciona bem:
Isso mostra que o TypeScript também usa digitação dinâmica de pato .
Se o código for compilado para algo como:
Isso seria um exemplo de tipagem estrutural dinâmica , porque verifica se o objeto tem as propriedades necessárias dos tipos necessários, mesmo que a própria função não as exija.
Se compilado para:
Isso seria um exemplo de digitação nominal dinâmica , porque verifica o nome do tipo do objeto, não sua estrutura.
O que isso tudo mostra é que a digitação dinâmica sem pato é possível (estrutural e nominal). Mas essa abordagem não é usada com muita frequência, porque combina principalmente as desvantagens da digitação sem pato (você precisa especificar os tipos explicitamente; menos flexível) e a digitação dinâmica (os erros de tipo são exibidos apenas no tempo de execução e apenas no código que realmente é executado) )
Se você quiser adicionar anotações de tipo para possibilitar a digitação sem pato, verifique os tipos em tempo de compilação.
fonte
[3,4]
para algum método de uma coleção mantendo[1,2]
rendimento[1,2,3,4]
, e passar[3,4]
para algum método de uma coleção[1,2]
teria[4,6]
, os métodos deveriam ter o mesmo nome? Chamando o primeiroSequence$Appendable$Add
e o segundo,NumericVector$Add
mas depois sendo capaz de dizer que uma variável deve ser interpretada como umaSequence
ouNumericVector
... #tsc
é uma interface para isso. Se você usar a biblioteca, ela acionará um evento. Por padrão, se nada estiver escutando, você obtém um script. Se você ouvir e lançar uma exceção, poderá impedir que o script seja gerado. Isso muda o sistema de tipos do TypeScript? Claro que não.Aparentemente (pelo que li), a tipagem de pato tem significado apenas em um contexto orientado a objetos, quando funções são anexadas como métodos a objetos. Então, quando você escreve
duck.quacks(3)
, isso vai funcionar se o valor atual deduck
tem o métodoquacks
.A digitação dinâmica não é necessariamente anexada a uma exibição OO com métodos.
Você pode definir o tipo
real
com operador ou função associada+: real*real->real
e o tiporational
com o operador associado+: rational*rational->rational
. Então, se você escrevera+b
, em um sistema de tempo verificado dinamicamente, suas variáveisa
eb
poderá ter um+
operador, mas você receberá um erro do tipo em tempo de execução.A digitação dinâmica verifica a consistência categorial dos valores, possivelmente vários deles.
A digitação do Duck verifica a consistência comportamental do código com um objeto em mãos (um único, tanto quanto eu o entendo).
Em certo sentido, a tipagem de pato é uma forma de polimorfismo de tempo de execução, exceto pelo fato de que se aplica apenas aos métodos de acesso de um único objeto.
No entanto, é possível definir uma forma mais geral de polimorfismo em tempo de execução, em que o operador
+
a ser executado seria determinado com base em todos os argumentos. Para que um pato e uma galinha possam danse juntos se compartilharem uma função danse comum. Eles podem ter vários, para que os patos possam danse também com gansos com uma função diferente. Mas isso parece um pouco complicado. Tanto quanto me lembro, algo do tipo (provavelmente com mais estrutura) pode ter sido possível com as funções genéricas da linguagem EL1 , um precursor muito antigo das linguagens orientadas a objetos.fonte
Uma resposta por analogia:
Você pode comprar um conversível e nunca largar a capota? Certo. Provavelmente não é a melhor maneira de gastar seus recursos, já que você é pago a mais por alguns recursos (por exemplo, capota conversível, reforço estrutural extra devido à falta de teto como elemento estrutural) e obteve alguns resultados piores (por exemplo, ruído extra na estrada, possivelmente menor) segurança contra colisões, compartimentos de armazenamento menores) como resultado do investimento nesse recurso que você não usará. Mas é tecnicamente viável.
É o mesmo com idiomas dinâmicos e digitação de pato. Você desistiu da maior eficiência e das garantias de segurança do tipo tempo de compilação das linguagens estáticas. Para quê? Geralmente pela simplicidade da digitação de patos. Variáveis e coleções podem conter qualquer coisa, e você não precisa especificar muito o que é necessário. Coleções mistas como
[ 12, "gumbo", 12.4, 4+4j ]
(um número inteiro, uma sequência de caracteres, um valor de ponto flutuante e um valor complexo) são triviais e você não tem a conversão de tipo constante que vê no código Java (por exemplo).É possível em uma linguagem dinâmica como o Python criar objetos que não são do tipo pato:
Mas, como você pode notar, não há uma verificação real dos tipos, e cada um dos métodos é implementado com uma estrutura interna do tipo pato (
list
). Depois de pagar o preço pelo dinamismo, você também pode colocar o topo para baixo e obter a simplicidade resultante:fonte
Hungarian
classe não é digitada? Como você apontou, não há verificação de tipos.NotHungarian
faz. A digitação com pato depende não apenas da verificação do tipo, mas também do uso do mesmo nome de chamada / método / mensagem (add
). (NotHungarian
Também usa um nome de método,add
que de comum com outros objetos Python, comoset
It "grasna" como os outros objetos / classes..)eval
inviáveis. A motivação nunca foi se livrar dos tipos, e algumas linguagens dinâmicas têm "digitação gradual". O MJD tem uma boa apresentação sobre tipagem estática versus dinâmica.