misc.log

日常茶飯事とお仕事と

ポリモーフィズムを新人に説明するための自分用お勉強

全くIT系の勉強をしてきていない、文系の学部卒を抱えての新人研修で、6月以降も在宅でC#の本を読んでもらうことになりました。個人的には最初は横について、Visual Studio自体の使い方なども教えながら、きめこまかに教えて、ある程度のところで独習にする方が良いと思うのですが……まだコロナウイルスの影響が抜けきらないということであれば仕方がありませんね。

で、下記の本をこちらでも読みながら、新人達がつまりそうなところや、本の説明だとちょっと物足りないところを補足していっています。

確かな力が身につくC#「超」入門 (Informatics&IDEA)

確かな力が身につくC#「超」入門 (Informatics&IDEA)

この本、基本的にコンソールアプリをメインで話を進め、GUIを使ったプログラムは全6章のうち5章以降。後半まで登場しません。そして、4章が「オブジェクト指向」と銘打たれて、クラスなどの説明をRPGのキャラクターや敵を効率的にプログラムで実現するという例を出しながら説明しています。この説明の仕方は私のやり方に非常に似ているので馴染みやすく、この本を選定した理由の1つでもあります。

その中で1つ「ポリモーフィズム」の説明がちょっと物足りなく思い、自分でも補足説明をしようとしたのですが……難しいですねこれ。実際に用語の厳密な意味を知っていなくてもプログラムは作れますが、将来的に「開発者向けのライブラリを作る」とか「実装のルールを定める」といった、上位業務に就くことを考えるとある程度の理解はして欲しいところ。まぁ今の時点で理解していなくても「そういえばあの人がなんか言っていたな」と思い出してもらえれば……とおもって説明しようとしたのですが、自分自身の理解の浅さを再認識する結果になりました。

とりあえず調べた経緯等を後々の再確認に備えてメモしておきます。

Wikipediaの説明を見てみた

Wikipediaの「ポリモーフィズム」の項を見るとこうなっています。

bit.ly

ポリモーフィズム(polymorphism、多態性)を構成する特性は下記の3つ。

  • アドホック多相性(Ad hoc polymorphism)
  • パラメーター多相性(Parametric polymorphism)
  • 部分型付け(Subtyping)

ん……んんw 難しいわこれ。部分型付けは、クラスの定義で親子関係(スーパークラスと、それを継承したサブクラスがある)という状態で、サブクラスのインスタンススーパークラスで宣言した変数に入れることができる。そして、同じスーパークラスの変数に入っているオブジェクトでも入れた物によって振る舞いが変わる、というような話。実は上記の本では「これがポリモーフィズムです」と説明されていて少し物足りなさを感じたのでした。

ただ実際、たとえば法政大学の講義資料でもそれがポリモーフィズムとして説明されてます(このページの説明はわかりやすいと思います)。

java2005.cis.k.hosei.ac.jp

ではWikipediaに載っていた他の2つは何だろう……。

アドホック多相性とは

アドホックとは「とりあえず」「その場しのぎの」といった意味で使われる言葉ですが、Wikipediaにも説明があるようにここでの用法はネガティブな意味ではなく、「後付けの」という意味合いが強いようです。データ型という仕組みが本来もっているものではなく、後付けでこういう使い方が出てきた……ということでしょうか。ちょっと上手く説明できませんが、実態はいわゆる「オーバーロード(overload)」機能。同じメソッド名でも引数の型や数が異なるものを複数定義でき、同じ名称で呼び出してもその引数構成で振る舞いが変わるというものです。

正直、オーバーロードポリモーフィズムは自分の中で結びついていなかったので、ちょっとこのあたりについての質疑などが出て無いかテラテイルで見てみたら……ありました。

teratail.com

まさにそのまんまの疑問ですね。やはり、広義と狭義で範囲が変わり、オーバーロードポリモーフィズムのひとつの実現方法かという判断はそこで変わると。

パラメーター多相性とは

こちらは、C#で言う「ジェネリクスGenerics)」が提供する機能が相当するようです。実はジェネリクス*1については使い方は判っていたのですが、C#で実際にジェネリクスを取り入れたメソッドなどを定義したことはありませんでした。また、「なんでジェネリクスという名称なの?」ということも理解できてませんでした……お恥ずかしい。

これについては、いつもの「未確認飛行 C」で非常にきっちり説明されています。

ufcpp.net

どうやったらこんな説明が書けるんだろう……すごい。要するに、引数や戻り値について型を特定せずにその「総称」として定義し、どんな型でも扱えるように作られたもの。型情報自体がパラメーターになっているというものなのですね。だから「総称」を指す「generics」と命名されている。

一応マイクロソフトDocsのURLも記載しておきましょう。

docs.microsoft.com

こちらも、メソッドやクラス名は同一でも、宣言時に指定する型によって振る舞いが変わり得るということで、ポリモーフィズムを実現する機能の1つとされているわけか……なるほど。

これを新人にどこまで説明するか

正直、ここまでの理解を新人がする必要は無いと思っています。はじめは使い方がわかって、何をどうしたらどうなるかということの実例をたくさん経験し、「なんだか判らなくても使える」というレベルからで問題ないでしょう。しかし、問題はその先です。彼らがチームを率いたり、チームで利用する共用のライブラリー的なものを設計したり、作ったりという、より上位の業務を行い始めたとき、こうした「プログラミング言語が持っている機能の意義」や「目指すところ」の理解があるかどうかでできあがるものの有用性がおおきく変わってくると私は考えます。

同じ事を実現するにもより簡単な方法をや、メンテナンス性の高い方法を選択したり、本来の用途ではない「誤用」をおおっぴらにやらかさないようにしたり。いろんなメリットがあるのですが、そういうことを知らなくても、「手間は掛かるし面倒だしコストも高いけれど」実現出来てしまうという側面もあるため、そもそもポリモーフィズムのような考え方を知らなくても、知らないことが当たり前の組織で仕事をしているとそのまま高いコストで面倒なことをやる。そして、それをそのままお客さんに金額にして請求するなんてんことがまかり通ってしまいます。

そういうお客さんと付き合っている間は問題無いかも知れませんが、いざ、新しいところに踏み出そうとしたときに、お客さん、自分たち、また、仕事に関わる他者のエンジニアの三者それぞれが「えっ!?なにそれ」と思ってお互いに失望したり、驚いたりするわけです。そして結局「この人達の仕事は効率が悪くて高い」となる。

そういう状況を回避するためには、少なくとも先輩社員はこうした裏側や言語仕様の意図について多少なりとも理解しようとする試みを行っておくべきだと思います(理解出来ずとも、難しい話があるということが分かっているだけでも多人数でかかればなんとかなるかもしれませんし)。

*1:ジェネリクス: Microsoftの資料などではジェネリック、と記載されていますが、genericは形容詞。英語では名詞形のgenericsジェネリクス)が正しい読みのようですね。