Một số giới hạn phong cách hợp lý về suy luận loại là gì?


8

C ++ 0x bổ sung hỗ trợ suy luận kiểu khá toàn diện. Tôi rất muốn sử dụng nó ở mọi nơi có thể để tránh sự lặp lại không đáng có, nhưng tôi tự hỏi nếu loại bỏ thông tin loại rõ ràng ở khắp mọi nơi là một ý tưởng tốt. Hãy xem xét ví dụ khá giả tạo này:

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

Bạn sẽ nói điều này là hợp lý, hay nó hoàn toàn vô lý? Xét cho cùng, đặc biệt là nếu bạn đã từng phát triển ngôn ngữ động, bạn thực sự không cần quan tâm nhiều đến các loại điều, và có thể tin tưởng rằng trình biên dịch sẽ nắm bắt được bất kỳ sự lạm dụng nghiêm trọng nào của hệ thống loại. Nhưng đối với những người dựa vào hỗ trợ biên tập viên cho chữ ký phương thức, bạn không gặp may, vì vậy sử dụng phong cách này trong giao diện thư viện có lẽ là một thực tế tồi.

Tôi thấy rằng việc viết mọi thứ với tất cả các kiểu có thể thực sự làm cho mã của tôi dễ theo dõi hơn rất nhiều, bởi vì nó loại bỏ gần như tất cả sự lộn xộn thông thường của C ++. Số dặm của bạn, tất nhiên, có thể khác nhau, và đó là điều tôi quan tâm khi nghe về. Những lợi thế và bất lợi cụ thể để sử dụng triệt để suy luận kiểu là gì?


Trên thực tế, bạn làm cần phải chăm sóc về các loại nếu bạn đang phát triển trong một ngôn ngữ năng động; nếu bạn có loại sai, bạn không tìm ra cho đến khi bạn nhấn phần mã đó vào thời gian chạy.
Larry Coleman

@Larry: Tất nhiên rồi. Nhưng không phải theo nghĩa là bạn cần dự đoán chính xác loại và chuỗi thừa kế của mọi đối tượng đang sử dụng.

Câu trả lời:


5

Bản thân tôi là một lập trình viên Python, tôi chia sẻ suy nghĩ rằng lập trình viên không cần biết loại chính xác. Trong trường hợp của C ++, đặc biệt là khi xử lý các mẫu templated templated .... Tất nhiên đó không phải là vì tôi coi thường việc gõ tĩnh (Tôi không - tôi coi Haskell là một trong những điều tốt nhất kể từ khi cắt lát bánh mì, một phần vì cách gõ tĩnh của nó) mà vì tôi không quan tâm đến loại chính xác. Tại sao, không được thể hiện tốt bằng các ví dụ sử dụng tên như foohoặc get_stuff(). Vì vậy, hãy chọn một cái gì đó gần với thực tế hơn:

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

Không phải là một chú thích loại duy nhất, nhưng nó hoàn toàn rõ ràng những gì nó làm, phải không? Mã này không quan tâm loại của usersnó là gì, nó chỉ cần một số phạm vi để lặp đi lặp lại trong đó có chứa những thứ namecó thể được cung cấp check_name. Chỉ có bấy nhiêu thôi. Không ai quan tâm đến 100 ký tự của các loại tên mà bạn phải nhập khác.

Áp dụng tương tự cho hầu hết các mã với tên có ý nghĩa. Ví dụ trong câu hỏi không rõ ràng, nhưng nó cũng sẽ không rõ ràng với tên loại rõ ràng, bởi vì cả bối cảnh và định danh đều không đưa ra bất kỳ dấu hiệu nào về những gì đang diễn ra. Sử dụng các định danh có ý nghĩa và mã có thể được hiểu bất kể chú thích loại rõ ràng.


3

Lý do họ đưa ra suy luận là để ngăn mọi người viết mã như:

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

Khi bạn có thể viết:

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

Ngoại trừ Foo sẽ là một kiểu templated dài, vì vậy nó trở nên đẹp hơn để viết:

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

Vì vậy, theo nguyên tắc thông thường, nếu sử dụng tự động khiến bạn viết mã như trên thay vì mã tương tự như ví dụ đầu tiên thì bằng mọi cách hãy sử dụng nó. Nếu không, hãy thêm vào các định nghĩa rõ ràng.


Có ý nghĩa. Tôi thấy mình đang sử dụng autotrong rất nhiều trường hợp mà tôi chắc chắn người khác sẽ rõ ràng, nhưng tôi không thấy điều gì thực sự sai với auto f = new SomethingLong(), bởi vì, rõ ràng những gì biểu hiện trả về. Tôi chỉ tự hỏi nơi để vẽ đường.
Jon Purdy

Điều đó tốt nếu SomethingLongkhông phải là một phần của bất kỳ cấu trúc thừa kế nào, nhưng trừ khi bạn chắc chắn rằng nó sẽ không bao giờ được thì tôi khuyên bạn nên chống lại nó. Dễ dàng hơn nhiều để vẽ đường về phía thận trọng.
dan_waterworth

2

Có những lý do tốt cho việc không phải lúc nào cũng sử dụng suy luận kiểu. Haskell có kiểu suy luận, nhưng tôi thường khai báo các kiểu hàm một cách rõ ràng. Đó là một phần kết quả của phong cách phát triển của tôi. Tôi khai báo hàm trước:

myFunction :: [Int] -> Int
myFunction xs = undefined
Tiếp theo, tôi sẽ viết mã sử dụng hàm đó và thực hiện biên dịch để đảm bảo nó gõ kiểm tra. Khi nó gõ kiểm tra, tôi sẽ tiếp tục thực hiện.

Lý do khác để khai báo các loại hàm là các khai báo có thể dùng làm tài liệu bổ sung. Rằng tài liệu này được xác minh trên mỗi biên dịch là một phần thưởng.


2
Mặc dù cách tiếp cận kiểu đầu tiên rất thanh lịch trong Haskell, tôi nghi ngờ rằng nó phù hợp với C ++. Không có khái niệm , chữ ký mẫu C ++ về cơ bản không nói gì - đó là việc triển khai xác định các loại yêu cầu và đối số phải đáp ứng. Các mẫu chỉ cần gõ vịt vào thời gian biên dịch - "thử và xem nếu nó hoạt động". Vì vậy, tôi muốn nói rằng, chúng ta có thể ẩn ý với các loại giống như các ngôn ngữ gõ vịt động quá.
Dario
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.