Apa saja batasan gaya yang wajar pada inferensi tipe?


8

C ++ 0x menambahkan dukungan inferensi tipe komprehensif yang sangat sangat rumit. Saya sangat tergoda untuk menggunakannya sedapat mungkin untuk menghindari pengulangan yang tidak semestinya, tapi saya bertanya-tanya apakah menghapus informasi jenis eksplisit di semua tempat adalah ide yang bagus. Pertimbangkan contoh yang agak dibuat-buat ini:

Foo.h:

#include <set>

class Foo {
private:

    static std::set<Foo*> instances;

public:

    Foo();
    ~Foo();

    // What does it return? Who cares! Just forward it!
    static decltype(instances.begin()) begin() {
        return instances.begin();
    }

    static decltype(instances.end()) end() {
        return instances.end();
    }

};

Foo.cpp:

#include <Foo.h>
#include <Bar.h>

// The type need only be specified in one location!
// But I do have to open the header to find out what it actually is.
decltype(Foo::instances) Foo::instances;

Foo() {

    // What is the type of x?
    auto x = Bar::get_something();

    // What does do_something() return?
    auto y = x.do_something(*this);

    // Well, it's convertible to bool somehow...
    if (!y) throw "a constant, old school";

    instances.insert(this);

}

~Foo() {
    instances.erase(this);
}

Apakah Anda mengatakan ini masuk akal, atau benar-benar konyol? Lagi pula, terutama jika Anda terbiasa berkembang dalam bahasa yang dinamis, Anda tidak benar-benar perlu peduli banyak tentang jenis hal, dan dapat percaya bahwa kompiler akan menangkap setiap penyalahgunaan mengerikan dari sistem tipe. Tetapi bagi Anda yang mengandalkan dukungan editor untuk tanda tangan metode, Anda kurang beruntung, jadi menggunakan gaya ini di antarmuka perpustakaan mungkin merupakan praktik yang sangat buruk.

Saya menemukan bahwa menulis hal-hal dengan semua jenis yang mungkin implisit sebenarnya membuat kode saya jauh lebih mudah bagi saya untuk diikuti, karena menghapus hampir semua kekacauan biasa dari C ++. Jarak tempuh Anda mungkin, tentu saja, bervariasi, dan itulah yang saya minati. Apa keuntungan dan kerugian spesifik dari penggunaan radikal inferensi tipe?


Sebenarnya, Anda lakukan perlu peduli tentang jenis jika Anda sedang mengembangkan dalam bahasa dinamis; jika Anda memiliki jenis sesuatu yang salah, Anda tidak mengetahuinya sampai Anda menekan bagian kode itu pada saat run-time.
Larry Coleman

@ Darry: Tentu saja. Tetapi tidak dalam arti bahwa Anda perlu memprediksi tipe dan rantai pewarisan yang tepat dari setiap objek yang digunakan.

Jawaban:


5

Menjadi programmer Python sendiri, saya berbagi pola pikir bahwa programmer tidak perlu tahu tipe yang tepat. Dalam kasus C ++, terutama ketika berhadapan dengan templated templated templated ... templates. Tentu saja itu bukan karena saya membenci pengetikan statis (saya tidak - saya menganggap Haskell salah satu hal terbaik sejak mengiris roti, sebagian karena pengetikan statisnya) tetapi karena saya tidak peduli dengan jenis pastinya. Mengapa, tidak ditunjukkan dengan baik oleh contoh yang menggunakan nama seperti fooatau get_stuff(). Jadi mari kita pilih sesuatu yang lebih dekat dengan kenyataan:

auto users = get_users();
vector<decltype(users[0])> blocked_users;
/* I'm not a C++ guru, much less C++0x so forgive me if type
   inference and foreach must be combined differently */
for (auto user : users) {
    if (check_name(user.name)) blocked_users.push_back(user)
}

Bukan anotasi jenis tunggal, tetapi sangat jelas apa fungsinya, bukan? Kode ini tidak peduli apa jenisnya users, hanya perlu beberapa rentang untuk beralih yang berisi hal-hal nameyang dapat diumpankan check_name. Tidak ada lagi. Tidak ada yang peduli dengan karakter 100-ish dari nama ketik yang harus Anda ketik sebaliknya.

Hal yang sama berlaku untuk sebagian besar kode dengan nama yang bermakna. Contoh dalam pertanyaan tidak jelas, tetapi juga tidak akan jelas dengan nama jenis eksplisit, karena baik konteks maupun pengidentifikasi tidak memberikan indikasi apa pun yang terjadi. Gunakan pengidentifikasi yang bermakna, dan kode dapat dipahami terlepas dari anotasi jenis eksplisit.


3

Alasan mereka menarik kesimpulan adalah untuk mencegah orang menulis kode seperti:

foo().bar().baz().etc();

Kapan Anda bisa menulis:

Foo f = foo();
Bar b = f.bar();
...

Kecuali Foo akan menjadi tipe templated lama, jadi lebih baik untuk menulis:

auto f = foo();
auto b = f.bar();
...

Jadi, sebagai aturan praktis, jika menggunakan otomatis menyebabkan Anda menulis kode seperti di atas, bukan kode yang mirip dengan contoh pertama maka dengan segala cara menggunakannya. Jika tidak, tetap tambahkan definisi eksplisit.


Masuk akal. Saya menemukan diri saya menggunakan autodalam banyak kasus di mana saya yakin orang lain akan eksplisit, tetapi saya tidak melihat apa yang sebenarnya salah dengan, katakanlah auto f = new SomethingLong(), karena jelas apa yang dikembalikan oleh ekspresi. Saya hanya ingin tahu di mana menggambar garis.
Jon Purdy

Tidak apa-apa jika SomethingLongbukan bagian dari struktur warisan, tetapi kecuali Anda yakin tidak akan pernah ada maka saya akan menyarankan untuk tidak melakukannya. Jauh lebih mudah untuk menarik garis pada sisi yang berhati-hati.
dan_waterworth

2

Ada alasan bagus untuk tidak selalu menggunakan inferensi tipe. Haskell memiliki tipe inferensi, tetapi saya biasanya mendeklarasikan tipe fungsi secara eksplisit. Itu sebagian akibat dari gaya perkembangan saya. Saya menyatakan fungsi terlebih dahulu:

myFunction :: [Int] -> Int
myFunction xs = undefined
Selanjutnya, saya akan menulis kode yang menggunakan fungsi itu dan melakukan kompilasi untuk memastikannya mengetik cek. Setelah mengetik cek, saya akan melanjutkan dengan implementasi.

Alasan lain untuk mendeklarasikan tipe fungsi adalah bahwa deklarasi dapat berfungsi sebagai dokumentasi tambahan. Dokumentasi ini diverifikasi pada setiap kompilasi adalah bonus.


2
Sementara pendekatan tipe-pertama sangat elegan di Haskell, saya ragu itu cocok untuk C ++. Tanpa konsep , tanda tangan template C ++ pada dasarnya tidak mengatakan apa - apa - ini adalah implementasi yang mendefinisikan jenis persyaratan dan argumen yang harus dipenuhi. Templat hanya melakukan pengetikan bebek pada waktu kompilasi - "coba dan lihat apakah berhasil". Jadi saya katakan, kita bisa lebih tepatnya secara implisit dengan jenis-jenisnya seperti halnya bahasa yang diketik bebek dinamis juga.
Dario
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.