2016-10-18 36 views
8

這在Perl 6的一個報告的bug:X::AdHoc instead of X::TypeCheck::Binding with subset parameter,首先是在2015年十一月爲什麼Perl 6爲我的子集類型拋出X :: AdHoc異常?


報道雖然與我的Perl 6的模塊Chemisty::Elements玩,我碰到的一個問題Exception我沒想到。

我定義了一個類型,ZInt,它將數字限制爲週期圖表上找到的序數(我在這裏假定了一點)。然後我使用該類型將參數約束爲子例程。我希望得到某種X::TypeCheck,但我得到X::AdHoc代替:

use v6; 

subset ZInt of Cool is export where { 
    state ($min, $max) = <1 120>; 
    ($_.truncate == $_ and $min <= $_ <= $max) 
     or warn "Z must be between a positive whole number from $min to $max. Got <$_>." 
    }; 

sub foo (ZInt $Z) { say $Z } 

try { 
    CATCH { 
     default { .^name.say } 
     } 

    foo(156); 
    } 

首先,我得到警告兩次,這是奇怪的:

Z應該在從1的正整數之間到120.得到< 156>。在zint.p6第5行第5行 Z必須介於從1到120的正整數之間。得到< 156>。在zint.p6線5 X ::即席

但是,塊我得到的X::AdHoc類型時,我寧願人們知道這是一個類型的錯誤。

我查了會發生什麼,沒有warn,然後又X::AdHoc

subset ZInt of Cool is export where { 
    state ($min, $max) = <1 120>; 
    ($_.truncate == $_ and $min <= $_ <= $max) 
    }; 

所以,我想我可以把我自己的異常:

subset ZInt of Cool is export where { 
    state ($min, $max) = <1 120>; 
    ($_.truncate == $_ and $min <= $_ <= $max) 
     or X::TypeCheck.new.throw; 
    }; 

但是,我得到一個警告:

在字符串上下文中使用任何類型的未初始化值 如果需要,。^ name,.perl,.gist或.say中的任何一個都可以將未定義的事物串聯起來。

在這一點上,我不知道什麼是抱怨。我認爲其中一種方法需要我沒有提供的東西,但是我沒有在文檔中看到有關newthrow的任何參數。

我該如何獲得我想要的類型而沒有警告,還有我的自定義文本?

+0

我建議,要求它perl6用戶也 – teodozjan

+0

這是一個開放的bug:https://rt.perl.org/Public/Bug/Display.html?id=126763 –

回答

3

不要拋出異常或警告一個。相反,你想失敗:

subset ZInt of Cool is export where { 
    state ($min, $max) = <1 120>; 
    ($_.truncate == $_ and $min <= $_ <= $max) 
     or fail "Z must be between a positive whole number from $min to $max. Got <$_>." 
}; 

我相信這是你的意圖。用你自己的異常失敗也可以,但是X :: TypeCheck有一個bug。它應該要求「操作」或提供合理的默認值,就像它對「已得到」和「預期」所做的那樣。

subset ZInt of Cool is export where { 
    state ($min, $max) = <1 120>; 
    ($_.truncate == $_ and $min <= $_ <= $max) 
    or fail X::TypeCheck.new(
      operation => "type check", 
      expected => ::('ZInt'), 
      got  => $_, 
     ); 
}; 
+0

'fail'和'warn'之間的區別在於'warn'立即大聲,而'fail'只在遇到其他代碼時纔會變大,比如分配給它時通過例程返回後變量。 – zostay

+0

'失敗'在這裏是個好建議。我必須去找到我使用'警告'複製的例子。 (我會將你的評論添加到答案中)。我仍然認爲子集檢查失敗應該會引發某種類型檢查錯誤。我會看到修復TypeCheck的。 –

+0

我也在某處看到過這個建議,但在我的快速搜索中找不到它。 – zostay

3

你可以通過--ll-exception並試圖找出你最終得到的錯誤和消息,但我不知道這將是多麼有幫助。

至於使用未初始化值的警告:您需要提供一個名爲operation的參數給X::TypeCheck.new;您可能提供的其他論據是gotexpected,請參閱core/Exception.pm

然而,這是一個糟糕的主意,拋出子集聲明,因爲任何針對該特定類型的智能匹配現在都會爆炸。一個稍微好一點的想法是.fail這個例外,但這仍然不適合我:不是子集類型的成員不是一個例外情況。

或者,你可以提供一個多候選人,做垂死:

subset ZInt of Cool where $_ %% 1 && $_ ~~ 1..120; 

proto foo($) {*} 
multi foo(ZInt $Z) { say $Z } 
multi foo($Z) { 
    die X::TypeCheck.new(
     operation => 'foo', 
     got => $Z, 
     expected => ZInt 
    ); 
} 

仍然有問題,如果你提供像"hello"上的數字轉換失敗爲%%參數將拋出的,而不是傳播的失敗,這可能被認爲是Rakudo核心設置的缺陷。

您可以通過工作的事情圍繞着一個像

subset ZInt of Cool where { try $_ %% 1 && $_ ~~ 1..120 } 

subset ZInt of Cool where { .Numeric andthen $_ %% 1 && $_ ~~ 1..120 } 

的參數類型檢查,子集或者從句,故障和異常的整個互動可能有點脆,所以你可能想嘗試一下,直到你到達你喜歡的語義和行爲。

另一種方法是從做一個Cool脅迫Int一個單獨的範圍檢查:

subset ZInt of Int where 1..120 ; 

sub foo(Int(Cool) $Z where ZInt) { 
    say $Z.perl; 
} 

在一個理想的世界,應該有某種方式與像ZInt(Cool)一個脅迫類型約束來表達這一點。

+0

此提供多似乎潛艇就像一個可怕的程序。 –

+0

@briandfoy:這不是一個完美的解決方案;我的觀點表明,子集不應該投擲;在語義上,強制類型如'ZInt(Cool)'是正確的方法;問題在於它們是通過在輸入值上調用'.ZInt'來實現的,然而它可以額外地在目標類型上尋找一個脅迫者;即使這是可能的,它也不會幫助你的問題,因爲子集目前不能有方法,因爲它們僅僅是限制;我有一個關於另一個使用where子句的因子的想法,但我將不得不看看它是否工作... – Christoph

+0

@briandfoy:爲理論上我想做的事情添加示例代碼(但可能不會在實踐中) – Christoph

相關問題