Me deparei com o termo digitação de pato enquanto lia tópicos aleatórios no software on-line e não o entendia completamente.
O que é "digitação de pato"?
Me deparei com o termo digitação de pato enquanto lia tópicos aleatórios no software on-line e não o entendia completamente.
O que é "digitação de pato"?
Respostas:
É um termo usado em linguagens dinâmicas que não possuem digitação forte .
A idéia é que você não precisa de um tipo para chamar um método existente em um objeto - se um método estiver definido nele, você poderá invocá-lo.
O nome vem da frase "Se parece um pato e grasna como um pato, é um pato".
A Wikipedia tem muito mais informações.
A digitação com pato significa que uma operação não especifica formalmente os requisitos que seus operandos devem atender, mas apenas tenta com o que é fornecido.
Ao contrário do que outros disseram, isso não está necessariamente relacionado a linguagens dinâmicas ou problemas de herança.
Tarefa de exemplo: chame algum método Quack
em um objeto.
Sem usar a digitação de pato, uma função que f
executa esta tarefa deve especificar antecipadamente que seu argumento deve suportar algum método Quack
. Uma maneira comum é o uso de interfaces
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
A chamada f(42)
falha, mas f(donald)
funciona desde que donald
seja uma instância de um IQuack
subtipo.
Outra abordagem é a tipagem estrutural - mas, novamente, o método Quack()
é formalmente especificado. Qualquer coisa que não possa provar quack
com antecedência causará uma falha no compilador.
def f(x : { def Quack() : Unit }) = x.Quack()
Poderíamos até escrever
f :: Quackable a => a -> IO ()
f = quack
em Haskell, onde a Quackable
classe garante a existência do nosso método.
Bem, como eu disse, um sistema de digitação de pato não especifica requisitos, mas apenas tenta se algo funcionar .
Assim, um sistema de tipo dinâmico como o do Python sempre usa digitação de pato:
def f(x):
x.Quack()
Se f
obtiver um a de x
suporte Quack()
, tudo estará bem; caso contrário, ele falhará em tempo de execução.
Mas a digitação com patos não implica em digitação dinâmica - na verdade, existe uma abordagem de digitação com patos muito popular, mas completamente estática, que também não fornece requisitos:
template <typename T>
void f(T x) { x.Quack(); }
A função não diz de forma alguma que ela quer algo x
que possa Quack
, então, em vez disso, apenas tenta em tempo de compilação e, se tudo funcionar, tudo bem.
def f(x)
em vez de def f(IQuack x)
.
A discussão da semântica da pergunta é bastante sutil (e muito acadêmica), mas aqui está a ideia geral:
Digitação de pato
(“Se ele anda como um pato e grasna como um pato, então é um pato.”) - SIM! Mas o que isso significa??! Isso é melhor ilustrado pelo exemplo:
Exemplos de funcionalidade Duck Typing:
Imagine que eu tenho uma varinha mágica. Tem poderes especiais. Se eu acenar com a varinha e disser "Dirija!" para um carro, então ele dirige!
Isso funciona em outras coisas? Não tenho certeza: então eu tento em um caminhão. Uau - ele dirige também! Em seguida, tento em aviões, trens e 1 Woods (eles são um tipo de taco de golfe que as pessoas usam para 'dirigir' uma bola de golfe). Todos eles dirigem!
Mas funcionaria, digamos, uma xícara de chá? Erro: KAAAA-BOOOOOOM! isso não funcionou tão bem. ====> Xícaras de chá não podem dirigir !! duh !?
Este é basicamente o conceito de digitação de pato. É um sistema de experimentar antes de comprar . Se funcionar, está tudo bem. Mas se falhar, como uma granada ainda na sua mão, vai explodir na sua cara.
Em outras palavras, estamos interessados no que o objeto pode fazer , e não no que o objeto é .
Exemplo: idiomas de tipo estaticamente
Se estivéssemos preocupados com o que o objeto realmente era , nosso truque de mágica funcionará apenas em tipos autorizados predefinidos - nesse caso, carros, mas falhará em outros objetos que podem dirigir : caminhões, ciclomotores, tuk-tuks etc. Não funciona em caminhões, porque nossa varinha mágica espera que funcione apenas em carros .
Em outras palavras, nesse cenário, a varinha mágica olha muito de perto o que o objeto é (é um carro?) E não o que o objeto pode fazer (por exemplo, se carros, caminhões etc. podem dirigir).
A única maneira de conseguir um caminhão para dirigir é se, de alguma forma, conseguir que a varinha mágica espere caminhões e carros (talvez "implementando uma interface comum"). Se você não sabe o que isso significa, basta ignorá-lo por enquanto.
Resumo: retirada principal
O que é importante na digitação do pato é o que o objeto pode realmente fazer, e não o que o objeto é .
Considere que você está criando uma função simples, que obtém um objeto do tipo Bird
e chama seu walk()
método. Existem duas abordagens, nas quais você pode pensar:
Bird
código ou o código não será compilado. Se alguém quiser usar a minha função, ele deve estar ciente de que eu só aceitar Bird
sobjects
e eu apenas chamo o walk()
método do objeto . Portanto, se a object
lata walk()
estiver correta, se não puder, minha função falhará. Portanto, aqui não é importante que o objeto seja um Bird
ou qualquer outra coisa, é importante que ele possa walk()
(esta é a digitação do pato )Deve-se considerar que a digitação do pato pode ser útil em alguns casos, por exemplo, o Python usa muito a digitação do pato .
A Wikipedia tem uma explicação bastante detalhada:
http://en.wikipedia.org/wiki/Duck_typing
A tipagem duck é um estilo de digitação dinâmica, no qual o conjunto atual de métodos e propriedades de um objeto determina a semântica válida, em vez de sua herança de uma classe específica ou implementação de uma interface específica.
A observação importante é provável que, com a digitação do duck, um desenvolvedor se preocupe mais com as partes do objeto que são consumidas do que com o tipo subjacente real.
Vejo muitas respostas que repetem o idioma antigo:
Se parece um pato e grasna como um pato, é um pato
e depois explique o que você pode fazer com a digitação de patos, ou um exemplo que parece ofuscar ainda mais o conceito.
Não encontro muita ajuda.
Esta é a melhor tentativa de uma resposta simples em inglês sobre digitação de patos que eu encontrei:
Duck Typing significa que um objeto é definido pelo que ele pode fazer, não pelo que é.
Isso significa que estamos menos preocupados com a classe / tipo de um objeto e mais preocupados com quais métodos podem ser chamados e quais operações podem ser executadas nele. Não nos preocupamos com o seu tipo, nos preocupamos com o que ele pode fazer .
Digitação de pato:
Se ele fala e anda como um pato, então é um pato
Isso geralmente é chamado de abdução ( raciocínio abdutivo ou também chamado de retrodução , uma definição mais clara, eu acho):
de C (conclusão, o que vemos ) e R (regra, o que sabemos ), aceitamos / decidimos / assumimos P (Premissa, propriedade ) em outras palavras, um dado fato
... a própria base do diagnóstico médico
com patos: C = passeios, conversas , R = como um pato , P = é um pato
Voltar à programação:
objeto o possui método / propriedade mp1 e interface / tipo T requer / define mp1
objeto o possui método / propriedade mp2 e interface / tipo T requer / define mp2
...
Portanto, mais do que simplesmente aceitar mp1 ... em qualquer objeto, desde que ele atenda a alguma definição de mp1 ..., o compilador / tempo de execução também deve estar bem com a afirmação o é do tipo T
E bem, é o caso dos exemplos acima? A digitação com Duck é essencialmente sem digitação? Ou deveríamos chamá-lo de digitação implícita?
Olhar para o próprio idioma pode ajudar; isso geralmente me ajuda (não sou um falante nativo de inglês).
Em duck typing
:
1) a palavra typing
não significa digitar em um teclado (como era a imagem persistente em minha mente), significa determinar " que tipo de coisa é essa coisa? "
2) a palavra duck
expressa como é feita essa determinação; é uma espécie de determinação 'solta', como em: " se andar como um pato ... então é um pato ". É "frouxo" porque a coisa pode ser um pato ou não, mas se realmente é um pato não importa; o que importa é que eu possa fazer com ele o que posso fazer com patos e esperar comportamentos exibidos por patos. Eu posso alimentá-lo com migalhas de pão e a coisa pode ir em minha direção, atacar ou recuar ... mas não vai me devorar como um urso pardo.
Eu sei que não estou dando uma resposta generalizada. Em Ruby, não declaramos os tipos de variáveis ou métodos - tudo é apenas algum tipo de objeto. Portanto, a regra é "Classes não são tipos"
Em Ruby, a classe nunca é (OK, quase nunca) o tipo. Em vez disso, o tipo de um objeto é definido mais pelo que esse objeto pode fazer. Em Ruby, chamamos isso de digitação de pato. Se um objeto anda como um pato e fala como um pato, o intérprete fica feliz em tratá-lo como se fosse um pato.
Por exemplo, você pode estar escrevendo uma rotina para adicionar informações da música a uma string. Se você tem experiência em C # ou Java, pode ser tentado a escrever o seguinte:
def append_song(result, song)
# test we're given the right parameters
unless result.kind_of?(String)
fail TypeError.new("String expected") end
unless song.kind_of?(Song)
fail TypeError.new("Song expected")
end
result << song.title << " (" << song.artist << ")" end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Aceite a digitação de pato de Ruby e você escreveria algo muito mais simples:
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Você não precisa verificar o tipo dos argumentos. Se eles suportarem << (no caso de resultado) ou título e artista (no caso de música), tudo funcionará. Se não o fizerem, seu método lançará uma exceção de qualquer maneira (como faria se você tivesse verificado os tipos). Mas sem a verificação, seu método fica subitamente muito mais flexível. Você pode passar uma matriz, uma string, um arquivo ou qualquer outro objeto que acrescente usando <<, e funcionaria.
A digitação de pato não é uma dica de tipo!
Basicamente, para usar a "tipagem de pato", você não terá como alvo um tipo específico, mas uma variedade maior de subtipos (sem falar em herança, quando eu quero dizer subtipos, quero dizer "coisas" que se encaixam nos mesmos perfis) usando uma interface comum .
Você pode imaginar um sistema que armazena informações. Para escrever / ler informações, você precisa de algum tipo de armazenamento e informações.
Os tipos de armazenamento podem ser: arquivo, banco de dados, sessão etc.
A interface informará as opções disponíveis (métodos), independentemente do tipo de armazenamento, o que significa que, neste momento, nada é implementado! Em outras palavras, a Interface não sabe nada sobre como armazenar informações.
Todo sistema de armazenamento deve conhecer a existência da interface implementando os mesmos métodos.
interface StorageInterface
{
public function write(string $key, array $value): bool;
public function read(string $key): array;
}
class File implements StorageInterface
{
public function read(string $key): array {
//reading from a file
}
public function write(string $key, array $value): bool {
//writing in a file implementation
}
}
class Session implements StorageInterface
{
public function read(string $key): array {
//reading from a session
}
public function write(string $key, array $value): bool {
//writing in a session implementation
}
}
class Storage implements StorageInterface
{
private $_storage = null;
function __construct(StorageInterface $storage) {
$this->_storage = $storage;
}
public function read(string $key): array {
return $this->_storage->read($key);
}
public function write(string $key, array $value): bool {
return ($this->_storage->write($key, $value)) ? true : false;
}
}
Então agora, toda vez que você precisar escrever / ler informações:
$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');
$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');
Neste exemplo, você acaba usando o construtor Duck Typing in Storage:
function __construct(StorageInterface $storage) ...
Espero que tenha ajudado;)
Eu acho que é confuso misturar digitação dinâmica, estática e pato. A digitação com patos é um conceito independente e até mesmo a linguagem estática, como Go, pode ter um sistema de verificação de tipos que implementa a digitação com patos. Se um sistema de tipos verificar os métodos de um objeto (declarado), mas não o tipo, isso poderá ser chamado de linguagem de digitação duck.
Tento entender a famosa frase do meu jeito: "Python não liga para um objeto ser um pato real ou não. Tudo o que importa é se o objeto, primeiro 'charlatão', segundo 'como um pato'".
Existe um bom site. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14
O autor apontou que a digitação com patos permite criar suas próprias classes que possuem sua própria estrutura de dados interna - mas são acessadas usando a sintaxe normal do Python.