Apa itu mengetik bebek?

429

Saya menemukan istilah mengetik bebek sambil membaca topik acak pada perangkat lunak online dan tidak sepenuhnya memahaminya.

Apa itu "mengetik bebek"?

sushil bharwani
sumber
1
@Mitch saya mencoba dan mendapatkan sesuatu sebagai bentuk warisan. Tetapi tidak bisa mengikuti banyak. Maaf jika saya menanyakan pertanyaan yang salah.
sushil bharwani
3
@sushil bharwani: tidak, tidak marah. Tetapi orang-orang berharap bahwa sebagai port of call pertama (yaitu hal pertama yang Anda lakukan) adalah mencoba mencari sebelum memposting di sini.
Mitch Wheat
104
Mengingat argumen di atas, tampaknya stackoverflow sebenarnya tidak diperlukan karena saya yakin hampir setiap pertanyaan yang dapat dipikirkan dijawab di suatu tempat di internet, dan jika tidak jawabannya mungkin dapat diperoleh dengan lebih mudah dan tanpa kritik dengan mengirim email kepada teman berpengetahuan. Saya pikir banyak dari Anda telah melewatkan titik stackoverflow.
rhody
41
Saya yakin saya pernah membaca bahwa SO dimaksudkan untuk menjadi "gudang pertanyaan kanonik", dan saya cukup yakin Anda tidak bisa mendapatkan lebih banyak kanonik daripada yang ini.
heltonbiker

Jawaban:

302

Ini adalah istilah yang digunakan dalam bahasa dinamis yang tidak memiliki ketikan yang kuat .

Idenya adalah bahwa Anda tidak perlu tipe untuk memohon metode yang ada pada objek - jika metode didefinisikan, Anda dapat memohonnya.

Namanya berasal dari ungkapan "Jika terlihat seperti bebek dan dukun seperti bebek, itu bebek".

Wikipedia memiliki lebih banyak informasi.

Oded
sumber
25
Berhati-hatilah menggunakan Strong Typing. Ini tidak didefinisikan dengan baik. Mengetik Bebek juga tidak. Google Go atau Ocaml adalah bahasa yang diketik secara statis dengan konstruksi subtyping struktural. Apakah ini bahasa yang diketik bebek?
SAYA MEMBERI JAWABAN CRAP
7
frasa yang lebih baik untuk mengetik bebek adalah: "Jika dikatakan itu adalah bebek .. well itu cukup baik untuk saya." lihat pyvideo.org/video/1669/keynote-3 28:30 atau youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod
7
Mengetik bebek tidak harus hanya digunakan dalam bahasa dinamis. Objective-C bukan bahasa yang dinamis dan menggunakan mengetik bebek.
eyuelt
12
Baik Python dan Ruby adalah bahasa yang diketik dengan kuat dan keduanya memiliki Mengetik Bebek. Mengetik String tidak berarti tidak memiliki Mengetik Bebek.
alanjds
8
Saya downvoting ini. Duck ducking tidak ada hubungannya dengan kekuatan tipe, hanya kemampuan untuk dapat menggunakan objek apa pun yang memiliki metode, apakah itu mengimplementasikan antarmuka atau tidak.
e-satis
209

Mengetik bebek berarti bahwa suatu operasi tidak secara formal menentukan persyaratan yang harus dipenuhi operandnya, tetapi hanya mencobanya dengan apa yang diberikan.

Tidak seperti apa yang dikatakan orang lain, ini tidak selalu berhubungan dengan bahasa yang dinamis atau masalah warisan.

Contoh tugas: Memanggil beberapa metode Quackpada objek.

Tanpa menggunakan bebek-mengetik, fungsi fmelakukan tugas ini harus menentukan terlebih dahulu bahwa argumennya harus mendukung beberapa metode Quack. Cara yang umum adalah penggunaan antarmuka

interface IQuack { 
    void Quack();
}

void f(IQuack x) { 
    x.Quack(); 
}

Panggilan f(42)gagal, tetapi f(donald)berfungsi selama donaldmerupakan instance dari IQuack-subtype.

Pendekatan lain adalah pengetikan struktural - tetapi sekali lagi, metode Quack()ini secara formal menentukan segala hal yang tidak dapat membuktikannya quackterlebih dahulu akan menyebabkan kegagalan kompiler.

def f(x : { def Quack() : Unit }) = x.Quack() 

Kami bahkan bisa menulis

f :: Quackable a => a -> IO ()
f = quack

di Haskell, di mana Quackabletypeclass memastikan keberadaan metode kami.


Jadi bagaimana cara mengetik bebek mengubah ini?

Yah, seperti yang saya katakan, sistem mengetik bebek tidak menentukan persyaratan tetapi hanya mencoba jika ada yang berhasil .

Dengan demikian, sistem tipe dinamis seperti Python selalu menggunakan mengetik bebek:

def f(x):
    x.Quack()

Jika fmendapat xdukungan Quack(), semuanya baik-baik saja, jika tidak, itu akan macet saat runtime.

Tetapi mengetik bebek tidak menyiratkan mengetik dinamis sama sekali - pada kenyataannya, ada pendekatan mengetik bebek yang sangat populer tetapi benar-benar statis yang tidak memberikan persyaratan apa pun juga:

template <typename T>
void f(T x) { x.Quack(); } 

Fungsi tidak mengatakan dengan cara apa pun bahwa ia menginginkan beberapa xyang bisa Quack, jadi alih-alih hanya mencoba pada waktu kompilasi dan jika semuanya berfungsi, itu baik-baik saja.

Dario
sumber
5
bukan maksud Anda: void f (IQuak x) {x.Quak (); } (bukan K.Quack) karena parameter fungsi f adalah IQuack x bukan Iquack k, kesalahan yang sangat kecil tapi saya merasa seperti itu perlu diperbaiki :)
dominicbri7
Menurut Wikipedia, contoh terakhir Anda adalah "mengetik struktural", bukan "mengetik bebek".
Brilliand
Yah, sepertinya ada pertanyaan terpisah untuk diskusi itu: stackoverflow.com/questions/1948069/…
Brilliand
1
Jadi jika saya mengerti apa yang Anda katakan, perbedaan antara bahasa yang mendukung pengetikan bebek dan yang tidak hanya dengan pengetikan bebek, Anda tidak harus menentukan jenis objek yang diterima fungsi? def f(x)bukannya def f(IQuack x).
PProteus
124

Penjelasan Sederhana (tanpa kode)

Diskusi semantik dari pertanyaan ini cukup bernuansa (dan sangat akademis), tapi inilah ide umum:

Mengetik Bebek

(“Jika berjalan seperti bebek dan dukun seperti bebek maka itu adalah bebek.”) - YA! tapi apa artinya itu ??! Ini paling baik digambarkan dengan contoh:

Contoh fungsionalitas Mengetik Bebek:

Bayangkan saya punya tongkat sihir. Ia memiliki kekuatan khusus. Jika saya melambaikan tongkat dan berkata "Berkendara!" ke mobil, lalu, itu drive!

Apakah ini berhasil pada hal lain? Tidak yakin: jadi saya mencobanya di truk. Wow - itu drive juga! Saya kemudian mencobanya di pesawat, kereta api dan 1 Woods (mereka adalah jenis klub golf yang digunakan orang untuk 'menggerakkan' bola golf). Mereka semua mengemudi!

Tetapi apakah itu akan berhasil pada kata, cangkir teh? Kesalahan: KAAAA-BOOOOOOM! itu tidak berhasil begitu baik. ====> Cangkir teh tidak bisa mengemudi !! ya !?

Ini pada dasarnya konsep mengetik bebek. Ini adalah sistem coba-sebelum-Anda-beli . Jika berhasil, semuanya baik-baik saja. Tetapi jika gagal, seperti granat masih di tangan Anda, itu akan meledak di wajah Anda.

Dengan kata lain, kita tertarik pada apa yang bisa dilakukan objek , daripada dengan apa objek itu .

Contoh: bahasa yang diketik secara statis

Jika kita khawatir dengan apa objek itu sebenarnya , maka trik sulap kita hanya akan bekerja pada tipe yang telah ditentukan sebelumnya - dalam hal ini mobil, tetapi akan gagal pada objek lain yang dapat mengemudi : truk, moped, tuk-tuk, dll. Ini tidak akan berfungsi pada truk karena tongkat sihir kami mengharapkannya hanya bekerja pada mobil .

Dengan kata lain, dalam skenario ini, keajaiban tongkat terlihat sangat erat pada apa benda itu adalah (itu mobil?) Daripada apa benda dapat melakukan (misalnya apakah mobil, truk dll bisa berkendara).

Satu-satunya cara Anda bisa mendapatkan truk untuk dikendarai adalah jika Anda entah bagaimana bisa mendapatkan tongkat ajaib untuk mengharapkan truk dan mobil (mungkin dengan "menerapkan antarmuka umum"). Jika Anda tidak tahu apa artinya itu maka abaikan saja untuk saat ini.

Ringkasan: Pengambilan kunci

Apa yang penting dalam mengetik bebek adalah apa benda itu benar-benar dapat lakukan, bukan apa benda itu adalah .

BKSpurgeon
sumber
Saya menemukan premis yang menarik tentang Anda lebih peduli tentang perilaku, itu definisi. Tidak diragukan lagi BDD sangat sukses dalam bahasa seperti ruby.
Pablo Olmos de Aguilera C.
27

Anggap Anda sedang mendesain fungsi sederhana, yang mendapatkan objek bertipe Birddan memanggil walk()metodenya. Ada dua pendekatan yang dapat Anda pikirkan:

  1. Ini adalah fungsi saya dan saya harus yakin bahwa itu hanya menerima Bird, atau kode mereka tidak akan dikompilasi. Jika ada yang ingin menggunakan fungsi saya, ia harus sadar bahwa saya hanya menerima Birds
  2. Fungsi saya mendapatkan objectsdan saya hanya memanggil walk()metode objek. Jadi, jika objectbisa walk()itu benar, jika tidak bisa fungsi saya akan gagal. Jadi di sini tidak penting objeknya adalah Birdsesuatu atau apa pun, penting bahwa itu bisa walk() (Ini adalah mengetik bebek )

Harus dipertimbangkan bahwa mengetik bebek mungkin berguna dalam beberapa kasus, misalnya Python menggunakan banyak mengetik bebek .


Bacaan yang bermanfaat

Alireza Fattahi
sumber
1
Penjelasan yang bagus, Apa keuntungannya?
sushil bharwani
2
Jawaban ini sederhana, jelas, dan mungkin yang terbaik untuk pemula. Baca jawaban ini bersama dengan jawaban di atasnya (atau jika bergerak, jawaban yang berbicara tentang mobil dan cangkir teh)
DORRITO
18

Wikipedia memiliki penjelasan yang cukup rinci:

http://en.wikipedia.org/wiki/Duck_typing

duck typing adalah gaya pengetikan dinamis di mana serangkaian metode dan properti objek saat ini menentukan semantik yang valid, bukan warisannya dari kelas tertentu atau implementasi antarmuka tertentu.

Catatan penting adalah kemungkinan bahwa dengan mengetik bebek pengembang lebih mementingkan bagian-bagian dari objek yang dikonsumsi daripada apa yang mendasari tipe sebenarnya.

Chris Baxter
sumber
13

Saya melihat banyak jawaban yang mengulangi ungkapan lama:

Jika terlihat seperti bebek dan dukun seperti bebek, itu bebek

dan kemudian terjun ke penjelasan tentang apa yang dapat Anda lakukan dengan mengetik bebek, atau contoh yang tampaknya mengaburkan konsep lebih lanjut.

Saya tidak menemukan banyak bantuan.

Ini adalah upaya terbaik untuk jawaban bahasa Inggris yang sederhana tentang mengetik bebek yang saya temukan:

Mengetik Bebek berarti bahwa suatu objek ditentukan oleh apa yang dapat dilakukannya, bukan oleh apa itu.

Ini berarti bahwa kita kurang peduli dengan kelas / jenis objek dan lebih peduli dengan metode apa yang dapat dipanggil dan operasi apa yang dapat dilakukan di atasnya. Kami tidak peduli dengan tipenya, kami peduli dengan apa yang bisa dilakukannya .

Gerard Simpson
sumber
3

Mengetik bebek:

Jika berbicara dan berjalan seperti bebek, maka itu adalah bebek

Ini biasanya disebut penculikan ( abductive reasoning atau juga disebut retroduction , menurut saya definisi yang lebih jelas):

  • dari C (kesimpulan, apa yang kita lihat ) dan R (aturan, apa yang kita ketahui ), kita menerima / memutuskan / menganggap P (Premis, properti ) dengan kata lain fakta yang diberikan

    ... dasar diagnosis medis

    dengan bebek: C = berjalan, berbicara , R = seperti bebek , P = itu bebek

Kembali ke pemrograman:

  • objek o memiliki metode / properti mp1 dan antarmuka / tipe T membutuhkan / mendefinisikan mp1

  • objek o memiliki metode / properti mp2 dan antarmuka / tipe T membutuhkan / mendefinisikan mp2

  • ...

Jadi, lebih dari sekadar menerima mp1 ... pada objek apa pun asalkan telah memenuhi beberapa definisi mp1 ..., compiler / runtime juga harus baik-baik saja dengan pernyataan o adalah tipe T

Dan baiklah, apakah demikian halnya dengan contoh-contoh di atas? Apakah mengetik Bebek pada dasarnya tidak mengetik sama sekali? Atau haruskah kita menyebutnya pengetikan tersirat?

Djee
sumber
3

Melihat bahasa itu sendiri dapat membantu; itu sering membantu saya (saya bukan penutur bahasa Inggris asli).

Dalam duck typing:

1) kata typingitu tidak berarti mengetik pada keyboard (seperti gambar yang terus-menerus ada dalam pikiran saya), itu berarti menentukan " jenis benda apa itu? "

2) kata tersebut duckmengungkapkan bagaimana penentuan itu dilakukan; itu semacam penentu 'longgar', seperti dalam: " jika berjalan seperti bebek ... maka itu bebek ". Ini 'longgar' karena benda itu mungkin bebek atau bukan, tetapi apakah itu sebenarnya bebek, tidak masalah; yang penting adalah saya bisa melakukannya dengan apa yang bisa saya lakukan dengan bebek dan mengharapkan perilaku yang ditunjukkan oleh bebek. Saya bisa memberi makan remah roti dan hal itu mungkin pergi ke arah saya atau menagih ke saya atau mundur ... tapi itu tidak akan melahap saya seperti yang grizzly.

Arta
sumber
2

Saya tahu saya tidak memberikan jawaban umum. Di Ruby, kami tidak mendeklarasikan jenis variabel atau metode — semuanya hanya semacam objek. Jadi Aturannya adalah "Kelas Bukan Jenis"

Di Ruby, kelasnya bukan tipe (OK, hampir tidak pernah). Sebaliknya, jenis objek lebih ditentukan oleh apa yang bisa dilakukan objek itu. Di Ruby, kami menyebutnya mengetik bebek. Jika suatu benda berjalan seperti bebek dan berbicara seperti bebek, maka penerjemah dengan senang hati memperlakukannya seolah-olah itu adalah bebek.

Misalnya, Anda mungkin menulis rutin untuk menambahkan informasi lagu ke string. Jika Anda berasal dari latar belakang C # atau Java, Anda mungkin tergoda untuk menulis ini:

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)"

Merangkul mengetik bebek Ruby, dan Anda akan menulis sesuatu yang jauh lebih sederhana:

def append_song(result, song)
    result << song.title << " (" << song.artist << ")"
end

result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

Anda tidak perlu memeriksa jenis argumen. Jika mereka mendukung << (dalam hal hasil) atau judul dan artis (dalam hal lagu), semuanya akan berfungsi dengan baik. Jika tidak, metode Anda akan memunculkan pengecualian (seperti yang akan dilakukan jika Anda memeriksa jenisnya). Tetapi tanpa pemeriksaan, metode Anda tiba-tiba jauh lebih fleksibel. Anda bisa memberikannya array, string, file, atau objek lain yang ditambahkan menggunakan <<, dan itu hanya akan berfungsi.

menangkis
sumber
2

Mengetik Bebek bukan Tipe Petunjuk!

Pada dasarnya untuk menggunakan "mengetik bebek" Anda tidak akan menargetkan jenis tertentu tetapi lebih banyak subtipe (tidak berbicara tentang warisan, ketika saya maksudkan subtipe yang saya maksudkan "hal-hal" yang sesuai dengan profil yang sama) dengan menggunakan antarmuka umum .

Anda dapat membayangkan suatu sistem yang menyimpan informasi. Untuk menulis / membaca informasi, Anda memerlukan semacam penyimpanan dan informasi.

Jenis penyimpanan mungkin: file, basis data, sesi dll.

Antarmuka akan memberi tahu Anda opsi (metode) yang tersedia terlepas dari jenis penyimpanannya, artinya pada saat ini tidak ada yang diterapkan! Dengan kata lain Antarmuka tidak tahu apa-apa tentang cara menyimpan informasi.

Setiap sistem penyimpanan harus mengetahui keberadaan antarmuka dengan menerapkan metode yang sangat sama.

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;
    }
}

Jadi sekarang, setiap kali Anda perlu menulis / membaca informasi:

$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');

Dalam contoh ini Anda akhirnya menggunakan konstruktor Duck Typing in Storage:

function __construct(StorageInterface $storage) ...

Semoga ini bisa membantu;)

obinoob
sumber
2

Tree Traversal dengan teknik mengetik bebek

def traverse(t):
    try:
        t.label()
    except AttributeError:
        print(t, end=" ")
    else:
        # Now we know that t.node is defined
        print('(', t.label(), end=" ")
        for child in t:
            traverse(child)
        print(')', end=" ")
Rajat
sumber
0

Saya pikir itu bingung untuk mencampur pengetikan dinamis, pengetikan statis dan pengetikan bebek. Mengetik bebek adalah konsep independen dan bahkan bahasa yang diketik statis seperti Go, dapat memiliki sistem pengecekan tipe yang mengimplementasikan pengetikan bebek. Jika sistem tipe akan memeriksa metode objek (dideklarasikan) objek tetapi bukan tipenya, ini bisa disebut bahasa pengetikan bebek.

es
sumber
-1

Saya mencoba memahami kalimat terkenal dengan cara saya: "Dosis ular sanca tidak peduli objek adalah bebek nyata atau tidak. Yang penting adalah apakah objek, pertama 'dukun', kedua 'seperti bebek'."

Ada situs web yang bagus. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

Penulis menunjukkan bahwa mengetik bebek memungkinkan Anda membuat kelas Anda sendiri yang memiliki struktur data internal sendiri - tetapi diakses menggunakan sintaksis Python normal.

Robin
sumber