C vs C++ vs Rust Part.2

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2021/12/15(水) 12:35:50.91ID:biBE4xC0
競え
※前スレ
C++ vs Rust
https://mevius.5ch.net/test/read.cgi/tech/1619219089/
2022/01/08(土) 21:54:31.05ID:FAQD/Dxg
>>510
なあ、例外がなければ安全だなんて言ってる無能な働き者はお前ぐらいだけど、大丈夫?
2022/01/08(土) 23:09:37.91ID:dcBn+b5K
>>509
>もしくはリソース不足などでの続行不可能などの事象はエラー処理ではないためパニック処理として分離した
>したがって曖昧な存在である例外というものは消え去った
ここで言ってるパニック処理が例外処理そのもの
例外処理用のハンドリング方法を別途用意しただけであって例外というものが消え去ったわけではない
2022/01/08(土) 23:12:31.28ID:dcBn+b5K
>>509
カーネルコードでアロケーションエラーを例外としてではなく通常のエラーとして処理するのは
アロケーション自体が自作だからではないよ
2022/01/09(日) 00:21:57.46ID:fLRbfEkO
Rust坊の植民地になった。ここまでC/C++に対する優位性の証明ゼロ、分裂したRust坊を収容するスレ
あんたらが本当に必要なのはRust初心者スレだ。親の仇のようにC/C++に攻撃性を向けるのはもうやめたら?
515デフォルトの名無しさん
垢版 |
2022/01/09(日) 03:40:09.35ID:IJqCXjgr
トリオンが足りないのでは?
2022/01/09(日) 04:14:04.91ID:sevz4s4M
誰もC++攻撃してないよね
2022/01/09(日) 09:21:12.75ID:IY0PEP+W
元々はRustスレに定期的に出没する「俺は天才だからC++でも安全なコードを書ける、Rustの制約はパフォーマンスの足枷」ってうるさい奴を隔離するスレだったんだよな
あいつがフェードアウトしたのに逆の意味でスレが機能し続けるのは皮肉なもんだ
2022/01/09(日) 09:37:17.07ID:E6fr7wut
>>503
英語版wikiの定義を読むといい

例外の定義や理解1つとっても日本がIT後進国なのを痛感する
2022/01/09(日) 10:02:26.10ID:QVmVQA75
>>518
> 日本がIT後進国なのを痛感する
例外の話だけじゃなくてこれはいろんなとこににじみ出てるよな
いろんなwikipediaの記事も日本語版って何かあいまいだったり
説明が簡潔じゃなかったりして驚く

まぁこれに関しては国のIT進歩度というよりは
あっちの人のほうが単に理論的で
理論的に書くのが好きで
理論的に書いてないのを許さない文化がるんだと思う
2022/01/09(日) 10:37:31.41ID:oMGs2plE
>>518-519
そういう具体性の欠片もないレスでドヤ顔されても… w
2022/01/09(日) 10:38:49.37ID:0wOzwgXF
>>519
それが逆に数学分野や工業化学分野だと、日本の方がはるかに端正で正確な記述だと思っているのです…
2022/01/09(日) 11:07:34.53ID:QVmVQA75
>>521
まぁ個人の感想なんで気にしないでねw
あとプログラミング言語の本も日本人が書いたものより
海外のものを翻訳したやつのほうがスッキリしてると感じる
説明も体系的というか
2022/01/09(日) 11:28:40.59ID:B5+MKIjQ
www 503 == 520 == 521 www
2022/01/09(日) 16:55:21.90ID:dllKbKSF
>海外のものを翻訳
ここは笑うところか?
2022/01/09(日) 18:55:06.30ID:KYx55eM0
wikipediaで知識を語る超初心者がマウント取るための厨房すれ
526デフォルトの名無しさん
垢版 |
2022/01/09(日) 20:11:12.28ID:IJqCXjgr
例外をサポートしない言語は例外が発生しないので例外安全です。
527デフォルトの名無しさん
垢版 |
2022/01/09(日) 21:06:21.23ID:prbTf4O2
型安全性を保証しない言語は型検査エラーを起こさないので型安全ですって言ってるようなもんやん
2022/01/09(日) 22:16:01.73ID:tE6q+RNQ
例外安全てのは例外によって引き起こされる問題に対して安全かどうかなんだからその喩えは不適切
2022/01/09(日) 22:29:15.26ID:z2Ja0yjO
何かを言っているようで実質内容がないw
530デフォルトの名無しさん
垢版 |
2022/01/09(日) 22:32:02.28ID:IJqCXjgr
全てのエラーは例外が原因です。
例外サポートを無くしましょう。
2022/01/09(日) 22:52:05.52ID:8Ry9gb1y
>>526
https://en.wikipedia.org/wiki/Exception_safety
> The guarantees presented here originated out of work on C++, but apply equally to other languages and error-handling mechanisms.
2022/01/09(日) 23:01:24.93ID:ULYulOFy
Rustがtry-catchの例外機構を持たない理由は非常に単純で
(A) 本質的にリカバリできることは通常のエラー処理だけで十分に対処可
(B) 本質的にリカバリできないことはpanic
前者の(A)では関数がResult<T,E>で返しそれがエラー時Err(E)の時に
処理をスルーして上位へ移譲したいならfunc()?と?を1文字付加だけで済む仕組み

一方で(B)の「本質的にリカバリできない」panicとは具体的に次のどちらかとなる
(1) プログラムに論理的な間違いがある場合
(2) 何らかのリソース不足になった場合

この(1)は具体的に以下のようなケースがある
- ありえない状況に陥ってプログラマー自らpanicさせる場合
- 一部の標準ライブラリに対してありえない値を渡した場合
- 配列などで範囲外のインデックスで操作しようとした場合
- ResultやOptionで正常値でない時にunwrap()した場合
- RefCellやRwLockで実行時借用ルールを犯した場合
これらはプログラムに論理的な間違いがある場合のみ生じるためエラー処理とは本質的に異なる

一方で(2)の「何らかのリソース不足になった場合」は
プログラム自体には論理的なミスはないが何らかが溢れた以下のケース
- 数値型が溢れて計算を続行できない場合
- ヒープが溢れて新たにアロケーションできない場合
- スタックが溢れて新たに関数呼び出しができない場合
このうち数値溢れ演算はpanicを起さないチェック付き演算で置き換えて回避可能
アロケーションもpanicを生じさせないアロケーターを作ることで回避可能

# ちなみに「リカバリできないことはpanic」の考えはクロージャ単位にまで拡張されていて
# panic::catch_unwind(クロージャ)を使うとResult<T,E>を返しpanic時にErr(E)を得られるため
# そのクロージャ自体は内部でリカバリできないがpanic発生を捕捉すること自体は可能

このようにRustでは曖昧な存在である『例外』を廃して
通常のエラー処理と真の異常時であるpanicの二種類に分けて扱っている
2022/01/09(日) 23:16:25.98ID:ShKK+0Hb
昔のテレビにはホワイトノイズあったけど、そんな感じです
534デフォルトの名無しさん
垢版 |
2022/01/09(日) 23:43:54.04ID:IJqCXjgr
プログラムには二種類ある。
例外か例外でないか。
例外は悪。
それ以外は善。
2022/01/09(日) 23:45:42.71ID:pQtTDH+G
じゃあ配列の範囲例外が発生するプログラムは全部悪ですね、範囲外を示して書き換えられるようにしないと!
なるほどです!ためになります!
2022/01/09(日) 23:50:45.64ID:uOSYnK8a
>>535
それはプログラムがバグってるから当然悪
正しいプログラムで範囲外アクセスが生じることはない
2022/01/10(月) 00:23:41.85ID:KrhDNAF9
>>532
数値の溢れをリソース不足に分類するのは違和感あるなあ
論理的間違いに分類するのが適切では
2022/01/10(月) 00:56:16.67ID:yjEJqFVX
>>537
例えば以下のフィボナッチ数列を表示するプログラム
fn main() {
let mut m: i32 = 1;
let mut n: i32 = 1;
loop {
println!("{}", m);
let next = m + n;
m = n;
n = next;
}
}
これは45回まで正しく表示した後に46回目に数値が溢れてpanicとなる
プログラム自体に論理的な間違いがあるわけではない
ただ数値の溢れというリソース不足を起こしただけにすぎない
2022/01/10(月) 01:07:09.56ID:yDWpdoZh
配列の範囲外(Index bounds)と言っているのに、数値の溢れ(overflow)をリソース不足と言い出す
「論理的間違い」とか何を言ってるのかサッパリ分からんな、こんすれの隔離Rust超初心者たち…
2022/01/10(月) 01:19:02.91ID:yjEJqFVX
>>539
その違いは明白
配列の範囲外アクセスはプログラムが論理的にバグっている時のみ生じる
数値の溢れはプログラム自体が論理的に正しくても生じる
2022/01/10(月) 01:56:06.89ID:jIBPGNfV
数値型の範囲も論理的に考慮してくださいよ
2022/01/10(月) 02:26:23.03ID:yjEJqFVX
>>541
それは単なるリソース不足による数値の溢れだから無意味
例えば>>538のプログラムはi32型をi64型やi128型やu128型にすれば少しは延命する
例えばu128型(unsigned 128bit整数)にすれば185個の正しいフィボナッチ数列を出力できる
しかしそこまでに過ぎずこれはリソース不足の問題である
それより上はBigIntなどの数値上の上限がない型を用いることになる
するとこれもいずれ途中でメモリ不足でアロケーションできず同様にpanicするだろう
したがってこれは「プログラムの論理的な間違い」ではなく「数値の溢れというリソース不足の問題」である
2022/01/10(月) 02:32:35.04ID:p+yOPw5a
>>541
論理的に返答できる相手がどうかも論理的に考慮してくださいよ
544デフォルトの名無しさん
垢版 |
2022/01/10(月) 03:15:13.62ID:B939XhoW
例外は危険なりよ。
2022/01/10(月) 08:11:22.08ID:G9ZH73mK
有限回のイテレーションしか回せないことが分かっているのに無限ループで書くのはプログラムの論理的な誤りじゃないんだ?
メモリだのファイルディスクリプタだのPIDだのの枯渇、いわゆる通常の「リソース不足」と違って、事前に発生が完全に予見できるのに?
2022/01/10(月) 08:38:15.28ID:yjEJqFVX
一般的に対策としてはもっと大きな整数が扱える型を用いることになり行き着く先はBigInt
例えば以下のフィボナッチ数列を表示するプログラム
論理的な誤りがあると主張するならば具体的にどこをどう直しますか?
use num_bigint::BigInt;
fn main() {
let mut m: BigInt = 1.into();
let mut n: BigInt = 1.into();
loop {
println!("{}", m);
let next = m + n.clone();
m = n;
n = next;
}
}
2022/01/10(月) 08:43:23.03ID:gmQTKrMe
>>538
普通は必要とされる範囲を規定してそれに適した型を使う
なのでオーバーフローは論理ミスだよ
2022/01/10(月) 08:50:28.54ID:G9ZH73mK
>>546
しれっとBigIntに直したそのプログラムには論理的な誤りがあると主張しません
>>538のi32版は論理的な誤りがあり、+の代わりにchecked_addを使って以下のように修正できます
fn main() {
let mut m: i32 = 1;
let mut n: i32 = 1;
loop {
println!("{}", m);
if let Some(next) = m.checked_add(n) {
m = n;
n = next;
} else {
break;
}
}
}
https://play.rust-lang.org/?version=stable&;mode=debug&edition=2021&gist=17058fd1c2a1c69f111ac09a94681ee6
2022/01/10(月) 08:56:07.29ID:pS98ddBp
>>545
有限回のイテレーションしか回せないとしてもその回数を事前に知るのは困難ではないか?
だから無限ループを用いるとこには何ら問題ないと思う

>>547
範囲を規定できる用途ばかりではないだろう
そのケースは出来る限り多くのフィボナッチ数を出力したいのだから範囲を規定することがナンセンス
2022/01/10(月) 08:57:32.63ID:pS98ddBp
>>548
それは>>196で既出
2022/01/10(月) 09:03:32.42ID:yjEJqFVX
>>548
それは>>532の「このうち数値溢れ演算はpanicを起さないチェック付き演算で置き換えて回避可能」の通りだから当たり前
2022/01/10(月) 09:03:49.79ID:cQg1KnlR
>>549
> 範囲を規定できる用途ばかりではないだろう
規定できる用途の方がはるかに多い
て言うかまともなプログラムなら規定してないなんてことはまずない
テストできないし
> そのケースは出来る限り多くのフィボナッチ数を出力したいのだから範囲を規定することがナンセンス
そんなケース滅多にないだろw
2022/01/10(月) 09:07:37.24ID:G9ZH73mK
>>551
「チェック付き演算に置き換えて回避可能」は「本質的にリカバリできない」に含まれるのか?

ていうかそもそもその区分は何のために存在するんだ?
Rustが例外を採用しない理由として言語開発者たちがそのように主張しているのか?
それとも君の感想?
2022/01/10(月) 09:20:25.60ID:yjEJqFVX
>>553
前者はpanicを回避可能
それでも計算続行不可能という点では後者の本質的にリカバリできないに該当なのかな
だからそれらは両立していると思うのだがどうだろうか?

あと「例外を採用しない理由」をなぜここで突然言及するのか疑問だが
もし以下の話について言っているのならば
>>532
>> Rustがtry-catchの例外機構を持たない理由は非常に単純で
>> (A) 本質的にリカバリできることは通常のエラー処理だけで十分に対処可
>> (B) 本質的にリカバリできないことはpanic

チェック付き演算を使用した場合は前者になるし
使用せずにオーバーフローすれば後者になるのだから
そこに何か明白でない論点はないと思うのだがどうだろうか?
2022/01/10(月) 09:31:36.48ID:aaWRldUf
>>546
それリソース不足にはなるけどオーバーフローにはならないよね?
2022/01/10(月) 09:44:54.40ID:pS98ddBp
>>552
ケースが多いか少ないかは関係ない
ケースが少ないから無視していいなんてことはプログラミング界隈ではありえない

>>555
元々こう書かれてるからそこはどちらでも関係ないかもな
多倍長整数型が溢れるのはリソース不足しか思いつかん

> >>532
> - 数値型が溢れて計算を続行できない場合
2022/01/10(月) 11:51:44.97ID:mx4R5SfM
今日はNGしやすくて助かる
いつもこの調子で頼むよ
2022/01/10(月) 12:01:05.13ID:m6EPjr42
>>553
リカバリできないかどうかは状況に応じて開発者が主観的に判断するものなので
「本質的にリカバリできない」かどうかを考えるのは無意味

エラーハンドリングの基本
もちろんRustの言語開発者も同じ考え方
https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html
2022/01/10(月) 12:12:45.84ID:pS98ddBp
Rustはそこに書いてあるようにエラーをResultで返すかpanicかの2択で済むもんな
2022/01/10(月) 13:03:25.90ID:EipmFK9a
>>556
>> - 数値型が溢れて計算を続行できない場合
だからそれは論理間違いだろ
2022/01/10(月) 13:56:51.54ID:uivNzQl2
数値型のオーバーフローをリソース不足と言って共感得るのは無理だろうな
プログラムにおける上限下限は暗黙的または経験則的に考慮して設計実装されるし、まともなユニットテスト書けば当然検出されるバグ

仮にオープンソースとして世に出すなら、マニュアルやバグレポートに対してどう対処するのか興味ある
2022/01/10(月) 14:09:36.74ID:NhSa0Exb
曖昧な例外を廃して、とかいっても結局そういう「経験的」とかいう曖昧なレベルでしかなされてないってことよな
2022/01/10(月) 14:16:44.51ID:pnnjNIgm
本人の理解が曖昧なだけだから
2022/01/11(火) 15:22:08.76ID:2061HgWk
結局try catch例外処理なんて最初から不要なものだったんだな
だから最近の言語RustやGoにはそのような無駄なものがないわけだ
2022/01/11(火) 15:51:54.57ID:t1MM9BO+
Rustが例外機構を無くとも同等のことを快適に記述できる要因は二つ
HaskellのEitherモナドを値付きenumとして表現したResult<T,E>を関数の戻り型としたこと
そしてResultがErrの時に?オペレーターにより見えない即時returnをするショートカットを用意したこと
2022/01/11(火) 16:40:23.19ID:wv+/KAmB
気持ち悪い自演はもうやめてーー
2022/01/11(火) 21:12:28.05ID:LUMp2LI9
検査例外と一緒なんだけどね
2022/01/11(火) 21:26:17.78ID:xKqG3MQU
そういえば例外の信奉者ほどJavaの検査例外を糞味噌に言うけど、例外機構の型検査をきっちりやろうとしたら
ああいう方法しかないわけだよね。
2022/01/11(火) 23:24:53.53ID:Ijlv3HIe
フロントエンドやサーバーサイドは間欠故障まではあっても、大抵リトライとタイムアウトで救える
バックエンドの耐障害性の設計がまともなら、だけど

そりゃエラーチェックなんて馬鹿らしくなるわな
2022/01/11(火) 23:38:16.29ID:Htfqiioy
大半のアプリケーションでは個別にハンドリングせず
集約エラーハンドラに任せたいとエラーのほうが圧倒的多数だから
呼び出し階層全てにどの例外が発生しうるかを書いていかないといけない検査例外が嫌われるのは自然なこと

Javaの場合は例外クラスの階層の問題とかその他の要素も相まって糞味噌扱い
2022/01/11(火) 23:39:37.20ID:2061HgWk
なるほど
こういう理解であってますか?
「Javaの検査例外」と「RustのResult/Optionエラー処理」を比較すると

(共通点)
以下をコンパイル時点で強制することで安全性を保証
「誰かがエラー時の捕獲と処理(Javaではcatch、Rustではmatch等)を必ずしていること」

(相違点)
Javaでは例外と同じtry-catchを利用 (そのため入れ子で例外が握り潰されたりややこしい)
Rustでは例外はなく通常の関数呼び出しと値返し処理となり、
関数の返す型がResultまたはOptionのenum型、
多段呼び出しの場合に途中で「?」使用によりエラー時にスルー可、
自分もしくは上位の誰かがResultまたはOptionのenum値をチェックしてエラー処理

Rustではエラー時にエラー表示して終了で良い場合は以下の楽にサボる方法もサポート
最上位のmain()がResult/Optionを返すことで自動的にエラー時に表示終了
ResultまたはOptionをunwrap()等してエラー時に即時panic終了
このpanic終了はスレッド単位やタスク単位も可能なのでサボりサーバー等も実装可
2022/01/11(火) 23:52:36.57ID:Htfqiioy
Rustも呼び出し階層全てでどのエラーが発生しうるか型で管理しないといけないからJavaの検査例外と同じ面倒臭さがある

面倒臭いからといって全部Result<T, Box<dyn Error>>にしちゃうと何のエラーが発生するのか分からなくなってしまう

面倒臭さと堅牢さのトレードオフ
2022/01/11(火) 23:58:57.17ID:2061HgWk
>>572
dyn Error返しでもエラー処理自体は可能なので
Rustは様々なサボり方をサポートしつつ堅牢にすることもできる選択があるので良いと思います
574デフォルトの名無しさん
垢版 |
2022/01/12(水) 01:37:24.08ID:nBmB5mPZ
戻り値を返さないコンストラクタやデストラクタ内でエラーが発生したら、例外
以外に通知する方法があるなら教えてほしい。

例外ハンドラを書かないって、エラー処理を一切しない、例えばディスクが一杯で
書き込めないとか、何かあると問答無用で落ちるプログラムってことだぞ。
2022/01/12(水) 01:42:57.07ID:zk3KtN+K
例外 (panic) 以外ないね
エラーが発生しうる処理はデストラクタが呼ばれる前にやるべきかな
RustでもBufWriterなんかがスコープアウトでdrop呼び出される前に明示的にflush必要だったりする (drop内のcloseで発生するエラーは無視される)
2022/01/12(水) 02:19:37.87ID:Fd1MyF0L
>>574
I/Oなどエラー発生の可能性が必ずありうるものはRustではResultが返る
唯一の例外がデストラクタすなわちRustではdrop
そこで問題になりうる可能性があるのはRAIIで自動的に呼ばれるデストラクタに依存して処理を行なうケース
エラーを捕捉したい時は>>575のように事前回避するがpanicさせてそれを捕捉も可能
2022/01/12(水) 11:53:11.60ID:EMNsA0zN
>>574
コンストラクタやデストラクタ内ではエラーが発生しないように作れって習わなかった?
それでも避けようのないエラーなら落としたほうがいい
プログラム全体を落としたくなければスレッドやプロセスを落とす
2022/01/12(水) 12:24:49.11ID:tJ2PyYKm
C++で例外安全をちゃんとやるの難しそう
2022/01/12(水) 12:30:04.82ID:ii0KI3af
>>577
デストラクタでエラーはまずいけどコンストラクタで避ける理由は無かろう。
[迷信] コンストラクタから例外を送出してはならない
https://www.kijineko.co.jp/%E8%BF%B7%E4%BF%A1-%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%81%8B%E3%82%89%E4%BE%8B%E5%A4%96%E3%82%92%E9%80%81%E5%87%BA%E3%81%97%E3%81%A6%E3%81%AF%E3%81%AA%E3%82%89/
2022/01/12(水) 12:31:30.95ID:ii0KI3af
>>578 Rustなんかだと何か簡単になるの?
2022/01/12(水) 12:54:54.70ID:zk3KtN+K
unsafeのpanic-safeはそれなりに気を遣わないといけないよね
safeだと特に何も考えなくても良い?
2022/01/12(水) 14:16:26.71ID:gLPtO7rz
C++は何種類もコンストラクタがあって大変だが
Rustはコンストラクタが無いため問題は発生しない
Rustにも自動で呼ばれるデストラクタはあるが
その前に捕獲すべきエラーが発生しうるものを自分で処理しておくので無問題
2022/01/12(水) 20:35:54.02ID:xJEGl+xo
俺はコンストラクタで例外投げないし投げさせないな
コマンドのような短命プロセスで雑な実装で良いとか、必然性があるなら別だけど
2022/01/12(水) 21:30:33.58ID:zk3KtN+K
コンストラクタと言ってるからc++だと思うけど事前条件を満たさないでコンストラクタが呼び出されたらどうするの?
2022/01/12(水) 21:36:50.23ID:MHAI7amN
南無三!と叫びながらreturn
2022/01/12(水) 22:39:14.21ID:CbaowxsH
>>583
> コマンドのような短命プロセスで雑な実装で良いとか
何その意味不明な必然性w
2022/01/12(水) 22:42:53.89ID:5pTy1wN9
いやわかるやろ
長期間安定して走らないといけないプログラムとそうでないのとはあるやろ
2022/01/12(水) 23:16:19.38ID:DMKGOQqO
>>584
ファクトリメソッド経由でしかコンストラクタは呼び出せないようにするんだよ
2022/01/12(水) 23:43:13.07ID:DMKGOQqO
コンストラクタでエラーが発生しないようにするのはリークの問題じゃなくて使いやすさの問題
new Hoge()を呼べるなら個別にハンドリングが必要なエラーは発生しないと分かるのが重要
デストラクタと違ってコーディング規約的なもの
590デフォルトの名無しさん
垢版 |
2022/01/13(木) 00:32:37.82ID:RultHF/h
>>589
コーディング規約(w

コンストラクタ内で、動的配列のクラスやテンプレートを使ってると、例外が発生する
可能性は常にある。 他の言語は知らんが、C++の場合、コンストラクタ内で例外が
発生すると、デストラクタは呼ばれない。
591デフォルトの名無しさん
垢版 |
2022/01/13(木) 00:41:21.53ID:RultHF/h
例えば、ファイルハンドルをラップしたファイルクラスがあったとして、引数なしの
デフォルトコンストラクタと、引数でオープン済のファイルハンドルを渡すコンスト
ラクタを定義したとして、後者のコンストラクタが無効なファイルハンドルを引数
として呼ばれたら、例外をスローするように実装するだろ?

後者のコンストラクタは、dup()で複製したファイルハンドル等を扱う際に必要。
2022/01/13(木) 01:53:08.91ID:hGSK4csp
>>591
ファイルハンドルが無効な場合をエラーとして処理すべきならコンストラクタを直接使わせずファクトリー経由にする
panic相当の例外として処理すべきならコンストラクタ使って例外スローでかわまない
2022/01/13(木) 05:45:30.92ID:aa54J19o
>>587
それとコンストラクタで例外発生させないことは関係なくね?
2022/01/13(木) 07:16:55.50ID:QuitFgmw
コンストラクタも例外も存在しないRustでは問題自体が生じない
>>591のケースでもRustでは後者のビルダー関数がResultを返すだけで済む
595デフォルトの名無しさん
垢版 |
2022/01/13(木) 08:12:03.99ID:RultHF/h
Rustって、名前の通り錆付いてるようだな。 例外(Exception)がないって、要は
Panicって名前とtry〜catchと互換性のない俺仕様の記述を発明しただけじゃん。

ttps://news.ycombinator.com/item?id=11370841
ttps://www.reddit.com/r/rust/comments/bzaxf2/why_rust_doesnt_have_exception_handling/
ttp://joeduffyblog.com/2016/02/07/the-error-model/

返す型を限定するのは、C++でもコーディング規約で縛れば済むだけの話だし。

結局、Nullポインタ程度で騒いでいるのは、マニュアルフォーカスのカメラでピンボケ
するとか、マニュアルミッションの車でクラッチ繋ぐのミスると、エンストするって
言ってるのと変わらん気がするナァ。
2022/01/13(木) 08:32:43.99ID:pYL+3tES
>>595
開発人数が増えると規約を守らせるコストが大きくなるからね
2022/01/13(木) 08:53:54.36ID:QuitFgmw
>>595
panicと例外は全く異なる
議論に立ち入りたいならばせめて最小限の理解をしよう
完成した通常のプログラムにおいてpanicが発生するのはメモリ不足の時のみ

次に、例外はそもそも必要ないことに気付こう
エラーが発生する可能性があるならばエラーを返せばよいだけだ
これでプログラミングにおいて困ることはない
try〜catchの例外機構はそもそも必要のないものだったのだ
2022/01/13(木) 12:20:53.94ID:VLvCS3li
>>597
panicが発生したときの制御フローは通常のフローと同じなの?

もし違うのなら、通常フローへの復帰はどうやるの?
2022/01/13(木) 12:34:07.73ID:k/BdCeDW
>>598
unwindingされてキャッチされるまでスタックが巻き戻るよ
例外と同じ
2022/01/13(木) 13:04:20.54ID:nB26Onrd
その点も含めて、少なくとも >597 の「全く異なる」は嘘だね。
後段の「エラーが発生する可能性があるならばエラーを返せばよいだけだ」についても、
じゃぁ何で panic があるの?ってなるし、どういうわけか例外憎しで適当なこと言いたいだけみたい。
2022/01/13(木) 13:23:05.77ID:k/BdCeDW
rustのpanicとかエラーハンドリングの考え方はgolangの影響大きい気はする
Result型を使うか多値でエラーを返すかの違いはあるが、panicという名前と動作、戻り値との使い分けは同じ
2022/01/13(木) 13:24:11.54ID:k/BdCeDW
なので >>595 のrustは俺仕様を発明したという指摘も事実と異なると思う
2022/01/13(木) 14:47:56.89ID:ToUR5G3E
エラーモデルの理解が浅い人を寄ってたかって叩いたところで得るものはないぞ
604デフォルトの名無しさん
垢版 |
2022/01/13(木) 15:05:09.73ID:2BXAobev
>>598
panicはバグ発生かメモリ不足でのみ起きる。
だから通常フローへの復帰はせずにabortとなる。
abort前に後処理をしたい時やデバッグ情報を出したい時のためにstd::panic::catch_unwindがある。
それらの処理のためにスタックが巻き戻る。

>>600
一方でtry catch例外処理はpanicとは完全に異なるものである。
単なるエラー処理でも使われて通常フローへの復帰をする。
そのためtry catchが言語の構文となっている言語も多い。
GoやRustにはこの例外処理はなくtry catchも無い。

プログラミングにおいて、エラー処理のためのtry catch例外処理は本来不要なものである。
エラーは関数の戻り値で返せばよい。
このように本来のやり方でエラーを返すのがGoやRustであり、これで実際に動いている。
つまり、単なるエラー処理のための例外機構は必要ないものであることがわかる。
2022/01/13(木) 15:34:59.47ID:oax73caB
>>604
話が微妙に違うなぁ。

「エラー処理としての例外は不要(panicや例外みたいに制御フローが異なる機能は必要)」
という話と
「例外処理そのものが不要」
という話がごっちゃになっていない?
2022/01/13(木) 15:50:06.61ID:E5YlFTVp
>>604
> プログラミングにおいて、エラー処理のためのtry catch例外処理は本来不要なものである。
> エラーは関数の戻り値で返せばよい。

あらゆる関数/メソッド呼び出しのたびにエラーチェックをするのが煩雑だから、try-catchが生み出されたんだと思う。
例えば、データベースアクセスが発生する三つの関数を呼び出すとき、
try {
  foo();
  bar();
  baz();
  commit();
} catch () {
  rollback();
}
みたいな。
続行不能なエラーが発生したが、本流に戻る必要があるときは便利。
607デフォルトの名無しさん
垢版 |
2022/01/13(木) 15:52:35.91ID:2BXAobev
>>605
話がごっちゃになっているのはtry catchの例外処理。

Rustでpanicが起きるのはバグとメモリ不足であり、絶対に起きてはいけない状況。
だからpanicの標準動作はそのままabortとなっている。
一方でエラー処理は起き得ることだから関数の戻り値で返す。

一方でtry catchの例外処理は、それらをごっちゃにまとめて扱っている。
単なるエラー処理を、なぜ、try catchで扱ってしまうのか?
それは関数の仕様設計ミスである。
ちゃんとエラーを返せば、単なるエラー処理のための例外処理は不要となる。
2022/01/13(木) 15:56:44.41ID:wvcpI8iw
Rust擁護するあまり無理筋の論理展開だな
プログラミングに必須じゃない機能は不要と言い出したらキリないのでは
2022/01/13(木) 15:59:01.01ID:k/BdCeDW
>>607
rustのpanicだってabuseできるし
べき論の話で言ったらC++もエラー処理には戻り値を使うべき

現在のベストプラクティスは両者とも大差ないのでは
610デフォルトの名無しさん
垢版 |
2022/01/13(木) 16:20:05.76ID:2BXAobev
>>606
Rustなら色々やり方あろうけど、わかりやすい例にするとこうなる。

fn main() {
match sub() {
Ok(result) => { commit(); println!("OK: {}", result); },
Err(err) => { rollback(); println!("ERROR: {}", err); },
}
}

sub() -> Result<DataType, Error> {
let a = foo()?;
let b = bar()?;
baz(a, b)
}

foo(), bar(), baz()各々はResultでエラー値も同時に返しているが、エラーチェックはまとめて出来る。
ResultはOkとErrの2つを取るenumであり、matchは強力なswitch相当と思っていただければいい。
try catchといった例外処理がなくてもプログラミングで困ることはない。
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況