2015-10-05 54 views
8

标题几乎总结了它,但这里是长版本无论如何。什么是间接对象符号,它为什么不好,以及如何避免它?

在发布了一小段Perl代码后,我被告知避免间接对象符号,“因为它有几个副作用”。注释引用这一行:

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

由于这是我怎么总是做了,在努力与时代获得,因此我问:

  • 为何如此糟糕呢? (具体地)
  • 潜在(可能是负面的)副作用是什么?
  • 该行应该如何重写?

我要问的评论者,但对我来说这是值得自己的职位。

+2

我最喜欢的间接对象符号示例:[为什么这个程序有效?我试图创建一个语法错误](http://stackoverflow.com/q/11695110/176646) – ThisSuitIsBlackNot

+1

ION的主要问题是没有使用它在Perl中的支持。该功能的存在会导致多重问题。我现在可以记住的两个:1)它导致一些语法错误,导致非常奇怪的/误导性的错误消息,2)它阻止有用的功能被实现,因为它们与有效的ION语法冲突。 – ikegami

回答

17

主要问题是它是不明确的。是否

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

意味着呼叫在Some::Modulenew方法,还是意味着调用new功能在当前的包调用Module功能在Some包具有给定参数的结果?

即,它可以被解析为:

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

另一种方法是使用显式方法调用符号Some::Module->new(...)

通常,解析器会正确猜测,但最好的做法是避免含糊不清。

4

评论者只是想看到Some::Module->new(FIELD => 'value');作为构造函数。

Perl可以使用indirect object syntax for other bare words that look like they might be methods,但是现在perlobj文档建议不要使用它。

它的一般问题是用这种方式编写的代码是不明确的,并且练习Perl的解析器来测试命名空间到检查当你写method Namespace是否存在Namespace :: method。

9

这有什么不好?

与间接法符号存在的问题是可以避免的,但它容易得多告诉人们,以避免间接法符号。

主要问题很容易被错误地调用错误的功能。看看下面的代码,例如:

package Widget; 

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

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

1; 

在该代码中,new SubWidget有望意味着

SubWidget->new() 

相反,它实际上意味着

new("SubWidget") 

这就是说,采用严格来抓大多数这种错误的实例。被use strict;被添加到上面的片段,将产生以下错误:

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

这就是说,存在其中使用严格不会捕获错误的情况。它们主要涉及在方法调用的参数周围使用parens(例如new SubWidget($x))。

因此,这意味着

  • 使用间接对象符号没有括号可能会导致奇怪的错误消息。
  • 对parens使用间接对象表示法可能会导致错误的代码被调用。

前者是可以忍受的,后者是可以避免的。但是,我们只是告诉人们“避免使用间接方法符号”,而不是告诉人们“避免在使用间接方法符号的方法调用的参数周围使用剩余符号”。这太脆弱了。


还有另一个问题。这不仅仅是使用间接对象表示法,它是一个问题,它支持Perl。该功能的存在会导致多重问题。主要是,

  • 它会导致一些语法错误,导致非常奇怪的/误导性的错误消息,因为代码似乎使用ION时,它不是。
  • 由于它们与有效的ION语法冲突,因此它阻止了实现有用的功能。

另一方面,使用no indirect;有助于解决第一个问题。


应该如何该行被改写?

写方法调用正确的方法是:

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

这就是说,即使这个语法是不明确的。它将首先检查是否存在名为Some::Module的函数。但是很少有人能够保护自己免受这些问题的困扰。如果你想保护自己,你可以使用以下命令:

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