探検


オブジェクト指向はオワコン? part4

1デフォルトの名無しさん
垢版 |
2026/09/24(木) 21:48:24.69ID:R0E4hCxI
過去スレ
オブジェクト指向はオワコン (2023/08/26〜)
https://mevius.5ch.io/test/read.cgi/tech/1721393540/
オブジェクト指向はオワコン? (2024/07/19〜)
https://mevius.5ch.io/test/read.cgi/tech/1721393540/
オブジェクト指向はオワコン? part2 (2026/08/13〜)
https://mevius.5ch.io/test/read.cgi/tech/1786599483/
オブジェクト指向はオワコン? part3 (2026/08/26〜)
https://mevius.5ch.io/test/read.cgi/tech/1787712923/
2026/09/25(金) 14:15:10.04ID:re2WXZGd
>>前スレ終盤
あんなものは抽象化じゃねぇってw
抽象という言葉の意味すら理解していない無知がカッコつけてそう呼んでいるだけ。
あえていえば相称関数あるいはデータ構造付属メソッド
2026/09/25(金) 14:26:17.33ID:h51z3iXb
抽象データ型(ちゅうしょうデータがた、英: abstract data type、ADT)とは、データ構造とその操作手続きを定義したデータ型、またはデータ抽象の方法の1つ。
通常のデータ型であれば変数宣言で変数に束縛されるものは値であるが、抽象データ型の世界において値に相当するものはデータ構造とその操作のまとまりである。

抽象データ型を用いない場合、データ構造またはデータの操作手続きのアルゴリズムの変更を行うとソースコード中にその変更部分が散在してしまい規模によっては修正困難となるが、データとその操作がひとまとめに記載されることになる抽象データ型においては、型の定義における実装部分を変更するだけで修正が完了する。
2026/09/25(金) 14:26:49.36ID:h51z3iXb
プログラムが実装されたとき、抽象データ型は実装を隠蔽するインタフェースを表す。
実装は将来において変更されうるので、抽象データ型のユーザーは実装ではなくインタフェースに関心がある。

抽象データ型の強みはユーザーから実装が隠蔽されていることである。
インタフェースのみが公開されるのである。
このことは、抽象データ型がいろいろな方法で実装されうることを意味するが、インタフェースに忠実な限りユーザープログラムは影響を受けないのである。
2026/09/25(金) 14:32:18.06ID:h51z3iXb
抽象データ型は各自のプログラムで必要となる固有のものを各自で定義できる。
汎用的な抽象データ型としては、以下のようなものがライブラリとして提供されていることが多い。
Collection
Container
List
String
Set
Multiset
Map
Multimap
Graph
Tree
Stack
Queue
など
2026/09/25(金) 14:35:34.10ID:re2WXZGd
>>3,4
その辺の入門的なWebから引用してきたような説明だな
2026/09/25(金) 14:38:36.88ID:re2WXZGd
しかし、特に抽象的でないものに対して抽象,抽象
うるせえ野郎だな
中小くらいにしとけ
2026/09/25(金) 14:43:09.86ID:OKDl5iMv
オブジェクト指向におけるインタフェース抽象型はその抽象データ型をさらに発展させたもの
複数の異なる型に対して共通の振る舞いをインタフェースとして宣言する
そして各型はそのインタフェースを実装する
プログラムの引数や変数などをインタフェース抽象型として記述できることが特徴である
それによって共通の振る舞いを一つのコードで共通コード化できる
そのインタフェースを実装しているならば任意な型で動作することができる
つまり特定の型に依存せずに抽象的なコードを書くことができるようになった
2026/09/25(金) 14:46:53.55ID:re2WXZGd
異なるデータ構造に対する処理で
同じメソッド名、引数で呼べる関数があったら
なぜ抽象なのか
2026/09/25(金) 14:56:02.05ID:UuV8E4i+
型は違えど同じ共通操作をしたいことがプログラミングでは多々あるだろ
それを共通インタフェースとして宣言して各型はそのインタフェースを実装する
そのインタフェース抽象型で記述した関数は抽象的なコードになって各型に横断的に使える
これは抽象的なジェネリックな関数のパラメータ型が、あるインタフェース実装をしている制約を満たす時と同じになる
11デフォルトの名無しさん
垢版 |
2026/09/25(金) 14:57:44.90ID:DP8L+qwL
>>9
具体的データ構造に依存しないから抽象ではあるんじゃね
その抽象が役立つものかどうかは別として抽象ではある
仮にその抽象にモスフングスという名前をつけてみよう
その名前が役立つかどうかは別の話だ
2026/09/25(金) 15:04:45.24ID:b8yGhIZZ
>>9
それだけだとたまたま構造的に同じメソッド名だけかもしれない
構造的なインタフェース型付けではそれでも同じに扱ってしまう弱点がある
一方でインタフェース名を宣言する場合は区別ができてたまたま同じメソッド名と同じ方の引数であってもどのインタフェース名を実装している型はどうかで区別できる
つまりインタフェース抽象型はたまたま同じを確実に排除できる
2026/09/25(金) 15:16:55.58ID:7GEWmO3W
話は簡単だよ
抽象型を用いずに関数を書くと各々の型ごとに別々の関数を書かなきゃいけない
手間もかかるしほぼ同じ関数が何度も出てきて可読性も悪いし保守性も悪い
よーするに抽象型を使った関数は良いコード
2026/09/25(金) 15:24:32.24ID:y3X2IqCa
>>12
それは名前的型システムと構造的型システムの違いの話であって、インターフェイス抽象型という概念はそのいずれとも結び付くのだから、最後の「インターフェイス抽象型は……できる」というのは論旨がつながらないと思うけど。
名前的型付けによるインターフェイス抽象型は……ということだよね。
2026/09/25(金) 15:47:43.22ID:re2WXZGd
>>11
なるほど、ソースレベルの呼び出し方がデータ非依存であるとを
ある分野では「抽象」と呼ぶことにしたってわけか
2026/09/25(金) 16:26:19.05ID:Dh2BjwsM
抽象型(abstract type)とはプログラミングの型システムのうち、名前的型システムにおける型の一種であり、直接インスタンス化することができないという特徴を持つ。
対義語は具象型または具体型(concrete type)であり、具象型はインスタンス化することができる。

抽象型は実装を提供しないか、あるいは不完全な実装を提供する。
具体的な形態や仕様はプログラミング言語ごとに異なるが、いくつかの言語において、実装を持たない抽象型はインタフェースやプロトコルヤトレイト等と呼ばれている。

クラスを持つプログラミング言語では、抽象型は抽象クラスとして実装される場合があり、具象型は具象クラスとして実装される。
ただし抽象クラスはインスタンス用の変数を持つことができる場合があり、それを持たないインターフェイス等と比べると別の機能が付加されている。
2026/09/25(金) 16:59:04.15ID:y3X2IqCa
抽象型という概念が、名前的型システムとしか結び付かないということは別にないと思うんだが……。
2026/09/25(金) 17:12:39.50ID:bJ1E9BNt
構造的型システムは問題点が山積みだかららしい
構造が同じだと同一視するから事故が起きまくり
例えばこんな例もあるようだ

https://scrapbox.io/nishio/%E5%90%8D%E5%89%8D%E7%9A%84%E5%9E%8B%E3%81%A8%E6%A7%8B%E9%80%A0%E7%9A%84%E5%9E%8B%E3%81%AE%E5%8B%98%E9%81%95%E3%81%84%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A9%B1
2026/09/25(金) 17:41:09.60ID:H+jZbV0f
>>18
それはGoだと発生しないね
2026/09/25(金) 18:11:54.83ID:Jn2tRD0t
>>19
どのような仕組みで防いでいるの?
21デフォルトの名無しさん
垢版 |
2026/09/25(金) 18:52:21.84ID:DP8L+qwL
>>19
Javaでも起きないよ(小声
22デフォルトの名無しさん
垢版 |
2026/09/25(金) 20:22:56.67ID:DolTsCFZ
>>18
OCamlだと名前的型と構造的型の使い分けができるみたい。
23デフォルトの名無しさん
垢版 |
2026/09/25(金) 21:14:30.62ID:r8ffWfv+
多重継承は?
2026/09/25(金) 21:22:17.71ID:k/tTX8EV
静的型付けがなぜ重視されるのか?
それは型が異なるものが間違って使われることを100%防げるため
人間はミスや混乱するものだからコンパイル時点で100%防げることは大きい

名前的インターフェイスによる抽象型の型付けも同様
その名前のインターフェイスが実装されている型だけを受け入れる
間違いを100%防ぐことができる

一方で構造的な場合はどうか?
100%防ぐことは絶対にできない
25デフォルトの名無しさん
垢版 |
2026/09/25(金) 21:47:20.00ID:DP8L+qwL
>>24
実装するインターフェイスを間違える可能性だってあるでしょうが!!
2026/09/25(金) 22:15:25.30ID:/pRvmlos
インターフェイス毎に別の名前が付いてるから大丈夫やろ
インターフェイス毎に実装すべきメソッド一覧も異なるからそこでも気付く
27デフォルトの名無しさん
垢版 |
2026/09/25(金) 22:51:22.35ID:DP8L+qwL
そんなガバガバな理由で100%防げるなら関数名や変数名で構造的型付けの問題も100%防げるんちゃう?
2026/09/25(金) 23:18:11.64ID:jN1iKnwt
構造的型付けは利用する複数のライブラリと自作の間で入り乱れたら詰むよな
インターフェースに名前があれば万が一でも別名指定もできるから確実に安心だ
2026/09/25(金) 23:21:53.97ID:YdShWX+l
ガバガバおじさんw
2026/09/25(金) 23:56:08.55ID:1Z1witsl
>>28
ガバおじさんは構造的型付けの場合はインターフェースに名前が無いと思ってるのか
脳内設定がガバガバだな
2026/09/26(土) 00:06:52.80ID:GiN3WV5L
>>30
C++やTypeScriptは名前なしでも構造が一致すれば使えるぞ
2026/09/26(土) 00:28:34.21ID:hH8wyUky
>>30
構造的型付けはインターフェース宣言が不要で名前無くても大丈夫だよ
名前的型付けは名前を持つインターフェース宣言が必要だけどね
2026/09/26(土) 00:37:34.99ID:eketQAju
Pythonは名前的型システムをベースにしつつ、特定の属性を持つことを「◯◯プロトコル」と呼んで構造的型システムの要素を加味していたりするし、両者の組み合わせというアプローチもあると思うな。
2026/09/26(土) 04:18:52.46ID:QMw9T6l2
抽象型には名前があるべきだ
名前があると可読性が格段に良くなりコンパイラによるエラーもわかりやすくなる
名前のない構造的な抽象型はデメリットが多すぎる
2026/09/26(土) 09:20:43.98ID:hp4h2mNt
名前のない抽象型ってどんなの?
見たことないんだけどどんなコードのこと?
36デフォルトの名無しさん
垢版 |
2026/09/26(土) 09:25:49.44ID:7QoscKFO
ケースバイケースで判断したらええ
どちらでも良いことをこちらじゃないとダメだと
思い込むのはアスペ仕草でしかないぞ
2026/09/26(土) 09:56:18.66ID:RhIbEw/H
たとえばPythonでは__next__属性と__iter__属性を持つオブジェクトはイテレーターとされるけど、構造的型付けの一種とみて良いんじゃない? iteratorプロトコルと称されるけど、iteratorという名前をコード上に書くわけではない。
名前的型システム+継承によるサブタイピング多相だけで全てを賄おうとすると継承ツリーが巨大になって管理困難になるということで、いろいろなアプローチが試みられているところだと思うけど。
2026/09/26(土) 10:48:28.81ID:FcRls3mc
>>34さんはダックタイピング、ジェネリックプログラミング/テンプレートプログラミングに対してどこか独特な善し悪しの境界線を持っていそうだね
2026/09/26(土) 11:02:26.73ID:hp4h2mNt
>>37
それはduck typingだね
duck typingをstructural typingの一種と見て良いんじゃないかということだけど区別したほうがいいんじゃない?
特にこういう議論においては
2026/09/26(土) 11:43:19.70ID:YrlTBNaA
>>37
継承ツリーが巨大になる??
それはクラス継承だけでやろうとするバッドパターンでしょ
インターフェースを使いましょう
2026/09/26(土) 12:11:27.38ID:aDxlc5/o
>>39
構造的型付けという概念は、静的型付けとも動的型付けとも結び付く概念だから、ダックタイピングを構造的型付けの1種とみなすことに問題があるとは思わないが。
ま、37は>>35に対する1つの考え方として提示したものだから、35自身がたとえば静的型付けしか念頭に置いてなかったということであれば、その期待に沿うものでなかったということなんだろうけど。

>>40
インターフェイスも継承によるサブタイピング多相に他ならない。継承ツリーが大きくなるというのは、たとえばPythonで現在◯◯プロトコルとして実現されているところを全て明示的な抽象基底クラスの継承を必要とするようにすることもできなくはないけれども、そうするとその分、プロトコル的アプローチでは必要とされない継承が増えてしまうということね。むろん得失はあるから、プロトコルのような構造的型付け的なアプローチの方が優れているというわけでは必ずしもないけれども、抽象クラスなりインターフェイスなりから継承してサブタイピング多相をやっておけば万事解決というほど簡単なことではなさそうだという認識がある程度共有されているからこそ、現在、構造的型付けのようなアプローチが模索されているということだと思うよ。
2026/09/26(土) 12:22:15.08ID:WpxzvFPy
>>41
インターフェースは継承ツリーを招きません
ツリーになるのは実装継承のクラスだけ
巨大な継承ツリーはクラス継承によってのみ構成されます
2026/09/26(土) 12:45:18.77ID:aDxlc5/o
Java等でいうインターフェイスの実装というのは、C++でいう抽象クラスからの継承に概ね相当する概念であって、インターフェイスは継承ツリーを作らないというのは単なるレトリックでしょ。C++で継承といっていたものを、用語上「継承」と「(インターフェイスの)実装」等に分けただけ。
本質的なのは、サブタイピング多相を実現するのに明示的なクラス名(インターフェイス名)の指定を必要とするという点なんだけど。
2026/09/26(土) 12:53:08.95ID:NqaKT3Js
>>43
それあんた逆だよ
C++はインターフェースがない不完全な言語だから抽象クラスで代用して禁断の多重継承を許している
Javaはインターフェースがある正しい言語だから多重継承は禁止されていてインターフェースをいくつでも好きなだけ実装できる
45デフォルトの名無しさん
垢版 |
2026/09/26(土) 13:10:49.97ID:cJdAZEFI
>>44
時系列的におかしいような。
2026/09/26(土) 13:14:02.37ID:NqaKT3Js
>>45
時系列的に合ってるよ
C++(インターフェースのない不完全な言語)→Java(インターフェース登場)の順
47デフォルトの名無しさん
垢版 |
2026/09/26(土) 13:14:02.91ID:7QoscKFO
Javaのようなinterface方式はクラスを修正してinterfaceを実装しないといけないから修正不可能なクラスの共通処理を実装できないのがネックだな
2026/09/26(土) 13:23:51.97ID:NqaKT3Js
>>47
それはJavaが不完全なインターフェースの実装指定言語だからだよ
インターフェースの実装を分離したその後の言語ではその問題は起きない
49デフォルトの名無しさん
垢版 |
2026/09/26(土) 13:24:48.01ID:7QoscKFO
>>48
たとえばどういうのよ?
2026/09/26(土) 14:28:05.74ID:cJdAZEFI
>>46
Modula-3のinterfaceがあって、c++ではhpp/cppと純粋仮想関数によってのちのjava系interfaceの
ようなことはできている。
javaは多重継承を禁止する必要性から、c++で可能だった機能をinterfaceキーワードにまとめた。
このへんは、大きなクラスをつくれないようにする分出公理のやりかたに似ている(個人的感想です)。
c++の時点では、不完全というより、精錬されていないという感じ。
2026/09/26(土) 14:46:21.41ID:cJdAZEFI
公理的プログラミング言語を考えると、そのひとつとしてクライスリトリプルであること。
モナド系であれば、純粋モナドである必要はないがモナド則に反しないこと。
これは圏論的プログラミングであり、オブジェクト指向のメッセージングを「射」と考えれば、
オブジェクト指向プログラミング=圏論的プログラミングだ。
2026/09/26(土) 14:50:49.93ID:RO16A3on
>>50
多重継承は問題点が多すぎるため、クラス継承は一つに限る、つまり多重継承禁止がスタンダードになった
親クラスとその子クラスは『1対多』になる

インターフェースは対極的な位置付けで、各機能毎にインターフェースをいくつも実装する
インターフェースとそれを実装するクラスは『多対多』
ある1つのクラスから見ると『多対1』になる
2026/09/26(土) 15:00:14.63ID:ejaIPLOy
>>41
型同士の互換性を型の構造から判断する型システムが構造的型付け

`def foo(x: Sequence) -> Sequence`という関数を`foo(a)`で呼び出した時
aがSequenceと互換性があるかどうかをSequenceとaの型の構造から判断するのが構造的型付け
ダックタイピングはそういう判断自体をやってない

特に動的か静的かをイメージしてたわけではなく
>>34の書きぶりから匿名抽象型みたいなものがある言語の例を期待してた
2026/09/26(土) 15:06:24.48ID:ejaIPLOy
複おじはいつも原因と結果がごちゃ混ぜなんだよな
巨大な継承ツリーを作らないように設計してるから巨大な継承ツリーにならないというだけで
クラスだからとかインターフェースだからという話じゃ全然ない

Pythonはクラスの多重継承をサポートしてるわけだけど
クラスを使っても巨大な継承ツリーを作らないように設計すれば巨大な継承ツリーにならない
当たり前だな
2026/09/26(土) 15:29:24.47ID:kJvzFJBM
>>53
名前のない匿名な抽象型の例としてはC++かな
例えば以下のコードは構造的にobject.size()を使っていることで型付けされて
型パラメータTは構造的に無名な抽象型になる

template<class T> void print_size(T object) {
cout << "size: " << object.size() << endl;
}

その構造的に無名な抽象型を満たす任意の具象型で使うことができる

int main() {
std::string s = "abcde";
print_size(s); // size: 5

std::vector<int> v = {100, 200, 300};
print_size(v); // size: 3
}

もちろん名前がないために
多数の構造やその多段など複雑に込み入ってくると可読性が悪すぎたりコンパイルエラーがわかりにくい問題点も多いけどね
2026/09/26(土) 16:46:58.54ID:zBN8CwfD
>>53
「ダックタイピングはそういう判断自体をやっていない」と言えるかどうかは型付け・型検査の概念の広狭に依存する。
型付け・型検査の概念を狭く解釈すればそのようにいうことができるけど、一般に「ダックタイピングは構造的型付けの一種である」と言われるとき、ダックタイピングで想定された特定の属性をレシーバーのオブジェクトが持っているか否かは、型付け・型検査の一部として観念できる。
2026/09/26(土) 22:22:51.92ID:n2TWK14F
>>55
それもダックタイピングだね
抽象型がプログラム上に型としては現れない
脳内にのみ存在するイマジナリー型なので匿名型とは違う

ちなみにそれをconceptで型制約する形にすれば
ダックタイピングじゃなく構造的型付けになる
2026/09/26(土) 22:32:39.52ID:n2TWK14F
>>56
Sequenceの必須メソッドは__len__と__getitem__なんだけど
`def foo(x: Sequence) -> Sequence`の中身が例えば`return [x[1], x[2]]`だったとしたら使われるのは__getitem__だけ
__getitem__呼び出し時にそのメソッドがあるかないかは判定はしてるがxの型がSequenceと互換性があるかどうかは判定していない
これがダックタイピング
2026/09/26(土) 23:01:58.09ID:BLRxOKC2
>>57
そのC++の構造的静的型付けをダックタイピングと呼ぶのはやめよう
それは正しくない
60デフォルトの名無しさん
垢版 |
2026/09/27(日) 08:39:38.65ID:WX540RHH
静的ダックタイピングと呼んだらええやん頭高市かよ
61デフォルトの名無しさん
垢版 |
2026/09/27(日) 08:42:16.05ID:kDXIIKaK
>>60
プログラマーって右翼多すぎる界隈じゃん昔から
論理的な思考、演繹的な解法ができない人が多いというか
2026/09/27(日) 09:38:40.25ID:kHe+LiQv
動的な構造的型付け=動的なダックタイピング
静的な構造的型付け=静的なダックタイピング
2026/09/27(日) 11:34:18.90ID:dEQoTM0i
>>58
言わんとするところは理解できるんだけど、プロトコルを基礎づける特殊メソッド全ての存在チェックがないから構造的型付けではないという理由で線を引くのであれば、
たとえば、そのコードでfooの中に__len__を参照するコードもあった場合とか、プロトコルを基礎づける特殊メソッドが単一の場合とかなら構造的型付けになるのかという話になる。
仮にそれらの場合もダックタイピングではあるが構造的型付けではないと整理するなら、それは結局、型付け・型検査がそのようにされるべきだという主張ということになる。
構造的な型の方の粒度をプロトコルより狭く設定する(たとえば、SupportsGetitemみたいな感じで)という構成も可能だろうし、あまり本質的な線引きにはなっていないように思うかな。
「動的型付けは型付けではない」という考え方自体は昔も今も非常に有力にあるし、結局、そういう言う考え方なんだろうなと思うけど。
2026/09/27(日) 12:37:50.98ID:QBKAmbSb
>>63
そういう線引きをしてるんじゃなくて型レベルのチェックはしてないよって話

線引きはシグニチャで要求される型と渡された値の型が互換性があるかどうかを型のレベルでチェックしてるかどうか
let x: Sequence = y; としたときにyの値の型がSequence型と互換性があるかどうかを型レベルでチェックしてるかどうか
そのチェックが構造的なら構造的型付けという線引き
2026/09/27(日) 12:49:34.68ID:QBKAmbSb
匿名抽象型の話だけどOCamlはそれっぽい表現ができるみたいだね

let use_object
(x : < print : unit -> unit;
name : string;
reset : int -> unit >) =
print_endline x#name;
x#print ();

xは指定されたprint, name, resetメソッドを持つ必要がある
resetは実際使われてないが持ってないとコンパイルエラー
2026/09/27(日) 13:23:57.86ID:dEQoTM0i
>>58 を >>64 のつもりで書いていることは分かっているし、その上でそこでいう線引きの基準(64でいう「型レベルのチェック」)は、
型付け・型検査の概念や型の粒度をどう設定するかに依存する相対的な概念だよねっていうことで>>63のように書いたんだが、あんまり伝わらなかったか。
ただ、Pythonのように名前的型システムをベースにしている言語におけるプロトコルを構造的型付けの1種として見ることができるのではないかという
題材というか話の切り口じたいがあまり良くなかったのかもなというのは反省。
2026/09/27(日) 14:02:33.03ID:bt0wIF5T
オブジェクト指向って解析しずらいから嫌い。
2026/09/27(日) 14:57:38.19ID:+Ffvm/aN
名前的と構造的の境界はどこにあるんだろうな
>>55のC++と>>65のOCamlを比べると
どちらも制限された型しか受け付けない抽象型だけど
型に直接の公開名はついていない
しかしC++の方は関数内のコードの構造を見るまでは型が制限されないのに対して
OCamlの方は先に関数の入り口の構造と指定で制限される
しかも関数内のコードの構造よりも強く制限された抽象型になってる
内部構造と無関係なresetの制約を受ける理由はresetという『名前』で指定しているためと解釈することもできる
2026/09/27(日) 17:56:09.43ID:sBAI0lnu
>>68
ダックタイピングと構造的型付けの境界だよね?

C++がコンパイル時に匿名抽象型的なものを内部的に作ってその型と渡された値の型の互換性をチェックしていたのならシグニチャには明記されないが構造的型付けと言うことはできたかもしれない
でも実際はそんなことはしてなくて渡された値の型でとりあえずテンプレートをインスタンス化してインスタンス化されたコードのコンパイルをしてみてメソッドが呼べなければエラーになるだけ

コンセプトを使えばインスタンス化される前に型レベルの互換性チェックが構造ベースで行われる
2026/09/27(日) 18:50:36.68ID:3YN1+PMa
>>69
一段ズレてるぞ
こうだ
コンセプトなし=構造的型付け
コンセプトあり=名前的型付け
71デフォルトの名無しさん
垢版 |
2026/09/27(日) 18:55:34.81ID:WX540RHH
>>67
オブジェクト指向でリファクタしたらええやん
72デフォルトの名無しさん
垢版 |
2026/09/27(日) 18:58:06.60ID:WX540RHH
Aの複雑さとBの複雑さを
同じ箇所にごちゃごちゃ書いたらわかりにくいだろ
オブジェクト指向ではAの複雑さをAの中に閉じ込める
Bの複雑さをBの中に閉じ込めるということをやって
複雑さをコントロールするんだよ
73デフォルトの名無しさん
垢版 |
2026/09/27(日) 18:58:45.76ID:WX540RHH
Aを修正したいときはAだけに集中してBは気にしなくて良いというのが理想
2026/09/27(日) 19:09:12.46ID:OVTBWj+n
>>69
構造的型付けを理解してなさすぎ
構造的とは実行コードだけ見て逆算で抽象型が決まるの

一方でそこで使われる役目のコンセプトはRustだとトレイトつまりJavaのインターフェースに近いポジション
コンセプトによる名前的型付けになる
これらは実行コードを見なくても先に抽象型が決まるの
2026/09/27(日) 22:15:08.26ID:XillenML
>>74
あー、nominalとstructuralの違いからして理解してなかったのか
そりゃ話が全く通じないはずだわ
76デフォルトの名無しさん
垢版 |
2026/09/27(日) 22:25:00.19ID:6uVL41yj
nominalは何らか型を制約する名称を用いて型付けされる。プログラムの構造が合致してなければコンパイルエラー。
structuralはプログラムの構造から型付けされる。名称はない。
2026/09/28(月) 00:25:48.20ID:Eld1IIYL
名前的型付けと構造的型付けの対比は静的型付けと動的型付けの対比とは独立した話だから、名前的型付けと構造的型付けの対比の文脈のはずなのにコンパイルとかコンパイラという言葉が出てきて、それで両者の違いを説明しようとするのは、それだけで一般的な説明としてはアウトだと思うわ。
2026/09/28(月) 01:38:54.80ID:bHv5uw6l
静的にエラーと言うべきだよな
79デフォルトの名無しさん
垢版 |
2026/09/28(月) 09:30:04.77ID:r6hSjsTa
細かい規約とかはどうでもいいが最低限変数、オブジェクトの型を用途別に区別が付くようにしろ。連想配列にしても使える候補を限定して定義し、コンパイル時にタイポチェックできるようにしろ。
何でもintかvoid*にしとけばOKだったCのオブジェクト指向とかは御免だ。
2026/09/28(月) 09:56:16.04ID:HvQM2P3m
用途別というのをどれくらいの細かさのレベルで捉えるのか、ドメイン固有の仕様をできるだけ型システムに取り込んで型で表現できるようにするのを良しとするか、そうしないのかっていうのは結構考え方が分かれるところじゃない? 
AdressとかPhoneNumberみたいな型をstringとは区別して定義して、型で仕様を表現するという考え方は本とかではしばしば見る。逆に関数型言語(の一部?)ではデータ型の種類は増やさず汎用的な関数でいろいろやるのが好まれるという主張も見る。どちらの方向性が良いのか、個人的な定見はないんだけど。
2026/09/28(月) 11:00:45.82ID:GprJgIHJ
関数の引数として受け取る場合

名前的型付け
・関数のシグネチャを見れば型がわかる/確定する
・関数内のコードを解読する必要がなく型がわかる/確定する
・そのため関数の開発者にも利用者にも理解がしやすい
・関数内のコードを解読して食い違いがあれば関数単体で実行前にエラーを出すことができる
・そのため開発時も保守更新時も効率がいい

機能的型付け
・関数のシグネチャで何も指定がない
・そのため関数の開発者はお手軽に使いやすい
・利用者にはわかりにくい
・関数内のコードを解読すれば型がわかる/確定する
・そのため関数を利用する側の各コードと突き合わせれば実行前にエラーを出せる可能性がある
・関数単体ではエラーは出ない

ここで「型がわかる/確定する」とは「具象型」または「特定の操作(群)が可能な抽象型」であることがわかる/確定するという意味である
名前的型付けの場合でもその抽象型に名前が付いているとは限らない
例えばインターフェースAとインターフェースBの両方を満たす抽象型はそれ自体の名前を持たないが抽象型としては確定する
2026/09/28(月) 11:04:15.98ID:GprJgIHJ
>>81
スマソ
肝心なところをミス
「名前的型付け」と「構造的型付け」です
2026/09/28(月) 12:18:20.77ID:4RLp7A79
型の識別をする際、名前的型付けは型の名前を基準とし、構造的片付けは型の構造を基準とする。部分型関係を定義するのに、名前的型付けは明示的な宣言(クラスやインターフェイスの継承など)を必要とするのに対し、構造的型付けは構造の包含関係等で判定できるので必ずしも明示的な宣言を必要としない……というのが基本的な違いだと思うけど。

構造的型付けだからといって型に名前を付けられないわけじゃないから、関数等の引数の型は普通に指定できるでしょ。自分はTypeScriptを書かないのでその型システムをきちんと知っているわけではないけれど、TypeScriptで関数の引数の型を指定できないなんて聞いたことがないし。
「実行前に〜」云々は静的型付けのことしか想定していないから、そもそも名前的型付けと構造的型付けの比較点として持ち出すのは的外れ。
2026/09/28(月) 12:27:18.60ID:oxabeVxG
>>83
それは型に対してメソッドなどを定義あるいは実装するときの話
>>81は関数の引数として受け取るときの型付けの話
それぞれ別の話であることに注意
2026/09/28(月) 12:35:41.34ID:4RLp7A79
何を言いたいのかよく分からないんだが、関数の引数の型付けという場面なら、構造的型付けの言語(たとえば、TypeScript)では引数の型の指定ができないという主張なの?
2026/09/28(月) 12:36:16.65ID:RUh9g+VI
Pythonでもあるまいし
2026/09/28(月) 12:38:06.03ID:zKqxj9Rf
>>85
型を明示的に指定したら名前的型付け
2026/09/28(月) 12:41:30.14ID:Tw5Q7kzq
>>85
あなたの勘違いがわかった
言語によって構造的型付けや名前的型付けが定まるわけじゃないよ
型付けの使われるシーンで定まるんだよ
2026/09/28(月) 13:01:08.42ID:4RLp7A79
>>87
名前的型付けと構造的型付けという用語は、一般的には型の識別を型の名前によって行うか、型の構造によって行うかを指す用語として使われており、型に名前を付けているか否かを指す語ではないはずだけど。
というか、用語・概念の最初の定義の時点で一般的な理解から外れているのってどうなの……。

>>88
場面に応じて、名前的型付けと構造的型付けとが併用されることがあることは別に否定しないけれど、TypeScriptにおける関数等の引数の型は、基本的には構造的型付けで判定されるはずだよ(細かい仕様としてはいろいろあるみたいだけど)。少なくとも、関数等の引数の型を指定した場合に、そのことによって名前的型付けになるということはない。
2026/09/28(月) 13:09:16.46ID:pNGkEIwI
>>55のC++の例は引数を束縛する名前がなく構造的型付けで静的ダックタイピングだけど
conceptを定義してその名前で束縛してやると名前的型付けになる

template <typename T>
concept HasSize = requires(T a) {
{ a.size() } -> std::convertible_to<std::size_t>;
};

void print_size(const HasSize auto& object) {
cout << "size: " << object.size() << endl;
}
2026/09/28(月) 13:18:40.06ID:95RywFaz
>>89
interface名を使う時点で型は確定するため名前的型付けだよ
一方でその名前的型付けされた型に値が構造的にマッチングできるというだけ
2026/09/28(月) 13:20:19.76ID:RUh9g+VI
C++のテンプレートみたいなのはどうなん?
2026/09/28(月) 13:43:22.57ID:4RLp7A79
>>90
コンセプトはそもそも制約条件の記述であって、型じゃないでしょ。

>>91
オレオレ定義で押し通そうとするのは何なん。検索するなり、AIに聞くなりして「名前的型付け」「構造的型付け」の意味を確認するところから始めた方が良いと思うが。
たとえば、関数の引数がインターフェイスA型のオブジェクトを受け取るシグネチャになっているとき、名前的型付けであれば、Aと同じ構造を持つが名前が異なるインターフェイスB型のオブジェクトは引数として渡せないことになるが、TypeScriptはそういう仕様になっている? それともオレオレ定義の名前的型付けでは、そういう名前の異なる型同士の間でも同一性・互換性を認めるってするの?
2026/09/28(月) 13:44:16.08ID:ryNukvdc
似てるようで別なこと

型推論
不明な型の変数がその後の使われ方で逆伝播して具象型が定まること

構造的型付け
不明な型の変数がその後の使われ方の構造によって制限されて抽象型が定まること

構造的マッチング
既に型が定まってる変数に対してその型と同じ構造のデータがマッチングないし代入されること
95デフォルトの名無しさん
垢版 |
2026/09/28(月) 14:22:27.24ID:l/ctBmDQ
構造的型付けとダックタイピングはWikipediaの型システムの解説が良く整理されていると思うけど、これをベースに考えればいいんじゃない?
https://ja.wikipedia.org/wiki/%E5%9E%8B%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0

オレオレ定義を使うなら、Wikipediaとの差分と、Wikipediaと違う定義にする理由くらいは明示してほしいところ。
2026/09/28(月) 14:40:40.53ID:n9ZOKaKy
>>93
コンセプトによって型が制約されて抽象型が生じる
インターフェースによって型が制約されて抽象型が生じるのと同じ
2026/09/28(月) 15:00:09.45ID:Rqiydlvp
>>90
print_sizeの引数として渡されたobjectの型が明示的にHasSizeを実装してると宣言してある場合だけ互換性がある型として扱われるのならnominal typing
実際はobjectの型が構造的にHasSizeを満たしていれば互換性がある型として扱われるのでそれはstructural typing
2026/09/28(月) 15:06:02.29ID:v+4ryWt8
>>92
C++20からのconceptが使われない限り
C++のテンプレートは構造的型付けであり静的ダックタイピングとも言われるとどの記事やサイトの説明にも書かれてるね
ところがTypeScriptの意味での構造的型付けとはまるで異なるようにみえる
例えば>>55はC++テンプレートの構造的型付けの典型的な事例だけどstring型とvector型が同じ型として扱われてるよ
2026/09/28(月) 15:48:54.81ID:4RLp7A79
C++のテンプレートは構造的型付けであると断言するものより、構造的型付け「に近い」とか構造的型付け「的」とか、ちょっと留保の余地を残した書き振りの説明の方が多くない?
名前的型付けと構造的型付けの対比は主にサブタイピング多相の文脈でクローズアップされるのに対し、テンプレートはパラメトリック多相の系譜だからちょっと区別されているのかなという印象だけど。
stringとvectorは同じ型とされているわけじゃないけど、sizeを持つという点で同じ構造を持っており、それによりprint_sizeとの関係では互換的に使うことが認められる。その意味で構造的型付け「的」ではあるけれども部分型関係があるわけじゃないから、名前的型付けと構造的型付けの対比として典型的に持ち出される場面とはちょっと違う……ということだと思うけど。
2026/09/28(月) 15:56:55.52ID:0CghAh2a
>>54
クラスとインターフェースはツリーと言っても向きが真逆だよ
ツリーと言うからには多重継承を許す極一部の言語を除く場合だろうけどその時
クラス継承のツリーは下方向に多数になり得る
一方でクラスから見てインターフェースは上で上方向が多数になり得る
101デフォルトの名無しさん
垢版 |
2026/09/28(月) 16:37:41.18ID:1uMJeQMq
いうほど真逆か?
2026/09/28(月) 16:48:24.28ID:BGoMxURs
>>100
構造的型付けを勘違いしていたことを自覚したので他の話題に切り替えたい模様
2026/09/28(月) 16:48:50.32ID:Q3Hh51qJ
継承の向きを揃えると逆だね
多対1 多数のインターフェイス→自分
1対多 自分→多数のサブクラス
2026/09/28(月) 16:52:08.39ID:YePwWPQV
>>99は反省してるようだからイジメてやるなよ
2026/09/28(月) 18:58:55.92ID:SXsOChla
>>83
実行前に分かるかどうかは一番重要なことだろ
開発したことないんか?
2026/09/28(月) 19:15:58.44ID:4RLp7A79
>>105
実行前に分かるかどうかが重要であるとかないとかいう話ではなく、名前的型付けと構造的型付けの違いにはならないと言っている。
>>95で紹介されているWikipedia辺りにちょっと目を通すだけでも、>>81が一般的な理解とかけ離れたことを書いているということは分かりそうなものだが。
2026/09/28(月) 19:20:18.74ID:6QPWoNxk
>>106
実行前に分かるか分からないかで2つに分かれてるなら致命的な違いに見える
2026/09/28(月) 20:35:55.08ID:4RLp7A79
「分かれてるなら〜」じゃなくて自分で調べたら?
名前的型付けと構造的型付けの対比は、静的型付けと動的型付けの対比とは独立している。したがって、名前的型付け・構造的型付けのいずれであるにせよ、静的型付けと動的型付けのいずれとも結び付き得る。
たとえばPythonは、(プロトコルなどはあるものの)名前的型付けが基本の動的型付け言語、TypeScriptは構造的型付けが基本の静的型付け言語。>>81がどれだけナンセンスなことを書いているのか、いい加減に理解してよ。
109デフォルトの名無しさん
垢版 |
2026/09/28(月) 20:59:40.77ID:uWV6IayP
>>107
さっき上げたwikipediaにまとまってるけど、
「名前的型付けとは、システムが保持しているプログラム要素の参照情報上の型の名前を見て、データ値の型を識別するスタイルである。
構造的型付けとは、参照情報上の型の名前を見ないで、データ値本体の分析でデータ値の型を識別するスタイルである。」

型の互換性判定で名前を見るか型の構造を見るかの違いだよ。

その結果、名前的型付けは名前同士の関係を実際に使用する前に明示する必要があって、型同士の依存関係をコーティング早期に強くする必要がある。
構造的型付けと名前的型付けの違いが効いてくるのは設計の話で、実行前か実行時かはあんまり効いてこないかと。
2026/09/28(月) 21:04:39.99ID:fhlg/LcG
>>108
Pythonはダックタイピングだから構造的型付け
2026/09/28(月) 21:13:27.25ID:jGOybPCK
>>83
TypeScriptは構造的部分型だよ
2026/09/28(月) 22:16:11.65ID:PhpUVe3q
>>108
君が相手にしてるのは複製おじさんと言って
いつも技術的に間違ったことばかりを書いて
指摘されても一切反省しない荒らし的なやつなので
まともな議論になると思ってはいけないよ
2026/09/28(月) 22:39:32.71ID:4RLp7A79
>>110
ダックタイピングが可能な範囲で一種の構造的な型(プロトコルはその一種)を観念するのは、個人的には支持したい考え方ではあるが、Pythonの言語仕様において「型」とされるのはそのような観念的な型ではなく、Pythonの型(言語仕様上の型)はあくまでも名前によって識別される。Pythonが名前的型付けを基本とする言語とされる所以。

>>111
そうだよ。部分型関係の有無を構造の包含関係等で判定できるって>>83で書いているとおりだが。

>>112
ありがとう。いつまでも付き合ってはいられないので、適当なところで切り上げます。
2026/09/28(月) 22:42:45.58ID:HLDe4fz7
構造的型付けは欠陥だらけなので採用しているプログラミング言語は片手で数えられる
ほとんどの言語は欠陥だらけの構造的型付けを採用しなかった
115デフォルトの名無しさん
垢版 |
2026/09/28(月) 23:17:01.30ID:1uMJeQMq
ハルシネーション治せる?
2026/09/29(火) 01:40:51.63ID:/y8pr6yq
構造的型付け言語でまともな開発するわけではないから特に問題はない
スクリプトとして使う分には合ってる
117デフォルトの名無しさん
垢版 |
2026/09/29(火) 07:49:54.00ID:rpd4Agfm
まともな言語なら構造的型付けと名前的型付けを併用できるだろ。
OCamlみたいに構造的部分型などを活用して設計を後回しにできるメリットは大きい。
2026/09/29(火) 09:05:53.80ID:ILQcCoh0
構造的型付けを採用しているのはTypeScriptとかGoといった比較的新しい言語だし、名前的型付けの言語でも構造的型付けの要素を追加する動きは少なくない。たとえばPythonは3.8でtyping.Protocolを追加している。

構造的型付けにはしばしば指摘されている欠点があるのでそれに対応する必要はあるものの、クラスやインターフェイスの継承といった明示的な宣言をしなくても部分型関係を作れるというのは非常に大きなメリットだと思うよ。既存の継承ツリーに手を加えられるとは限らない(仮に手を加えられたとしてもその分ツリーは大きく複雑になる)からね。個人的には『ロバストPython』に出ていた飲食店のメニューを表す継承ツリーにSplittableという要素を追加するという例が面白かった。
2026/09/29(火) 10:00:30.01ID:cCKQULA1
>>118
問題はその手を加えられない既存の継承ツリーだということに気付かなきゃ
既存の継承ツリーなんてものがあるために変な対応をしなきゃいけなくなってる
120デフォルトの名無しさん
垢版 |
2026/09/29(火) 10:12:07.14ID:Vfkc83jJ
クラス継承のツリーが癌
健全なオブジェクト指向には不要だった部分
2026/09/29(火) 10:41:44.88ID:BHNGK2GU
間違ったオブジェクト指向を教えられアンチオブジェクト指向になった人と
構造的型付けとは静的なダックタイピングだという間違った知識いまだに信じてる人と
構造的型付けと名前的片付けの区別がつかない人が
きれいに重なってるのが面白い

原因はやっぱり20年以上前から知識をアップデートできてないからだろうな
2026/09/29(火) 10:48:33.13ID:UKR2p5le
構造的型付けは型システムの安全性を失くす危険因子
安全性を重視するなら絶対に導入してはいけない
2026/09/29(火) 11:01:53.27ID:NSQyi4O1
構造的型付けを導入してしまったTypeScriptは苦しんでるよな
構造が同じなら同じ型になるのは型安全性を乱す致命的な間違いだった
そこでTypeScriptは型を区別するために隠しフィールドを増やすという本末転倒な方法を編み出した
2026/09/29(火) 12:08:51.86ID:ZiRQx0wb
構造的型付けを安全にするのは簡単だよ
①構造に名前を付ける
②同じ構造でも名前が異なるなら区別する
③各型やクラスはどの構造を持っているのか名前で宣言する
これで安全になるよ
①②③は必須だよ
2026/09/29(火) 12:11:29.61ID:vzAaEt5X
構造体もそれぞれ目的が違うんだから同じ内容に見えても別名にするだろうし、名前だって目的に沿った名前にするから当然違う名前になる
2026/09/29(火) 12:27:42.44ID:YWwtg6nn
>>125
その通りなんだけど
構造的型付けの間違いは「一部分でも同じ構造を持つなら同じ抽象的な型として扱う」ことにしたこと
2026/09/29(火) 12:29:26.17ID:vzAaEt5X
>>126
それは最悪だな、機能追加や変更がやりづらいw
2026/09/29(火) 12:35:20.45ID:CNghhHUF
構造的型付けでもその構造型に名前をつけることはよくあるけれども、型の区別を名前で行うならばそれはもはや構造的型付けではないでしょ。
構造的型付けのメリットを活かしつつ、欠点をどうフォローするかは構造的型付けを取り入れた各言語で模索中ってところじゃないの。Pythonみたいな言語で部分的に構造的型付けを取り入れているだけの分にはほぼメリットしか感じないけど、TypeScriptみたいな純粋な構造的型付け言語でどうなのかというのは、自分はTypeScript を知らないので分からないな。結構苦労するのか、それともそれなりに対処法が確立されているので実際的にはさほど問題にならないのか。
2026/09/29(火) 12:40:43.77ID:tY+uLrS/
>>126
その「一部分でも同じ構造を持つなら同じ抽象的な型として扱う」は>>124の①②③を満たせば型安全にすることができる
だから本質的な問題は①②③を満たせているかどうか
2026/09/29(火) 12:43:03.74ID:vzAaEt5X
プリミティブなレベルでの構造的型付けならいいが
そんなものは言語ライブラリレベルでしか成立しなくて
アプリ階層の構造なんてそれこそ流動的で開発終了した後でさえ変更が入るってのにw
2026/09/29(火) 12:48:16.40ID:qMOOoGYG
>>128
TypeScriptでは構造的型付けの問題点を解決するために安全なプログラムでは名前で区別するようになったよ
ブランディングと呼ばれる手法が用いられていて構造に名前を入れることを必須にしてその名前によって構造を区別してるよ

interface UserId {
__brand: "UserId";
id: number;
}

interface ProductId {
__brand: "ProductId";
id: number;
}
132デフォルトの名無しさん
垢版 |
2026/09/29(火) 12:59:09.82ID:ykmES0Hv
構造的型付けは欠陥品であることが明白になった
2026/09/29(火) 13:02:40.21ID:CNghhHUF
同じ構造でも名前が違うなら区別する(②)というときの「名前」が型の名前ならそれは構造的型付けではないし、型安全性みたいな用語をふわっと使うのもどうかと思うけど……。

>>131
型の識別のためだけのダミーな属性を入れるということなので、構造的型付けの理念からは一歩後退ということになるんだろうけど、少なくとも構造的型付けオンリーでやるのはちょっと厳しいというのは共通認識になっているということなんだろうね。
134デフォルトの名無しさん
垢版 |
2026/09/29(火) 13:05:35.23ID:hV2YmEQE
バカの論理やめえやw
それはうなぎの血をがぶ飲みしたら体を壊すからうなぎは体に悪いと言ってるようなものだろうがバカがw
2026/09/29(火) 13:06:04.65ID:vzAaEt5X
例えが意味不明
136デフォルトの名無しさん
垢版 |
2026/09/29(火) 13:14:44.89ID:hV2YmEQE
意味不明という言葉を使うやつ例外なくバカです、うなぎでバカが釣れました、リリースします
2026/09/29(火) 13:23:04.24ID:XIbqHuSI
>>131
それが①②③を満たしているか確認してみると

>>124
>①構造に名前を付ける

interface UserId と
__brand: "UserId"; で二つも名前がついてるから合格
しかし二重に名前を付けざるを得ない点は辛いところだね

>②同じ構造でも名前が異なるなら区別する

構造の中に __brand: "UserId"; という名前を持ったことで区別できるようになったので合格

>③各型やクラスはどの構造を持っているのか名前で宣言する

これは各型やクラスに __brand: "UserId"; を持つことになるのだろうから合格

①②③を満たしているね
interfaceで名前を二重に持たざるを得ない欠点があるから100点はあげられないけれど
138デフォルトの名無しさん
垢版 |
2026/09/29(火) 14:08:29.60ID:ZkEmXw6z
構造的型付けの欠陥を対処したら名前的型付けになりました草
139デフォルトの名無しさん
垢版 |
2026/09/29(火) 14:47:56.91ID:hV2YmEQE
柔軟性が失われてて大爆笑
レスを投稿する


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