2011-08-18 21 views
8

Tôi đã triển khai thư viện nhập động cho D khi tôi gặp phải sự cố thú vị.Sử dụng nhập động trong D, ngôn ngữ được nhập tĩnh

Ngay bây giờ, tôi đã thành công trong việc tạo ra một hàm có tên dynamic() trả về phiên bản động của một đối tượng.

Ví dụ:

import std.stdio, std.dynamic.core; 

class Foo 
{ 
    string bar(string a) { return a ~ "OMG"; } 
    int opUnary(string s)() if (s == "-") { return 0; } 
} 

void main(string[] argv) 
{ 
    Dynamic d = dynamic(new Foo()); 
    Dynamic result = d.bar("hi"); 
    writeln(result); // Uh-oh 
} 

Vấn đề tôi đã chạy ngang qua là một thực tế rằng writeln cố gắng sử dụng thời gian biên dịch phản chiếu để tìm ra cách để điều trị result.

Điều đầu tiên nó cố gắng là gì? isInputRange!(typeof(result))

Vấn đề là, nó trả về đúng! Tại sao? Bởi vì tôi phải giả định rằng tất cả các thành viên mà nó cần tồn tại, trừ khi tôi có thể chứng minh bằng cách khác trong thời gian chạy - đó là quá muộn. Vì vậy, chương trình sẽ cố gắng gọi front, popFrontempty trên result, làm hỏng chương trình của tôi.

Tôi không thể nghĩ ra cách nào để sửa lỗi này. Có ai có ý tưởng gì không?

Trả lời

1

gì là sai với việc sử dụng std.variant mà thực hiện tất cả các bạn cần để gõ động (cùng với khá nhiều đường cú pháp)

+1

'std.variant' không hỗ trợ loại có các lĩnh vực tùy ý. –

+0

@cyber, ý bạn là gì? –

+0

OP muốn tạo một đối tượng trong đó 'obj.anything' hợp lệ tại thời gian biên dịch (mặc dù nó có thể không hợp lệ tại thời gian chạy). Không có gì trong 'std.variant' cho phép điều này, như tôi đã thấy. –

1

Ông có thể cung cấp một tình trạng quá tải cho isInputRange? Một cái gì đó như thế này (lưu ý rằng tôi đã không nhìn vào thực hiện isInputRange):

template isInputRange(T : Dynamic) { 
    enum isInputRange = false; 
} 

Nếu đây được cung cấp bởi dynamic.core của bạn, tôi nghĩ tình trạng quá tải này nên được lựa chọn trước khi std một lib.

+1

Phải, nhưng vấn đề là điều này đòi hỏi phải biết trước mọi loại phòng ngừa. Rõ ràng, nó không làm việc cho bất cứ ai kết thúc bằng cách sử dụng thư viện của tôi ... – Mehrdad

+0

Thật không may lừa này không hoạt động, std.stdio không thể nhận chuyên môn. – Lutger

0

Đối với trường hợp chung, Dynamic phải chấp nhận bất kỳ tra cứu phương pháp nào tại thời gian biên dịch, như bạn đã nói. Giả sử cho một thời điểm mà bạn có thể ngăn chặn biến vị ngữ isInputRange để đánh giá đúng, bây giờ mã sai sẽ được tạo ra khi bạn cố gắng tạo một Dynamic từ một phạm vi đầu vào.

Tôi không nghĩ rằng điều này có thể khắc phục được, ít nhất là không theo cách chung. Trong trường hợp cụ thể này, giải pháp tốt nhất mà tôi có thể nghĩ đến là Dynamic cung cấp phiên bản toString của riêng nó, và writeln sẽ thích hơn so với chuyên môn inputRange. Tôi tin rằng writeln không làm điều này tại thời điểm này, ít nhất là không cho cấu trúc, nhưng nó có lẽ nên.

Một thỏa hiệp khác là không cho phép một vài phương pháp như popFront trong ràng buộc opDispatch, thay vào đó, Dynamic sẽ cung cấp opIndex hoặc đối tượng thành viên để truy cập các trường hợp đặc biệt này. Điều này có thể không tệ như âm thanh, bởi vì các trường hợp đặc biệt rất hiếm và sử dụng chúng sẽ dẫn đến lỗi trình biên dịch rõ ràng.

Tôi nghĩ rằng cách tốt nhất để cứu vãn loại phương pháp phân giải này là Dynamic để sửa writeln và chấp nhận rằng Dynamic sẽ không hoạt động với tất cả các mã mẫu.

+0

Sự cố khi tạo writeln thích toString hơn isInputRange là mỗi lớp thừa hưởng một phương thức toString chung từ Object, mà chỉ xuất ra tên lớp. Do đó, nếu writeln được thay đổi, nó sẽ phải xử lý các cấu trúc và các lớp khác nhau. – tgehr

2

Bạn đang cố gắng làm cho hai khái niệm cơ bản khác nhau hoạt động cùng nhau, cụ thể là các mẫu và nhập động. Các mẫu dựa rất nhiều vào việc gõ tĩnh, isInputRange hoạt động bằng cách kiểm tra các thuộc tính hoặc các phương thức mà một kiểu có. Loại động của bạn được coi là có mọi thuộc tính hoặc phương pháp tại thời gian biên dịch, nó được xử lý như hoàn thành mỗi giao diện gõ vịt tĩnh. Do đó, để làm cho Công việc động trong môi trường được nhập tĩnh, bạn phải cung cấp thêm thông tin tĩnh tại một số nơi.

Một số giải pháp tôi có thể thấy:

  1. cung cấp riêng triển khai tạo kiểu động của bạn cho các chức năng sử dụng nhiều. Toàn bộ vấn đề bạn đang gặp phải là do thực tế rằng bạn đang cố gắng sử dụng các hàm chung mà giả định kiểu gõ tĩnh với các kiểu động.

  2. một cách rõ ràng làm cho phạm vi hoạt động của char và tự chăm sóc chuyển đổi thành chuỗi dữ liệu cơ bản. (Bạn sẽ phải có một phương thức toString tùy chỉnh anyways nếu vấn đề isInputRange sẽ không tồn tại, bởi vì nếu không kết quả của nó sẽ lại là kiểu Dynamic). Điều này có lẽ sẽ làm cho writeln (d); công việc.

  3. cung cấp trình bao bọc cho động cho phép bạn chuyển các loại động vào nhiều chức năng được tạo khuôn mẫu khác nhau. (Những người sẽ chỉ trưng bày một giao diện tĩnh và chuyển tiếp tất cả các cuộc gọi đến Dynamic).

Ví dụ:

Dynamic d; 
// wrap d to turn it into a compile-time input range (but NOT eg a forward range) 
Dynamic d2=dynamic(map!q{a*2}(dynInputRange(d))); 
// profit 

4. Thêm một mẫu thành viên vào Dynamic, cho phép tĩnh vô hiệu hóa một số tên hàm thành viên.

Ví dụ:

static assert(!isForwardRange!(typeof(d.without!"save"))); 
0

Bạn đã nhìn vào std.variant?

import std.stdio, std.variant; 

class Foo { 
    string Bar(string a) { 
     return a ~ " are Cool!"; 
    } 
} 

void main() { 
    Variant foo = new Foo(); 
    Variant result = foo.peek!Foo.Bar("Variants"); 

    writeln(result); // Variants are Cool! 
} 

http://www.d-programming-language.org/phobos/std_variant.html

Các vấn đề liên quan