2015-10-05 17 views
8

Tiêu đề khá nhiều tiền, nhưng đây là phiên bản dài.Ký hiệu đối tượng gián tiếp là gì, tại sao nó là xấu, và làm thế nào để tránh nó?

Sau khi đăng một đoạn mã perl nhỏ, tôi được yêu cầu tránh ký hiệu đối tượng gián tiếp, "vì nó có một số tác dụng phụ". Các bình luận tham khảo dòng này cụ thể:

my $some_object = new Some::Module(FIELD => 'value'); 

Vì đây là làm thế nào tôi đã luôn luôn thực hiện nó, trong một nỗ lực để có được với thời gian do đó tôi hỏi:

  • gì xấu như vậy về nó? (cụ thể)
  • Tác dụng phụ tiềm ẩn (có lẽ là âm tính) là gì?
  • Dòng đó nên được viết lại như thế nào?

Tôi sắp hỏi người nhận xét, nhưng với tôi điều này xứng đáng với bài đăng của riêng mình.

+2

Ví dụ yêu thích của tôi về ký hiệu đối tượng gián tiếp: [Tại sao chương trình này hợp lệ? Tôi đã cố gắng để tạo ra một lỗi cú pháp] (http://stackoverflow.com/q/11695110/176646) – ThisSuitIsBlackNot

+1

Vấn đề chính với ION không sử dụng nó nhiều như sự hỗ trợ cho nó trong Perl. Sự tồn tại của tính năng này gây ra nhiều vấn đề. Hai tôi có thể nhớ ngay bây giờ: 1) Nó gây ra một số lỗi cú pháp dẫn đến thông báo lỗi rất kỳ quặc/sai lệch, 2) Nó ngăn các tính năng hữu ích được triển khai kể từ khi chúng xung đột với cú pháp ION hợp lệ. – ikegami

Trả lời

17

Vấn đề chính là nó không rõ ràng. Liệu

my $some_object = new Some::Module(FIELD => 'value'); 

nghĩa để gọi phương thức new trong gói Some::Module, hay nó có nghĩa là để gọi new chức năng trong gói hiện tại với kết quả của cách gọi Module chức năng trong gói Some với các thông số cho trước?

tức là, nó có thể được phân tích như sau:

# method call 
my $some_object = Some::Module->new(FIELD => 'value'); 
# or function call 
my $some_object = new(Some::Module(FIELD => 'value')); 

Cách khác là sử dụng phương pháp rõ ràng cuộc gọi ký hiệu Some::Module->new(...).

Thông thường, trình phân tích cú pháp đoán chính xác, nhưng cách tốt nhất là tránh sự mơ hồ.

4

Người nhận xét chỉ muốn xem Some::Module->new(FIELD => 'value'); làm người xây dựng.

Perl có thể sử dụng indirect object syntax for other bare words that look like they might be methods, nhưng hiện tại tài liệu perlobj đề xuất không sử dụng.

Vấn đề chung với nó là mã được viết theo cách này là mơ hồ và thực hiện phân tích cú pháp của Perl để kiểm tra không gian tên, ví dụ: kiểm tra khi bạn viết method Namespace phương thức Namespace :: có tồn tại không.

9

Điều gì thật tệ?

Các vấn đề với ký hiệu phương pháp gián tiếp có thể tránh được, nhưng dễ dàng hơn khi yêu cầu mọi người tránh ký hiệu phương pháp gián tiếp.

Vấn đề chính rất dễ bị gọi nhầm chức năng.Đi đoạn mã sau, ví dụ:

package Widget; 

sub new { ... } 
sub foo { ... } 
sub bar { ... } 

sub method { 
    ...; 
    my $o = new SubWidget; 
    ...; 
} 

1; 

Trong mã đó, new SubWidget dự kiến ​​sẽ có nghĩa

SubWidget->new() 

Thay vào đó, nó thực sự có nghĩa là

new("SubWidget") 

Điều đó nói rằng, sử dụng nghiêm ngặt sẽ bắt hầu hết các trường hợp lỗi này. Được use strict; để được thêm vào đoạn mã trên, các lỗi sau đây sẽ phải xuất trình:

Bareword "SubWidget" not allowed while "strict subs" in use at Widget.pm line 11. 

Điều đó nói rằng, có những trường hợp sử dụng nghiêm ngặt sẽ không bắt lỗi. Chúng chủ yếu liên quan đến việc sử dụng các parens xung quanh các đối số của cuộc gọi phương thức (ví dụ: new SubWidget($x)).

Vì vậy, đó có nghĩa là

  • Sử dụng Object Notation gián tiếp mà không cần dấu ngoặc có thể dẫn đến các thông báo lỗi kỳ lạ.
  • Sử dụng Ký hiệu đối tượng gián tiếp với dấu ngoặc đơn có thể dẫn đến mã sai được gọi.

Trường hợp cũ có thể chịu đựng được và sau đó có thể tránh được. Nhưng thay vì nói với mọi người "tránh sử dụng parens xung quanh các đối số của các cuộc gọi phương thức bằng cách sử dụng ký hiệu phương pháp gián tiếp", chúng tôi chỉ nói với mọi người "tránh sử dụng ký hiệu phương pháp gián tiếp". Nó quá mỏng manh.


Có một vấn đề khác. Nó không chỉ là sử dụng ký hiệu đối tượng gián tiếp mà là một vấn đề, nó hỗ trợ nó trong Perl. Sự tồn tại của tính năng này gây ra nhiều vấn đề. Chủ yếu,

  • Nó gây ra một số lỗi cú pháp dẫn đến thông báo lỗi rất kỳ quặc/gây nhầm lẫn vì mã dường như đang sử dụng ION khi không.
  • Nó ngăn các tính năng hữu ích được triển khai kể từ khi chúng xung đột với cú pháp ION hợp lệ.

Mặt khác, sử dụng no indirect; sẽ giúp khắc phục sự cố đầu tiên.


dòng đó nên được viết lại như thế nào?

Cách đúng để viết các lời gọi phương thức như sau:

my $some_object = Some::Module->new(FIELD => 'value'); 

Điều đó nói rằng, ngay cả cú pháp này là mơ hồ. Trước tiên nó sẽ kiểm tra xem một hàm có tên là Some::Module tồn tại hay không. Nhưng đó là rất không chắc rằng rất ít người tự bảo vệ mình khỏi những vấn đề như vậy.Nếu bạn muốn tự bảo vệ mình, bạn có thể sử dụng như sau:

my $some_object = Some::Module::->new(FIELD => 'value'); 
6

Như thế nào để tránh nó: Có một mô-đun CPAN rằng cấm các ký hiệu, hoạt động như một mô-đun pragma:

no indirect; 

http://metacpan.org/pod/indirect

+0

Giá trị của nó bị giới hạn bởi vì sẽ không tìm thấy vấn đề trong mã trong câu trả lời của tôi. – ikegami

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