文系なりにプログラミングを考えてみる#1
こんばんは,基本的に純度100%の文系眼鏡,ぜんのーです。
世の中はどうやらゴールデンウィークに突入しているとかなんとか。皆様いかがお過ごしでしょうか。
さて,わりかしどうでもいい話なんですけれど,いまさらながらにプログラミングの基本の基本について文系らしく頑張ってみようかと思った次第。主に,プログラミングに触り始めた方々のお役に立てれば幸いと筆を執ったというお話です。仕事がらプログラミング初心者にプログラムを教えることが多いのですが,その中で思ったことを,つらつら書き連ねてみようかなと。
あ,ちなみに,言語はJavaを対象にしてます。あと,構文の使い方,記述の仕方は参考書や他の多くの方がWeb上にアップしてくださっている記事を参考にしていただきたいと思っています。この記事はあくまで,納得した上でコードを書くための手助けになればと記述したものになります。
プログラミング「言語」
- プログラムはアプリを動かすためにコンピュータにしてほしい命令を伝えるための文章です。
- 要するにコンピュータに対する「お願い」を記述した文章ということ。
- 日本人は日本語で意思疎通をすることが多いけれど,コンピュータは機械語で意思疎通を行います。
- 人間が意思疎通のために使用する言語をまとめて「自然言語」と言ったりするのですが,自然言語と機械語の間にはとても大きな隔たりがあるため,人間が機械よりの言葉(プログラミング言語)で文章(コード)を書き,それを機械語に翻訳しコンピュータは動きます。
- 人間が母国語を不自由なく使用できるのはその言語を使用している期間が長く,何度も何度も繰り返して使用しているからです。反して外国語は学校で習ったとしても日常的に使用しているわけではないため,母国語より不得手なことが多いはずです。プログラミング言語も言語であるならば,学び,不慣れでも使用し,慣れていくことが必要でしょう。
「宣言」って,なんぞ?
- 多くのプログラミング言語に出てくる言葉に「宣言」というものがあります。
- 日常的に使われる宣言とは,意思や方針を他者にもわかるように表明することです。
- プログラミング言語においては,意思や方針ではなく,データの在り方を表明します
- 表明する相手はコンピュータであり,自分も含めたそのコードを読むプログラマでもあります。
- 「定義する」と脳内で変換した方がしっくりくる人もいるかもしれません
「変数」の「変」っていう字がインパクトありすぎて困る
- 「変数」とはデータを格納している入れ物です。箱と例えられることが多いものです。
- 変数は名前を付けて管理します。変数の名前は「変数名」と呼ばれます。
- 箱なので,中身を入れ替えることが可能です。「変更可能な値(数)」なので「変数」というわけです。なお,変更不可能なものは「定数」と表現されます。私たちの生活で最も一般的と思われる定数は円周率の「π」でしょう。
- Javaではデータには型という概念が存在し,変数には型を指定します。例えば整数を表す型や文字を表す型など,さまざまな種類の型が存在します。変数に型を指定して宣言し,宣言時に指定した型のデータしか入れられないようにすることがJavaにおいての変数の基本です。
- なぜそんなめんどくさいことをするのかというと,ミスをなくすためです。皆さんは,同じ容器に入ったソースと醤油をかけ間違えたことはないでしょうか。あるいは塩と砂糖でも構いません。間違えると猛烈にバッドな気分になりますよね。プログラミングでもそれは一緒なので,仕組みとして間違えることができないようにしておいたのだと考えると納得できるところはあるのではないでしょうか。
- 内部的にはメモリ領域にデータを格納する領域を確保し,その領域に一意の名前を付けて,名前によってデータにアクセスするためのものです
- 日常的にも「彼」や「お父さん」などの,「人称代名詞」や「名詞」,「目的語」を使用し,現在の文章や言葉が「何(誰)」を指すものなのかわかりやすくします。そのプログラミング言語版が変数名だと思っていただいていいのではないでしょうか。コンピュータは人間のように空気を読むなんてことをしませんので,通常会話のように何を指すかを表した言葉を省略することはできません。
- 例えば,「ぜんのー」という名前のデータがあったとします。名前のデータをメモリ領域に補完したとしても,その名前にアクセスする方法がわからなければコンピュータはどうしようもなくなります。だから,名前を付けて管理をします。
- 名前さえあればデータにアクセスできるので,変数名は名前兼住所と思っていてもいいかもしれません。
値型と参照型の必要性に思い悩む
- 少し厄介なことに,変数(データ)には値型と参照型という二つのパターンがあります。
- 値型は変数名を基に見に行った先に,データそのものが格納されています。参照型は,見るべきデータの保存場所だけが格納されているという二段構えになっています。
- Java言語では基本データ型として設定されているものは値型です。それ以外は参照型になります。
- 基本データ型は変数を宣言した時にメモリ上に確保される領域が決まっています。大きすぎるデータは確保した領域に入りきらずに困るなんてこともありますが,サイズが決まっているがゆえに,直接データを保存して大丈夫なのです。
- 参照型は,メモリ上に確保される領域が一定ではありません。けれど,変数宣言時にメモリ領域を大きめに確保しておいて,余ったら返すなんてことはできません。そのため,参照型の変数はどんなサイズのものが保存されるかわからなくても大丈夫なように,本来のデータの保存先の住所だけが保存されるようになっています。
そもそも,日本語に訳された言葉がベストなのか悩む
- ここまで見てきた中でも感じられた方はいらっしゃるかもしれませんが,専門用語の日本語訳はそれが一見してニュアンスを感じ取れるようなものではないことも多々あります。
- しかし,用語は正しく覚えて使えないと,困ります。なぜなら,その分野にかかわる人間が「共通認識」としておきたいものが用語として用意されるからです。ニュアンスとしてわかりにくいからと用語を覚えて使うことを避けてしまうと話がややこしくなったり,認識を一致させることに時間がかかったりといいことがありません。なので,わかりにくくても,「慣れる」必要があります。
- しかし,わからない言葉を使うのは難しいです。そのため,慣れるまでは自分の脳内でのみ,言葉を置き換えて納得することをお勧めします。置き換える言葉が見当たらなければ,あきらめて最初から用語を覚えてしましましょう。
「条件分岐」をどこで使えばいいかわからない
- 以前,「条件分岐でできることはわかったけど,実際にどこに使えばいいかわからない」という質問を案外の多くの方から受けたことがあります。
- 条件分岐はプログラムの処理を場合によって分岐させるために使用するものです。
- 例えば,お酒や煙草の購入は成人であることが条件です。「お車でお越しですか?(車で来ているならば駐車券の処理をします。)」って感じの文章が日常的な条件分岐です。
- で,どこで使うかなのですが,プログラムはどこに何を使うかの答えはありません。定石のようなものは存在しますが,こと,条件分岐などはどのようなプログラムを作成するか次第で使う場所が変わります。
- 日常会話だって,まったく同じ会話なんてほとんど存在しないように,プログラムも,そのコードも千差万別です。これに関しては「書きたいように書いてください」としか言いようがない気がします。結果として,うまく動いてくれればいいのです。バグを内包する危険がないかとか,読みやすいかとか,効率的かなんてことを気にするのは,いったん自力で何とか動かしてみてからでいい気がしています。
「反復処理」はまだいい。問題は「配列」とセットになった場合だ
- さて,「ループ」などとも呼ばれる反復処理ですが,繰り返して行いたい処理を書くときにとても便利です。最もシンプルなものは「1から100までの数を順番に出力するためのプログラム」といったところでしょうか。
- さて,「配列」です。こちらは複数の変数を連結したものと表現すればいいでしょうか。イメージ的には「電車」や「3個パックのヨーグルト」など,同じ種類のものを複数の箱に分けて保管するという感覚です。
- 同じ型のデータで「同じ意味合い」で使用するものはセットにしておいたほうが扱いが楽なので配列というものが存在しますが,日常的に使用している配列の概念としては「一人暮らし用のマンション」ってとこでしょうか。マンション名が配列名で,部屋番号という数字を基にその部屋(箱)の中には対応している人間が住んでいて,引っ越しに伴う代入が発生するといった感じです。プログラム上での配列は0から順番に1,2...と数字が降られていくことに注意です。この配列のどの箱に保存されているかなどを表す数値を「添え字」と言います。日常生活でも引き出しにラベルを張り付けて中に何が入っているかをわかりやすくしますよね。配列においてはこのラベルが添え字にあたります。
- 配列は反復処理,特に「for文」と相性が良いです。for文はそのループの制御にカウンターを使用します。そのカウンターの数値そのままで配列の中に格納しているデータにアクセスできるのが強みです。
メソッド関連の用語が更に謎を呼ぶ
- プログラムを学び始めてしばらくして,関数やメソッドと言われるものに触れる機会があります。長くなってきたコードを,適切に細かく分けていき,管理や保守をしやすくし,また,コードの可読性を上げる(要するに見やすくするということ)ために導入されます。
- 問題は「引数」と「戻り値」というよくわからない(と言われることが多い。特に戻り値の使い道)言葉が出てくることです。
- そもそもメソッド(関数)は一連の処理に名前を付けて切り出したものです。日常生活では「料理をする」「ブログを書く」「風呂に入る」「寝る」等でしょうか。
- 引数は「処理を行うために必要なデータ」であり,戻り値は「処理を行った際の結果」です。
- さて,「初めて恋人ができたあの頃に思いを馳せる」などというメソッドが存在するとします。この場合,処理をする際に必要なデータ(引数)は固定です。対象はその人にとって唯一の「初めての恋人」です。このため,引数を使用する必要はありません。そして,すべき処理は「思いを馳せる」なので,自分の脳内で完結します。決して外に何かを出すような処理ではありませんので戻り値も必要ありません。まあ,リアルでこの処理を行うと表情として出力があるかもしれませんが,ややこしいことになりそうなので割愛。
- さて,先ほどのメソッドが,「初めて恋人ができたあの頃にのことを語る」だった場合はどうでしょう。厳密には「初めて恋人ができたあの頃の記憶を抽出する」と「語る」の2つにメソッドは分かれます。この場合,まずは引数の必要ない「初めて恋人ができたあの頃の記憶を抽出する」メソッドを実施し,その時の記憶を戻り値として吐き出し,その記憶を変数に入れて管理します。その記憶の入った変数を基に(引数として渡し)「語る」メソッドを使用します。
- ここで命令を2つに分けたのは,我々が「語る」のは「初めて恋人ができたあの頃の思い出」以外にもたくさんあるからです。使いまわしができる処理は,どんどん細かくメソッドに分けてみましょう。
- 引数と戻り値は作る処理に必要な場合だけ利用します。例えば,「足し算」をする時を考えましょう。「1+2=3」という計算の場合,「=」の左側に存在する「1」と「2」が引数,答えの「3」が戻り値と考えるとわかりやすいのではないでしょうか。また,引数は複数指定して使うことも可能ですが,結果である戻り値は常に1個です(配列1つなどの返し方も可能)。
- この,「結果は常に1つ」というのは非常に素敵な考え方だと思います。同じ材料を渡せば常に同じ物が出来上がるということです。もう少し,日常生活にメソッド(関数)を当てはめてみましょう。
- 「炊飯器を使う(メソッド)に水と米(引数)を渡すと,炊き立てご飯(戻り値)」が返ってくるとか,「ブログを書く(メソッド)時には題材(引数)を基に記事(戻り値)が出来上がる」とか,そういうことです。私たちの行為には常に結果(戻り値)が付きまといますね。行為自体も,何らかの情報や状況(引数)を基に行為するというのは受け入れやすい考え方かと思います。
「オブジェクト指向」で挫折
- さて,一番多くの方が躓くところがこの「オブジェクト指向」です。とても膨大な内容があるので,とりあえず触りだけ。
- 「オブジェクト指向」の「指向」がまずわかりにくい。ここはざっくばらんに「全部の事をオブジェクトとして考えましょうぜ!約束ですよ。」くらいの意味合いで受け取っておけばいいのではないでしょうか。
- オブジェクトは現実世界で触れることができるすべてのものです。プログラミングの上では実際に実体化して扱えるものです。うん,よくわからないのでもうちょっと見ていきましょう。
- Javaにおけるクラスの定義とは何か。それはプログラムの中で使う「概念」の定義です。現実世界では概念の定義は非常に難しく,そのイデアを寸分の過不足なく記述することは難しいわけですが。こと,プログラミングにおいては,そのプログラムにおいて使いたい形に自分が定義してしまえばいいのです。
- 現実世界の人間の定義は非常に難しいですが,プログラミングの世界においては,「名前」というパラメータ(情報)だけがあるものを人間クラスとして定義しても間違いではありません(扱いやすいかは別ですが)。
- で,概念を定義したら,次は実体化の作業です。
- 実体化に必要なのは「それがそれとして個別に存在するためのデータ」と言っていいかもしれません。人間という概念(クラス)が定義されていて,そこから実体化されたオブジェクト(インスタンス)は,与えられた情報をもって,さまざまな個体へとなります。私は私の名前と肉体とその他多くの情報をもって私として規定されているように。
- ある1つの概念に対して,複数プログラマがクラスとして定義をした場合,寸分たがわぬ定義にならないことも多いでしょう。それは,人が自分の世界で生きているからです。変なたとえかもしれませんが,現実世界でも何を重要とし他人をどう捉えるかはその人次第です。私に対する評価は,きっと十人十色の返答が現実世界でも返ってくるでしょう。プログラムの世界でも,作るべきアプリやシステムが決まっていたとしても作り手の違いで,異なるクラス設計になることは往々にしてあります(現実世界ほどかけ離れた評価,定義になることはないと思いますが)。
- さて,なんだか話が大仰になってしましましたが。もう少し簡単な例を考えたいと思います。たい焼きについて考えます。たい焼きクラスはたい焼きの鋳型です。そこに必要な材料を入れて,実際にたい焼き(インスタンス)を作ります。
- 最近のたい焼きは,あんこが入っていたり,チョコが入っていたりと,中身(データ)はバラバラですね。クラスのインスタンスは個別に存在しているものではあるけれど,それぞれが必ずユニークな(単一の)ものではないということは大切なことかもしれません。授業では「Student」クラスなどを作って名前を付けてみたいなことをするものだから同じ物を複数作ってはいけないという先入観にとらわれてしまうのかもしれません。クラスはもっとおおらかなものなので,肩ひじ張らずに付き合っていっていただければと思います。
こうやって書いてみたものの,もっと例や図や実際のコードも入れたほうがいい気がしてきたので,余力があればそのうち編集します。皆さんのプログラミング生活の何かの足しになれば幸いです。
それでは皆様,また後日。