結局C++とRustってどっちが良いの? 5traits

レス数が1000を超えています。これ以上書き込みはできません。
2023/06/30(金) 21:56:35.52ID:PDIJ4aZy
「C++の色々配慮してめんどくさい感じは好きだけど、実務になったらメモリ安全性とか考えて今後Rustに変わっていくんかな」
「うだうだ言ってないで仕事で必要なのをやればいいんだよ、趣味なら好きなのやればいい」

っていう雑談スレ。

結局C++とRustってどっちが良いの? 4traits
https://mevius.5ch.net/test/read.cgi/tech/1686046386/

関連スレ(マ板): Google&MS「バグの70%はC/C++。Rustにする」
https://medaka.5ch.net/test/read.cgi/prog/1619943288/
2023/07/28(金) 14:10:58.16ID:GMHqUp+Z
impl traitの中にgenericsの型パラメータ含めればいい
936をRustで実装すると↓みたいになる
(RustにはEnumクラスもNumクラスもないからFrom<u8>で代用してる)

fn iter_sq_to_100<T>() -> impl Iterator<Item = T>
where
T: Copy + From<u8> + std::ops::Mul<Output = T>,
{
(1u8..=10u8).map(|v| {
let t = T::from(v);
t * t
})
}

fn main() {
// 戻り値を受け取る側からTの型を指定
println!("{:?}", iter_sq_to_100().collect::<Vec<u32>>());
println!("{:?}", iter_sq_to_100().collect::<Vec<f32>>());

// 関数を呼び出す側からTの型を指定
println!("{:?}", iter_sq_to_100::<u32>().collect::<Vec<_>>());
println!("{:?}", iter_sq_to_100::<f32>().collect::<Vec<_>>());
}

ただしこれは型パラメータで戻り値が多相的になってるだけでimpl traitでそうなってるわけではない
多相型もジェネリクスも一緒だと思うけどHaskellとの対比だとクラスをBoundに置き換えればいいのかな
2023/07/28(金) 14:40:11.65ID:g7faSWJw
>>952
すいません、やっぱりわたしの疑問とは違っています
わたしの理解では「impl traitは引数、返り値に一般型をとるが特定のtrait 境界を持つものを指定する場合の糖衣構文」だと思っていたのです
つまり先の例impl Iterator<Item = u32>であれば
①まず

 fn myF(××) -> impl T {...}

の記法でTはtypeではなくてtraitである(ここにtraitが来る事が impl trait 記法の呼び名の理由、この記法は

fn myF(××) -> impl A, where A;T{...}

の糖衣構文で「myFはtrait Tのimplementを持つ任意の型を返す関数」を意味する
と思っていて、よって先の例
fn foo1(input: u32) -> impl Iterator<Item = u32> {...
ではfooはItemがu32であるIterator traitを持つ任意の型を返り値として持てる関数だと思っていました、もちろん自分で好きなクロージャ作ってそれにIterator<Item = u32>をimplementすればそれを返り値に持てると思っているんです
しかしそれは違う、fooは単相型、型は決定しており返り値のサイズも配置も決定しているので分割コンパイルできる(そもそも分割コンパイルの話の中で出てきた話なのでここでの多層性はもちろんこの意味)というツッコミが入ったのでホントかと、もうこのソースでRustはfooの返り値の型を完全に決定してて別のファイルからfooを呼ぶ場合にも別々にコンパイルしてposixの標準のリンカが使えるのかなんてことができるのかと
少なくともHaskellではできないはずです
2023/07/28(金) 15:00:21.91ID:GMHqUp+Z
少なくともfooを呼ぶ側はfooの実装とリンクされるまで
返されるimpl traitのサイズも実際の型も分からないから
完全に分割コンパイルが可能とは言えないね
型が分からないと呼ぶべき関数の実装も分からないから標準(?)のリンカは使えない
traitを実装しててその関数が存在することだけは分かるけど

ただfooの戻り値のimpl traitの型は(型パラメータがなければ)
fooの実装側で完全に決定される
「正体が分からない単相型」って感じ
2023/07/28(金) 15:13:12.73ID:GMHqUp+Z
リンク時に外から型サイズを指定できるオブジェクト形式だと頑張れば分割コンパイル可能なのかな
あまりこの辺は知識がない
2023/07/28(金) 15:26:38.94ID:orZ7jJno
なんかよう分からないけど、この数日のスレ見てても
imp,trait,whereなど知らない概念が多すぎてRustは難しすぎる。
2023/07/28(金) 15:55:11.46ID:CGNQVLgE
>>953
間違った思い込みをしてる
まずは公式ドキュメントを読みましょう
https://doc.rust-lang.org/reference/types/impl-trait.html
2023/07/28(金) 16:22:37.19ID:cNvH/3YC
>>957
間違ってますか?
結論的に
impl Iterator<Item = u32>
を返り値として持つ関数をFile Aで定義して事前コンパイル、その後File Bで独自のIterator <u32> のinstanceを持つ型を作った場合、rust compilorはcompile済みのfile Aをlinkするだけでいいんですか?
2023/07/28(金) 16:33:53.87ID:2BokdQo2
具体的にはどうするんですか?
file AにはItemとしてどんなサイズの型を指定されるかわからないわけですけどcompilorは各引数を受け取る時スタックのどこに第××引数が格納されてると決定できるんですか?
昔のweb情報では「impl traitが静的にアクセスするアドレスを決定できるように多相な型にするには oxで囲まないとダメ」とありました
Boxedである事を要請すれば確かに事前にアドレスを決定できます
しかし先の例ではBoxedてないので呼び出し側が要求する返り値のサイズが決まっていなければ生でスタックに並べられたら呼ばれた関数は引数を読み出せないんじゃないですか?
もちろん動的に呼び出す時に引数のサイズ与えればできますけどRustはアクセスすべきアドレスをコンパイル時に静的に決定してるんじゃないんですか?
2023/07/28(金) 16:45:41.21ID:4cjf/6GX
関数の返し型を具体的に書くかimpl Traitと書くかの違いはもちろん明瞭にある
簡単な例で説明する

// まず実験用のおもちゃ(5ずつ増えるイテレータStepFive)を用意
pub struct StepFive { n: i64 }
impl StepFive {
 fn new(init: i64) -> Self { StepFive { n: init } }
 pub fn cur_value(&self) -> i64 { self.n } // 注意: イテレータには不要な追加機能
}
impl Iterator for StepFive {
 type Item = i64;
 fn next(&mut self) -> Option<Self::Item> { self.n += 5; Some(self.n) }
}

// このおもちゃイテレータを返す関数を二つ用意する
// 返し型を具体的に StepFive と書くケース
pub fn step_five_1(init: i64) -> StepFive { StepFive::new(init) }
// 返し型を impl Trait の形で書くケース
pub fn step_five_2(init: i64) -> impl Iterator<Item = i64> { StepFive::new(init) }

fn main() {
 // イテレータとしてはどちらも当然機能する
 assert_eq!(vec![5, 10, 15], step_five_1(0).take(3).collect::<Vec<_>>());
 assert_eq!(vec![5, 10, 15], step_five_2(0).take(3).collect::<Vec<_>>());

 // しかしイテレータにない機能を使うと違いが明瞭に出る
 assert_eq!(123, step_five_1(123).cur_value()); // コンパイル通る
 assert_eq!(123, step_five_2(123).cur_value()); // コンパイルエラー method not found in `impl Iterator<Item = i64>`
}
2023/07/28(金) 16:46:14.77ID:4cjf/6GX
>>960の続き

つまり返し型を具体的に StepFive と書けばその型の機能をフルに活用できる
しかし返し型を impl Iterator<Item = i64> と書けばイテレータとしての機能のみが使える

後者はコンパイル時に StepFive の実装を知る必要がなくなる
つまり後者は next() で Option<i64> が返るという「impl Iterator<Item = i64>」の一般的知識のみでコンパイルできることになる
その代わり後者は StepFive にcur_value() というイテレータとは別のメソッドがあっても使えないという違いが出てくる
2023/07/28(金) 16:49:54.59ID:GMHqUp+Z
>>956
C++20もconceptとかrequireとか言い出してるから心配しなくていいよ
そのうち追い抜く

>>959
リンク時に確定する呼び出しも「静的に決定される」扱いでいいんじゃないのか
リンク時にアドレスの書き換えとかすると思ってたけど
どこまでがコンパイルでどこからがリンクなのか分からん
2023/07/28(金) 17:13:12.78ID:CGNQVLgE
>>958
コンパイルエラーになるよ
まずは基本的なドキュメント読んで出直してよ
今の段階ではここでやり取りしてもお互いに時間の無駄
964デフォルトの名無しさん
垢版 |
2023/07/28(金) 17:40:24.39ID:sn3bIpOK
>>962
>C++20もconceptとかrequireとか言い出してるから心配しなくていいよ
最近のC++に問題が多数混入したことは知られているが、
人気が絶頂だったころのC++はシンプルで分かり易かったぞ。
2023/07/28(金) 17:59:52.30ID:gdkptAW0
>>964
今はそれより高機能なのにシンプルなRustがベターだね
traitと(代数的データ型である)enumの二つだけ追加で覚えれば済むから
2023/07/28(金) 18:02:55.59ID:GMHqUp+Z
人気が絶頂だったころのC++っていつのC++だ
C++17あたりかな

まさかC++98とは言わんよな…(当時は言語の選択肢が少なかったと思うけど)
2023/07/28(金) 18:26:18.74ID:sn3bIpOK
C++98位が絶頂。
968デフォルトの名無しさん
垢版 |
2023/07/28(金) 19:04:47.55ID:Ih8SBU9O
>>956
流石にそれはRustへの知識が足らんだろ。impl, trait, whereは全てRustでは必要不可欠な概念だぞ。ここら辺がわかってないとなると構造体に関する理解も怪しいだろ。
2023/07/28(金) 19:33:09.89ID:sn3bIpOK
>>968
でも覚えたくないから。
2023/07/28(金) 20:29:08.19ID:rzH+uNMJ
>>956
traitの概念と用法だけ覚えればよくてimplとwhererは一般的な言葉と同じ

implは単なる「実装」
「impl Trait」が型指定の位置に来れば「Traitを実装」している型の意味
「impl Trait for 型」は「その型にTraitを実装」宣言
「impl 型」は「その型を実装」宣言

whereは説明を後置する関係副詞と同じ
型に対してtraitによる境界(制約)などを指定
2023/07/28(金) 20:33:57.60ID:rDj5FSnq
>>967
そっからは…JavaScriptなんかが本気で伸びていった時期か。
2023/07/28(金) 23:59:27.11ID:GMHqUp+Z
C++アンチの大半はC++98を嫌々使ってた世代だろ
C++0xが16進数のBになるとは思わなかった
2023/07/29(土) 02:08:00.81ID:MBm8IaU2
ポコチンファイト
2023/07/29(土) 03:40:53.45ID:yFHJJQio
C++は、98年頃、非常に人気であった。
それが、どんどん人気を失い、現状に至っている。
2023/07/29(土) 05:56:52.93ID:oT83Ayc0
人気があったのはあくまでc とかの古い言語に対してだろ。

当時もperl5とかのスクリプト言語の方が人気だったし。
2023/07/29(土) 10:55:11.31ID:m3e/8XSV
>>965
its true👍
2023/07/29(土) 12:15:13.32ID:mCbo+dID
>>975
C++は、C++11以後、改悪された。
2023/07/29(土) 12:34:34.52ID:XwXxiU6u
>>974
最近また順位を上げてきてるって記事見るよ

>>977
廃止された機能はほとんどないので
C++11が好きならC++11の範囲で使えば良い
その意味では改悪ってことはない
2023/07/29(土) 12:37:22.94ID:mCbo+dID
C++以後とはC++11自体も含む。
C++11が改悪の最初。
2023/07/29(土) 12:42:47.89ID:mCbo+dID
C++11が最良と思っている人はC++が最悪の言語に
見えることだろう。そしてそういう人がRustを礼賛
しているように見える。
ちなみに、Stackoverflow の Most Loved Language
は、実際に使用した上で好き嫌いを表明した人を分母
とした上での好きな人の比率に過ぎないので、
たとえば、
C++ : 好き=50:嫌い=50, 愛され率 50%
Rust : 好き=7:嫌い=3, 愛され率 70%
のようになっているに過ぎない。
この場合、C++好きはRust好きの7倍以上居るが、
比率的には愛され率が50%になってしまって、
Rustより愛されて無い、という結果になってしまうが
それは統計上の一応の数値に過ぎない。
981デフォルトの名無しさん
垢版 |
2023/07/29(土) 12:56:18.62ID:XwXxiU6u
>>979
じゃC++-98使ったら?
moveなしなんて俺は考えられん
2023/07/29(土) 12:56:58.78ID:mCbo+dID
新しいものが良いものだという固定観念は間違い。
C++は、C++98が最良で、C++11で改悪されごちゃごちゃに
なった。
C++を愛する人はC++98を愛した人。
C++11以後を見ると改悪された後なのでごちゃごちゃになった
醜態を見る事になり、C++が大嫌いになる。
そして、そういう人がC++を完全に避けるようになり、行き場所を
失い、Rustを礼賛している。
983デフォルトの名無しさん
垢版 |
2023/07/29(土) 12:58:15.78ID:XwXxiU6u
>>982
相変わらず不勉強な人だな
適応できないとうよりおまいさんは単なる怠惰なんだよ
2023/07/29(土) 12:58:56.51ID:mCbo+dID
>>981
moveは、std::vectorをメインコンテナに位置づけたから
必要となった概念に過ぎない。LinkedListをメインコンテナ
にすれば、不要となる。そして、ここでいうLinkedListとは
本来のLinkedListの事であり、std::listのことでない。
C++委員会は馬鹿ばっかっりなので、本来のLinkedList
を全く理解できて無い。
985デフォルトの名無しさん
垢版 |
2023/07/29(土) 12:59:13.66ID:XwXxiU6u
>>982
moveなしのC++なんよく使う気になるね
986デフォルトの名無しさん
垢版 |
2023/07/29(土) 12:59:23.06ID:mCbo+dID
>>983
違う。
常識が間違っている。
2023/07/29(土) 13:01:23.60ID:mCbo+dID
>>985
数学や右脳的IQが低い人にはLinkedListは理解が難しい
概念とされているため、LinkedListを使わない人に
とって、moveは必須となってしまうが、バグの温床と
なっている。
そのために出てきたのがRust。
何もかもが間違っている。
988デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:02:06.55ID:XwXxiU6u
>>984
>moveは、std::vectorをメインコンテナに位置づけたから
>必要となった概念に過ぎない。
違うだろwww
std::vectorの高速化にも役立つが
vectorのために作られた概念では断じてない
989デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:03:53.63ID:XwXxiU6u
>>987
moveの導入はstd::vectorとは関係ありません
std::vectorでも役に立つってだけ
990デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:06:10.18ID:XwXxiU6u
>>986
いや怠惰だよ
オープンソースを嫌う理由も書いているのを読んだ
適応障害かな?と思っていたが単なる怠惰だよ
991デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:09:29.91ID:XwXxiU6u
この人の行動パターンは新しいことを学習することを極度に嫌うんだな
それ自体は当人の自由だが
「俺が覚えたくない新しいことは間違ってるのでおまいらも覚えるな
おまいらは馬鹿だ」って考え方はどうなのよ?
2023/07/29(土) 13:10:49.76ID:mCbo+dID
はっきりいって、std::vectorとそれに類するデータ構造
以外では、moveはほとんど役立ってない。
2023/07/29(土) 13:11:57.95ID:mCbo+dID
もちろん、意味が有るケースもあるが、コンピュータでは、
「率」が重要となる。
重箱の隅をつつくような事を重視して、優先順位の高い
ことを疎かにすれば、良い結果にはならない。
2023/07/29(土) 13:15:00.69ID:mCbo+dID
コンピュータの世界では何かの概念を導入すると、
必ずと言っていいほど、別の何かとはトレードオフに
なってしまう。
だから、優先順位や使用率、遭遇率、出現確率などを
常に考慮し続けなければならない。
その配慮に欠けているのが(C++11も含む)C++11以後。
そして、Rustは優先順位が間違ったC++11の悪いものを改良して
しまったから、汚い最悪の言語となってしまっている。
センスの悪い言語と言える。
995デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:39:52.19ID:XwXxiU6u
>>992
>はっきりいって、std::vectorとそれに類するデータ構造
>以外では、moveはほとんど役立ってない。
お前のくそコードがそうなのは否定しないよw
996デフォルトの名無しさん
垢版 |
2023/07/29(土) 13:41:30.10ID:XwXxiU6u
>>994
>コンピュータの世界では何かの概念を導入すると、
>必ずと言っていいほど、別の何かとはトレードオフに
>なってしまう。
トレードオフの結果moveによって失われたものを述べよ
2023/07/29(土) 13:44:38.55ID:XwXxiU6u
>>984
>本来のLinkedListの事であり、std::listのことでない。
何が違うの?
2023/07/29(土) 13:51:09.21ID:5uFTVg8T
その人small oの意味間違ってた人?
あの数学力見るととても言ってるほど賢いと思えない
2023/07/29(土) 14:01:34.25ID:mCbo+dID
>>998
俺はそんな間違いはしない。別人だろう。
1000デフォルトの名無しさん
垢版 |
2023/07/29(土) 14:04:41.52ID:mCbo+dID
>>997
手短に言えば、本来の使い方をするためのインターフェースだな。
10011001
垢版 |
Over 1000Thread
このスレッドは1000を超えました。
新しいスレッドを立ててください。
life time: 28日 16時間 8分 6秒
10021002
垢版 |
Over 1000Thread
5ちゃんねるの運営はプレミアム会員の皆さまに支えられています。
運営にご協力お願いいたします。


───────────────────
《プレミアム会員の主な特典》
★ 5ちゃんねる専用ブラウザからの広告除去
★ 5ちゃんねるの過去ログを取得
★ 書き込み規制の緩和
───────────────────

会員登録には個人情報は一切必要ありません。
月300円から匿名でご購入いただけます。

▼ プレミアム会員登録はこちら ▼
https://premium.5ch.net/

▼ 浪人ログインはこちら ▼
https://login.5ch.net/login.php
レス数が1000を超えています。これ以上書き込みはできません。
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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