2008-11-17 15 views
110

Trong another Stack Overflow questionLeon Timmermans khẳng định:Tại sao nguyên mẫu chức năng của Perl 5 là xấu?

tôi khuyên bạn không sử dụng nguyên mẫu. Họ có sử dụng của họ, nhưng không phải cho hầu hết các trường hợp và chắc chắn không phải trong này.

Tại sao điều này có thể đúng (hoặc khác)? Tôi gần như luôn luôn cung cấp nguyên mẫu cho các chức năng Perl của tôi, và tôi chưa bao giờ thấy ai khác nói xấu về việc sử dụng chúng.

+0

Tôi cũng tò mò. Thời gian duy nhất tôi không sử dụng chúng là khi tôi gọi với một số lượng các đối số. –

+7

Tôi có thể khuyên bạn nên đọc bài viết, [“Nguyên mẫu Perl được coi là có hại”] (http://www.perlmonks.org/?node_id=861966)? – tchrist

Trả lời

116

Nguyên mẫu không tệ nếu được sử dụng đúng cách. Khó khăn là nguyên mẫu của Perl không hoạt động theo cách mọi người thường mong đợi. Những người có nền trong các ngôn ngữ lập trình khác có xu hướng mong đợi các nguyên mẫu để cung cấp một cơ chế để kiểm tra các cuộc gọi hàm đó là chính xác: có nghĩa là chúng có đúng số lượng và kiểu đối số. Nguyên mẫu của Perl không phù hợp với nhiệm vụ này. Đó là việc sử dụng sai mục đích thật tệ. Nguyên mẫu của Perl có mục đích số ít và rất khác nhau:

Nguyên mẫu cho phép bạn xác định các chức năng hoạt động như chức năng tích hợp sẵn.

  • Dấu ngoặc đơn là tùy chọn.
  • Bối cảnh được áp dụng cho các đối số.

Ví dụ, bạn có thể định nghĩa một hàm như thế này:

sub mypush(\@@) { ... } 

và gọi nó như

mypush @array, 1, 2, 3; 

mà không cần phải viết \ để có một tham chiếu đến mảng.

Tóm lại, nguyên mẫu cho phép bạn tạo đường cú pháp của riêng mình. Ví dụ, khung Moose sử dụng chúng để mô phỏng cú pháp OO điển hình hơn.

này là rất hữu ích nhưng nguyên mẫu đang rất hạn chế:

  • Họ phải được hiển thị tại thời gian biên dịch.
  • Chúng có thể bị bỏ qua.
  • Truyền đạt ngữ cảnh cho đối số có thể gây ra hành vi không mong muốn.
  • Chúng có thể gây khó khăn khi gọi các chức năng bằng cách sử dụng bất kỳ thứ gì khác ngoài mẫu được quy định nghiêm ngặt.

Xem Prototypes trong perlsub cho tất cả các chi tiết đẫm máu.

+2

Tôi đã chấp nhận câu trả lời này bởi vì tôi cảm thấy nó trả lời tốt nhất câu hỏi - nguyên mẫu không phải là bản chất xấu, nó chỉ là cách bạn sử dụng chúng. – Alnitak

+2

Nguyên mẫu Moose ở mặt khác, là/awesome/http://p3rl.org/MooseX::Declare http://p3rl.org/MooseX::Method::Signatures –

+13

[Xa hơn mọi thứ bạn từng muốn biết Nguyên mẫu Perl] (http://www.perlmonks.org/?node_id=861966). – tchrist

66

Vấn đề là nguyên mẫu chức năng của Perl không làm những gì mọi người nghĩ rằng họ làm. Mục đích của họ là cho phép bạn viết các hàm sẽ được phân tích cú pháp như các hàm dựng sẵn của Perl.

Trước hết, các cuộc gọi phương thức hoàn toàn bỏ qua các nguyên mẫu. Nếu bạn đang làm lập trình OO, nó không quan trọng nguyên mẫu của bạn phương pháp có. (Vì vậy, họ không nên có bất kỳ nguyên mẫu.)

Thứ hai, nguyên mẫu không được thi hành nghiêm ngặt. Nếu bạn gọi một chương trình con với &function(...), nguyên mẫu sẽ bị bỏ qua. Vì vậy, họ không thực sự cung cấp bất kỳ loại an toàn nào.

Thứ ba, chúng là hành động ma quái ở khoảng cách xa. (Đặc biệt là nguyên mẫu $, làm cho tham số tương ứng được đánh giá trong ngữ cảnh vô hướng, thay vì ngữ cảnh danh sách mặc định.)

Đặc biệt, chúng khó chuyển các tham số từ mảng. Ví dụ:

my @array = qw(a b c); 

foo(@array); 
foo(@array[0..1]); 
foo($array[0], $array[1], $array[2]); 

sub foo ($;$$) { print "@_\n" } 

foo(@array); 
foo(@array[0..1]); 
foo($array[0], $array[1], $array[2]); 

in:

a b c 
a b 
a b c 
3 
b 
a b c 

cùng với 3 cảnh báo về main::foo() called too early to check prototype (nếu cảnh báo được kích hoạt). Vấn đề là một mảng (hoặc mảng mảng) được đánh giá trong ngữ cảnh vô hướng trả về độ dài của mảng.

Nếu bạn cần viết chức năng hoạt động như được tích hợp sẵn, hãy sử dụng mẫu thử nghiệm. Nếu không, không sử dụng nguyên mẫu.

Lưu ý: Perl 6 sẽ có các nguyên mẫu hoàn toàn được sửa lại và rất hữu ích. Câu trả lời này chỉ áp dụng cho Perl 5.

+0

Nhưng họ vẫn cung cấp một kiểm tra hữu ích mà người gọi của bạn và phụ đang sử dụng cùng một số đối số, vì vậy có gì sai với điều đó? –

+0

đó là loại điểm của câu hỏi của tôi - tôi không bao giờ sử dụng cú pháp cũ & func, vì vậy nguyên mẫu không cung cấp chức năng kiểm tra tham số chức năng hữu ích. – Alnitak

+2

Không; sự đồng thuận chung là nguyên mẫu chức năng Perl cung cấp cơ bản không có lợi ích. Bạn cũng có thể không bận tâm với họ, ít nhất là trong Perl 5. Perl 6 có thể là một câu chuyện khác (tốt hơn). –

29

Tôi đồng ý với hai áp phích trên. Nói chung, nên tránh sử dụng $. Nguyên mẫu là chỉ hữu ích khi sử dụng đối số khối (&), globs (*), hoặc mẫu tài liệu tham khảo (\@, \$, \%, \*)

+0

Nói chung, có lẽ, nhưng tôi muốn đề cập đến hai trường hợp ngoại lệ: Thứ nhất, nguyên mẫu '($)' tạo một toán tử đơn nhất có tên, có thể hữu ích (chắc chắn Perl thấy chúng hữu ích; đôi khi tôi cũng vậy). Thứ hai, khi ghi đè tích hợp (cho dù thông qua nhập hoặc sử dụng CORE :: GLOBAL: :), bạn nên nói chung với bất kỳ nguyên mẫu nào được tích hợp sẵn, ngay cả khi nó bao gồm '$', hoặc bạn có thể gây bất ngờ cho người lập trình (bản thân bạn, thậm chí) với ngữ cảnh danh sách, nơi tích hợp sẵn sẽ cung cấp ngữ cảnh vô hướng. –

1

Một số người, nhìn vào một chương trình con prototype Perl, cho rằng nó có nghĩa là một cái gì đó mà nó doesn 't:

sub some_sub ($$) { ... } 

Để Perl, điều đó có nghĩa là trình phân tích cú pháp mong đợi hai đối số. Đó là cách Perl cho phép bạn tạo các chương trình con hoạt động giống như các trình xây dựng sẵn, tất cả đều biết những gì mong đợi từ mã kế tiếp. Bạn có thể đọc về các nguyên mẫu trong perlsub

Nếu không đọc tài liệu, mọi người đoán rằng các nguyên mẫu tham khảo kiểm tra đối số thời gian chạy hoặc một cái gì đó tương tự mà chúng đã thấy bằng các ngôn ngữ khác. Như với hầu hết mọi thứ mọi người đoán về Perl, họ hóa ra là sai.

Tuy nhiên, bắt đầu với Perl v5.20, Perl có một tính năng, thử nghiệm khi tôi viết điều này, cung cấp cho một cái gì đó giống như những gì người dùng mong đợi và những gì. Perl của subroutine signatures không chạy luận đếm thời gian, ấn định biến, và thiết lập mặc định:

use v5.20; 
use feature qw(signatures); 
no warnings qw(experimental::signatures); 

animals('Buster', 'Nikki', 'Godzilla'); 

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat"; 
    say "The dog is $dog"; 
    say "The lizard is $lizard"; 
    } 

Đây là tính năng mà bạn có thể muốn nếu bạn đang cân nhắc nguyên mẫu.

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