aiscript icon indicating copy to clipboard operation
aiscript copied to clipboard

エラー処理について

Open FineArchs opened this issue 1 year ago • 32 comments

普通にthrow catchを実装してもいいですが、「エラー型」の実装ができそうなので提案します。

エラー型について

次のようなものを考えています。

  • 何らかの式の評価でエラーeが発生したとき、通常の値の代わりにこの「エラー型」の値Error(e)を返す。
  • 「エラー型」の値は通常の値のように、変数に代入したり関数の引数や返り値にすることができる。
  • 「エラー型」の値は通常の値とは違い、その値を参照して何か計算をしようとするとエラーを発生させる。そのエラーは最初の式の評価で発生したエラーeである。
  • 値が「エラー型」であるかはCore:typeを使用して見分けることができる。これにより例外処理を行う。

#11 で @syuilo さんが言っていたことを、既存のAiscriptコードの動作を壊さない範囲で実装する案です。

FineArchs avatar Aug 02 '23 15:08 FineArchs

このエラー型の概念って他の言語にあったりしますか?

syuilo avatar Aug 02 '23 23:08 syuilo

Either?

salano-ym avatar Aug 03 '23 03:08 salano-ym

エラーを関数の返り値として表現している点ではEitherと似ていると思います。 ですが今回のエラー型は演算の対象となった瞬間にAiscript エラーで処理を停止させるため、Eitherのように成功とエラーを同列に扱うようなことはできません。

FineArchs avatar Aug 03 '23 04:08 FineArchs

@syuilo 同じ概念を持つ言語に心当たりはありません。 単に #282 で言う「null以外の何かを返す」ためのものとしての発想です。

FineArchs avatar Aug 03 '23 04:08 FineArchs

Core:typeだけ特別でそれ以外は専用メッセージを出す? そうでないなら単に型エラーで済む気がする

salano-ym avatar Aug 03 '23 04:08 salano-ym

型エラーだと原因が分かりにくいので…

FineArchs avatar Aug 03 '23 04:08 FineArchs

Core:typeだけ特別でそれ以外は専用メッセージを出す?

~~その通りです。~~ 専用メッセージというか、これまでに出していたエラーと同じメッセージ(index out of rangeやNo such variableなど)を出します。

FineArchs avatar Aug 03 '23 05:08 FineArchs

「null以外の何かを返す」が目的ならエラーチェックしないのはnull参照と同じで自己責任だと思う

salano-ym avatar Aug 03 '23 05:08 salano-ym

普通の1 + "a"みたいな式でもErrorを返すということ? だとしたら強制終了が遅延されるのはかえって分かりにくいような気もするかも?

salano-ym avatar Aug 03 '23 05:08 salano-ym

強制終了が遅延されるのはかえって分かりにくい

それはその通りです ただCore:typeでの分岐を出来るようにするためにはそうせざるを得ないので… 基本的には計算した値はすぐ何かに使うと思うので、問題は軽いと思っています

FineArchs avatar Aug 03 '23 05:08 FineArchs

「null以外の何かを返す」が目的ならエラーチェックしないのはnull参照と同じで自己責任だと思う

ごめんなさい、これよく分かってないです。解説希望です

FineArchs avatar Aug 03 '23 05:08 FineArchs

「null以外の何かを返す」が目的ならエラーチェックしないのはnull参照と同じで自己責任だと思う

ごめんなさい、これよく分かってないです。解説希望です

Json:parseで失敗した返値がError(e)だったとしてこれを特別に扱う必要は無いと思う

salano-ym avatar Aug 03 '23 05:08 salano-ym

Json:parseで失敗した返値がError(e)だったとしてこれを特別に扱う必要は無いと思う

次回参照された時にエラーメッセージを出す機能の話でしたら、まあ無くてもいいかもしれませんがあったほうが便利かなと思っています。

FineArchs avatar Aug 03 '23 05:08 FineArchs

普通の1 + "a"みたいな式でもErrorを返すということ?

とりあえずはモナドのように失敗可能性のある処理にだけErrorを返させようと思っています。

FineArchs avatar Aug 03 '23 05:08 FineArchs

復帰可能(Json:parse)ならError、できない(1+'a')なら強制終了で区別した方がいいと思う。詳しくないけどGoがそんな感じらしいので。 err+1みたいになってエラーが出るのはチェックしなかったことが問題なので普通の型エラー。 Error型を組み込みで入れるのは良いと思う。

salano-ym avatar Aug 03 '23 05:08 salano-ym

1+'a'のような事前回避が容易なエラーはその場で強制終了にするのは賛成ですが、復帰可能性の概念は曖昧で基準にしづらい気がします。何故Json:parseが復帰可能で1+'a'やゼロ除算は復帰不可能なのかよく分かりません。

err+1のような事態で単純な型エラーにせずerrに内包されたエラーを出すのは、出来るだけ今まで同様にエラーを出したいという意図があります。(更新履歴を頻繁に確認する習慣がない人は、急に訳の分からない型エラーが出たら途方に暮れてしまうと思います) とはいえ、これだと先で言われていたような「エラーの発生が遅延されてかえって分かりにくくなる」問題が発生してしまいます。そこで、例えば

number expected but got error. Error Message: "Unexpected end of JSON input"

のような複合のエラーメッセージを出すのはどうでしょうか?

FineArchs avatar Aug 03 '23 06:08 FineArchs

基本的にはその場でエラーを発生させて、ユーザーの選択(専用の構文を使うなどして)でError型の値を返すようにするのはどうでしょう

try catchのように呼び出し元でのエラーキャッチができないと思います。これが少し気になりました

marihachi avatar Oct 04 '23 23:10 marihachi

try {
  someFunc()
} catch(e) {
  processError(e)
}

でやりたいことは基本的に

let result=someFunc()
if (Core:type(result) == 'error') processError(result)

で出来るはずなのでその問題はないと思います。

FineArchs avatar Oct 05 '23 00:10 FineArchs

できないは違いました ifで分岐、returnしてエラーを呼び出し元に伝える必要があるということですよね

marihachi avatar Oct 05 '23 01:10 marihachi

エラーを例外ではなく返り値の型で表すことの利点の一つは(静的型チェックを行うシステムであれば)エラーの種類まで含めて型システムが働くことであり、try-catch文が混ざるとこの利点が消えてしまいます。

また、もう一つの利点は(静的型チェックがあれば)プログラマにエラーの処理を強制出来ることなので

ifで分岐、returnしてエラーを呼び出し元に伝える必要がある

これがむしろ利点になります。

(現状は静的型チェックがないのでただ面倒になっているだけですが…)

FineArchs avatar Oct 05 '23 02:10 FineArchs

せめて

result? //if Core:type(result) == 'error' return result else result
catch(result) {...} // if Core:type(result) == 'error' {...}

みたいなシンタックスシュガーは用意すべきかも…?

FineArchs avatar Oct 05 '23 03:10 FineArchs

基本的にはその場でエラーを発生させて、ユーザーの選択(専用の構文を使うなどして)でError型の値を返すようにするのはどうでしょう

これについてはどうですかね? エラーを処理しなかった場合にエラーの発見が遅れることを防げると思います。ユーザーが後でエラーを処理すると意思表示したときにだけエラーの発生を遅延させます。

marihachi avatar Oct 05 '23 05:10 marihachi

throw-catchの話ではなく、基本的にはその場で実行を停止するようにしたいという話ですか?

FineArchs avatar Oct 06 '23 22:10 FineArchs

エラー処理するまでもなくとりあえず動けば良いというようなスクリプトの使い方もあると思ってます。 この場合はエラーがその場で起こって欲しくないですか?

marihachi avatar Oct 07 '23 03:10 marihachi

エラーを型で表す方式は厳格な型システムを前提としているので、「とりあえず動けば良いというようなスクリプトの使い方」とは思想が真っ向から対立するんですよね…

FineArchs avatar Oct 07 '23 03:10 FineArchs

現状の使い方からするとメッセージ付きのnull-1みたいな感じなので専用構文を挟まないとエラー処理できないのは分かりにくい気がします。 挟ませるとしてどの時点で停止扱いになってどの時点までに挟む必要がありますか?

salano-ym avatar Oct 07 '23 04:10 salano-ym

専用構文でエラー処理を宣言するだけで厳密なエラー処理しようとしている書き手の意図は確認できますね その場合はエンジン側によるエラー停止はしないで良いんじゃないかと思います。 いつまでのエラー処理しないといけないという制約もあるのが理想ですが、実装が複雑になりそうです。

marihachi avatar Oct 07 '23 04:10 marihachi

話を遡りますが、 @saki-lere さんの言っていた「復帰不可能な」エラーとは、「事前回避可能な」エラーをそう呼んでいるという認識で正しいでしょうか? そうであれば、そのようなエラーを即時停止の扱いにする理由が分かってきた気がします。(型システムに組み込むと型チェックが複雑になりすぎる)

FineArchs avatar Oct 07 '23 16:10 FineArchs

@marihachi という訳で、エラーを「即時停止するエラー」と「処理すべきエラー」に分けようと思うのですが、どうでしょうか?

FineArchs avatar Oct 07 '23 16:10 FineArchs

例えば、以下のような2種類を分けるということですかね 型違いの四則演算などエラー処理でなんとかするべきではないもの(常に即時エラー) JSONパースのような入力の違いによってエラーが起こりうるもの(エラー処理可能)

これについては賛成です

marihachi avatar Oct 07 '23 23:10 marihachi