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'); 
相關問題