2010-07-21 21 views
6

Đối với những người bạn không quen thuộc với mixin chuỗi D, họ về cơ bản là thời gian biên dịch. Bạn có thể lấy bất kỳ chuỗi thời gian biên dịch nào (cho dù là một chương trình siêu lập trình bằng chữ hoặc được tạo ra bằng cách lập trình hoặc biên dịch hàm thời gian) và biên dịch nó thành mã. Nếu bạn sử dụng một chuỗi ký tự đơn giản, đó là bản sao-dán tự động biên dịch.Có sử dụng mixin chuỗi D để tái sử dụng mã chống mẫu không?

Bạn có cho rằng đó là một mẫu giả để sử dụng kết hợp chuỗi ký tự như một phương tiện sử dụng lại mã đơn giản mà các phương pháp bao thanh toán khác không hoàn toàn phù hợp? Một mặt, về cơ bản nó là bản sao-và-dán tự động của trình biên dịch, có nghĩa là một khi được trộn lẫn trong các cá thể không có gì để làm với nhau. Những điều xấu sẽ xảy ra (mặc dù tại thời gian biên dịch, không phải lúc chạy) nếu một biểu tượng trong chuỗi mixin va chạm với một biểu tượng trong phạm vi hỗn hợp. Nó tương đối không có cấu trúc trong đó người ta có thể, ví dụ, trộn một chuỗi vào giữa một hàm sẽ làm việc nếu và chỉ khi các biến trong phạm vi được đặt tên theo một quy ước nhất định. Mixins cũng có thể khai báo các biến mà phạm vi bên ngoài sau đó có thể sử dụng khi chúng thấy phù hợp.

Mặt khác, vì sao chép và dán là trình biên dịch tự động, có một điểm chân lý duy nhất cho mã được đề cập ở cấp nguồn và nếu cần sửa đổi, nó chỉ cần được sửa đổi ở một nơi và mọi thứ vẫn được đồng bộ hóa. Chuỗi mixins cũng đơn giản hóa việc sử dụng lại mã rất khó để nhân tố theo bất kỳ cách nào khác và nếu không sẽ có khả năng bị cắt và dán một cách thủ công rất cao.

Trả lời

9

Tất cả những lời chỉ trích bạn nêu là đúng sự thật.

Bất kể, nó vẫn vượt trội so với bản sao chép thủ công.

Thực ra, tôi có một thứ tương tự đang chạy trong thư viện công cụ của mình, mở rộng bảng chuỗi. mã ví dụ, từ thực hiện giá trị động một con đường tracer của:

T to(T)() { 
    static if (!is(T == Scope)) { 
     T value; 
     if (flatType == FlatType.ScopeValue) value = sr.value().to!(T); 
    } 
    const string Table = ` 
       | bool   | int   | string    | float | Scope 
     -----------+---------------+-------------+----------------------+---------+---------- 
     Boolean | b    | b   | b?q{true}p:q{false}p | ø  | ø 
     Integer | i != 0  | i   | Format(i)   | i  | ø 
     String  | s == q{true}p | atoi(s)  | s     | atof(s) | ø 
     Float  | ø    | cast(int) f | Format(f)   | f  | ø 
     ScopeRef | !!sr   | ø   | (sr?sr.fqn:q{(null:r)}p) | ø | sr 
     ScopeValue | value   | value  | value    | value | sr`; 
    mixin(ctTableUnrollColMajor(Table, 
     `static if (is(T == $COL)) 
     switch (flatType) { 
      $BODY 
      default: throw new Exception(Format("Invalid type: ", flatType)); 
     } 
     else `, 
     `case FlatType.$ROW: 
     static if (q{$CELL}p == "ø") 
      throw new Exception(q{Cannot convert $ROW to $COL: }p~to!(string)~q{! }p); 
     else return $CELL; 
     ` 
    ).litstring_expand() ~ `static assert(false, "Unsupported type: "~T.stringof); `); 
    } 

tôi chắc chắn rằng thật dễ dàng để xem những gì một khủng khiếp, lộn xộn không cần thiết của IFS lồng nhau và báo cáo trường hợp đó sẽ không mixins chuỗi - cách này, tất cả các sự xấu xí được tập trung ở phía dưới, và thực tế hành vi của chức năng rất dễ đọc trong nháy mắt.

+0

* sniff * Tôi yêu bạn, Feep. Điều này thực sự là một trong những ý tưởng tuyệt vời của bạn. –

+0

Mỗi mẹo bán gọn gàng đáng tin cậy như vậy có ba hoặc bốn ý tưởng chỉ đơn thuần là _horrible_ - như trình phân tích cú pháp đồ thị máy dựa trên văn bản CTFE được chôn sâu trong tools.base :) – FeepingCreature

2

Trong khi các giải pháp khác, thanh lịch hơn có thể tốt hơn để sử dụng nếu bạn có thể, chuỗi mixin có thể cực kỳ hữu ích. Chúng cho phép tái sử dụng cả mã và tạo mã. Chúng được kiểm tra tại thời gian biên dịch. Mã mà kết quả là chính xác giống như nếu bạn đã tự viết bằng tay, vì vậy nó không kém an toàn hơn nếu bạn đã tự viết nó bằng tay.

Vấn đề với mixin chuỗi là chúng khó kiểm soát hơn mã viết tay theo nghĩa nó không được đặt trong nguồn của bạn theo cùng cách với số dòng có thể theo dõi rõ ràng về lỗi và có thể khó gỡ lỗi hơn. Ví dụ, hãy hello world với một mixin chuỗi:

import std.stdio; 

void main() 
{ 
    mixin(hello()); 
} 

string hello() 
{ 
    return " 
    writeln(\"hello world\"); 
"; 
} 

Nếu chúng ta loại bỏ các dấu chấm phẩy sau writeln(), sau đó các lỗi chúng tôi đã nhận sẽ

d.d(7): found 'EOF' when expecting ';' following statement 

Các mixin được thực hiện trên dòng 5. Dòng 7 là một dòng trống. Vì vậy, số dòng là hữu ích hạn chế ở đây. Bây giờ, mixin này đủ ngắn để chúng ta có thể đặt nó trên một dòng và nhận ra rằng lỗi trên cùng dòng với mixin, nhưng với các mixin phức tạp hơn, điều đó rõ ràng sẽ không hoạt động. Vì vậy, bằng cách sử dụng một mixin chuỗi, khả năng của bạn để tìm ra nơi một lỗi là bị suy yếu.Nếu mã được tạo ra bằng cách sử dụng CTFE, sau đó nó sẽ trở nên khó khăn hơn nhiều để tìm ra chính xác những gì mã thậm chí trông giống như để tìm ra những gì sai với nó. Nó giống như tìm ra mã vĩ mô kiểu C biến thành mã nào, ngoại trừ việc nó có thể tồi tệ hơn vì chúng có thể được tạo thay vì thay thế trực tiếp. Tuy nhiên, chúng không thay thế trừ khi bạn nói rõ với chúng, vì vậy chúng an toàn hơn nhiều so với các macro kiểu C.

Kết hợp chuỗi hoàn toàn an toàn và không có gì đặc biệt sai với chúng, nhưng chúng giúp bảo trì khó hơn theo một số cách. Mã viết tay tương ứng sẽ dễ debug hơn. Tuy nhiên, chuỗi mixin đủ mạnh để chúng có thể tạo ra nhiều mã cho bạn và tiết kiệm cho bạn rất nhiều chi phí bảo trì theo nghĩa đó, và chúng cho phép bạn sử dụng lại mã, điều này cũng có thể là một sự bảo trì lớn.

Vì vậy, cho dù sử dụng một mixin chuỗi là một ý tưởng tốt trong một tình huống cụ thể phụ thuộc vào tình hình đó. Tôi không thấy bất cứ điều gì đặc biệt sai với họ, và tôi chắc chắn sẽ không gọi họ là một khuôn mẫu, nhưng có cả ưu và khuyết điểm khi sử dụng chúng sao cho chúng là ý tưởng hay tùy thuộc vào những gì bạn đang làm . Trong nhiều trường hợp, có nhiều giải pháp sạch hơn, thanh lịch hơn sẽ tốt hơn. Ở những người khác, họ chính xác là những gì bác sĩ đã ra lệnh.

Cá nhân, tôi nghĩ rằng chúng tuyệt vời nếu bạn muốn tạo mã, tiết kiệm cho mình nỗ lực phải viết mã đó bằng tay và có thể giúp tạo mã đúng cho nhiều tình huống khác nhau và tránh mạo hiểm tạo ra các lỗi mới như bạn có thể đã có bạn viết nó cho mình trong mỗi những nơi mà bạn sử dụng mixin. Nó cũng là một trong những cách để hoàn toàn sử dụng lại mã mà không phải lo lắng về chi phí của một cuộc gọi hàm hoặc các vấn đề với các giới hạn của thừa kế đơn hoặc bất kỳ thứ gì khác làm cho việc sử dụng lại mã bằng cách gọi hàm hoặc thừa kế khó hơn. Bạn chỉ cần sao chép và dán mã vào từng vị trí theo cách tạo ra để nếu bạn thay đổi mã, các thay đổi sẽ được dán ở mọi nơi mà bạn không phải lo lắng về việc theo dõi tất cả chúng như thể bạn đã có bản sao tay và dán.

Vì vậy, hãy sử dụng mixin chuỗi nếu thích hợp và tốt nhất là không nên sử dụng chúng nếu chúng không cần thiết, nhưng không có gì thực sự sai khi sử dụng chúng.

+0

Tôi thấy rằng cách duy nhất để cải thiện số dòng vấn đề là chèn các chỉ thị '# line' vào nguồn mixin chuỗi. Bằng cách đó, lỗi thường rơi vào đúng vị trí; đã thực hiện gỡ lỗi toàn bộ thư viện liên kết được xây dựng từ hỗn hợp chuỗi được tạo bởi CTFE ít hơn của một cơn ác mộng hoàn toàn và hoàn toàn. –

+0

Bạn chỉ có thể viết một hàm CTFE để xóa các dòng mới, bạn biết đấy. ^^ – FeepingCreature

+1

@FeepingCreature LOL. Dễ thương. Điều đó sẽ giúp với dòng trong thông báo lỗi chỉ ra dòng mà chuỗi được trộn lẫn trên cũng như các thông báo lỗi sau này trong tệp, nhưng nó sẽ không giúp tìm ra lỗi trong bản mixin. Tất nhiên, kể từ khi bạn thậm chí không nhất thiết phải biết những gì mã được trộn lẫn trong hình như, biết số dòng trong đó là xấu không nhất thiết phải giúp bạn anyway. Tôi cho rằng đạo đức của câu chuyện là những chuỗi mixins có tác dụng rất tuyệt, nhưng những cái buggy có thể là một nỗi đau để sửa chữa. –

1

Chuỗi mixin giống như goto: nên tránh ở nơi nào có thể và nên được sử dụng ở bất cứ đâu.

+0

Có một số sự thật với điều đó, nhưng tôi thường tránh goto như bệnh dịch hạch trong khi tôi muốn khá sẵn sàng sử dụng mixins chuỗi trong một loạt các trường hợp. Bây giờ, nếu có một giải pháp tốt hơn so với mixin chuỗi, tôi chắc chắn sẽ lấy nó, nhưng tôi hoàn toàn sẵn sàng để đặt mixins chuỗi trong mã của tôi trong khi tôi sẽ suy nghĩ cứng và chắc chắn xem xét lại trước khi thực sự đặt một goto trong mã của tôi. –

+0

@ Jonathan Nathan: Nghe có vẻ như tôi không muốn sử dụng 'goto' hơn tôi. OTOH có rất ít trường hợp bạn phải sử dụng 'goto' trong D những gì có dấu ngắt và tiếp tục. – BCS

+0

@BCS về cơ bản tôi không bao giờ sử dụng goto bằng bất kỳ ngôn ngữ nào trừ khi tôi không có lựa chọn nào khác để có được hiệu suất tôi cần. Tôi không thực sự thích dán nhãn tiếp tục hoặc phá vỡ nhãn hoặc, nhưng tôi muốn sẵn sàng sử dụng chúng nếu nó có ý nghĩa tốt trong một tình huống cụ thể. Nhưng thẳng lên goto? Khá nhiều không có cơ hội đó. Trừ khi bạn * thực sự * cần hiệu suất, luôn luôn có một cách tốt hơn. Vì vậy, vâng, có vẻ như tôi miễn cưỡng sử dụng goto hơn bạn. –

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