ブログバトラー
今現在コイツに夢中です。
とても夢の広がるサービスだと思います。とにかく楽しい。
こんなときは、JavaScriptの使えないはてなダイアリーがちょっとだけ悔やまれますね。
Rubyの記事書くのはサボっておいて、こんなのだけ反応してすいません……
また必ず続き書きますよ、というのを含めてブログバトラーのブックマークレット置いておきます。
ブックマークレットはid:amachangさんとこから頂いてきました。
いつもいつも、視点が素晴らしいと思います。
javascript:var d=document.createElement('div');d.innerHTML='';document.body.appendChild(d);var s=d.style;s.position="fixed";s.top="100px";s.left="100px";s.zIndex=1000;void(0);
オブジェクトとかクラスとか
いわゆるオブジェクト指向という考え方の中に登場する、基本中の基本の言葉について少し触れました。
これって用語がわかれば良いという話ではなくて、なかなか感覚を掴むまでが苦労する気がします。
オブジェクト指向感覚を得るには、『憂鬱なプログラマのためのオブジェクト指向開発講座』がとても良いです。
解説にはC++言語を使っているのですが、C++を知らなくても、むしろついでにC++を学べてしまうくらいで理解しやすい内容だと思います。
憂鬱なプログラマのためのオブジェクト指向開発講座 (DDJ Selection)
- 作者: Tucker
- 出版社/メーカー: 翔泳社
- 発売日: 1998/05/31
- メディア: 大型本
- 購入: 10人 クリック: 508回
- この商品を含むブログ (78件) を見る
リテラルの正体を暴く
演算子はメソッドの呼び出しですよ、というところからはじまって、オブジェクトやクラスの話になってしまいました。
もう一度演算子のところに戻ってみましょう。
11 + 5
たとえばこんな何の変哲も無い足し算すら、メソッドの呼び出しである、という主張でした。
今の私は、メソッドがあるからには、そこにはその『メソッドを持っているオブジェクトがある』はずだ、ということを知っています。
そうは云っても、現在『 + 』のほかの登場人物といえば『 11 』と『 5 』だけですね……
普通に考えてみたら、このどちらかが、『 + 』のメソッドを持っているはずです。
しかし、今回は同じ数値リテラルですから、どちらで考えても同じことです。結局、数値リテラルも実はオブジェクトだよ、ということになるのではないでしょうか。
オブジェクトということは、その基になるクラスが必ずあります。
それでは『 11 』や『 5 』は何というクラスのインスタンスなのでしょうか。
その正体は、『Fixnum』クラスです。
⇒Fixnum
ほんとかよ、って云われると困るので、ちょっと話が飛びますがオブジェクトのクラスを知る方法を紹介します。
例えば『 11 』のクラスが知りたければこのようにします。
puts 11.class
↓実行結果
Fixnum
このように、
<オブジェクト>.class
という形式で、そのオブジェクトが属するクラスを取得することができます(言い方を変えると、classというのはクラス名を返却するメソッドです)。
これを実行すれば、『 11 』はFixnumクラスのインスタンスである、ということが確認できると思います。
同じように、"Hello"のような文字列リテラルや、3.14のような浮動小数点数でもクラス名を確認できます。
puts "Hello".class puts 3.14.class
↓実行結果
String Float
文字列リテラルはStringクラスのインスタンスで、浮動小数点数はFloatクラスのインスタンスのようです。
これらはそれぞれ、String型・Float型というような言い方をされることもあります。
ともあれ、数値リテラルはオブジェクトで、四則演算しているときも実際は定義されているメソッドを呼び出しているんだよ、というのがなんとなくわかってきました。
ついでなので、本当にそんなメソッドが定義されているのかも見てみたいと思います。
オブジェクトの持つメソッドを知るには、たとえば次のようにします。
puts 11.methods
methodsというのは、オブジェクトの持つメソッドの一覧を返却するメソッドで、
<オブジェクト>.methods
という形式で呼び出すことができます。
実行するとずらずらっと色々表示されて、その中に『 + 』とか『 / 』とか『 class 』とか『 methods 』自身も確認できると思います。
演算子も確かにメソッドでした……ふーむ。
ゆとり教育の正体は?
そういえば前回、
puts 11 / 3
を実行したら
3
が出てくる、ということで文句を云ってみました。
これについては通りすがりさんが
11 / 3 は、整数同士の割り算だから、答えも整数。
小数点の答えをほしい場合はどちらかを小数にする必要がある。
puts( 11.0 / 3 )
ここからへんは、数値クラスについて、マニュアルにいろいろと書いてある。
とコメントで教えてくださいました。ありがとうございます。
そんなわけで早速マニュアルを見てみましょう。
⇒数値関連クラスの定義メソッド
ここまでで、数値関連のクラスではFixnumとFloatを確認しています。
Rubyにおける数値型は、実際にはNumericというクラスを頂点とした継承関係を築いているようです。
前回の問題は結局のところ、『Fixnumクラス(というかIntegerクラス)の / メソッドは、引数がIntegerであるとき、Integerの結果を返却する』ように定義されている、ということなのだと思います。
通りすがりさんがおっしゃっているように、どちらかのオペランドの型をFloatにすれば解決です。
レシーバ
ここまでなんの断りもなく書いてきましたが、一応確認しておきます。
オブジェクトのデータやメソッドを表す場合は、
オブジェクト.データ オブジェクト.メソッド
という具合に、.(ドット:ピリオド)で繋いで関係を表現します。
このとき、.の左側にあるものを“レシーバ”と呼びます。
このあたりは、リファレンスマニュアルを確認すると良さそうです。
⇒メソッド呼び出し
さらりと書いちゃってますが、意外と重要です。レシーバ。すいません。
さてさてこんな風に呼び出すメソッドですが、以前数値を10進数以外の形式で表示させた際にも、このようにしてちゃっかりメソッドを利用しました。
puts '■10進整数\n' puts 123.to_s(16) # 16進表記 puts -123.to_s(8) # 8進表記 puts 0d123.to_s(2) # 2進表記 puts '■16進整数' puts 0xffff.to_s(16) puts '■2進整数' puts 0b1011.to_s(2) puts '■8進整数' puts 0377.to_s(8) puts 0o377.to_s(8)
ここで使っているto_sメソッドは、引数で指定した基数による文字列表現に変換するメソッドです。
このような『to_なんとか』メソッドは、Rubyでは(なんとか型に)変換を行うメソッドに付けられる名前になっています。
to_sのsはString(文字列)のsなので、文字列表現に変換、という機能になるわけですね。
同じような感じで、to_f(to Float)なんていうメソッドもあって、これを使った場合だとFloatに変換できるわけです。
ということは、
puts (11 / 3).to_f
とすればいい感じの結果が!
↓
3.0
……でません。
既に計算してしまった結果に対して変換をかけているので、あたりまえですね。
なので、こんな風にします。
puts (11.to_f / 3) puts (11 / 3.to_f) puts (11.to_f / 3.to_f)
これで完璧です。要するに演算前(メソッド呼び出し前)に適切な型にしておく必要があるよ、ということです。
でもまぁ素直に浮動小数点数リテラル使えばいいと思います。
クラスとメソッド
メソッド < オブジェクト < クラス
前回演算子式を学んだ際、気になる部分を残していました。
ほとんどの演算子は特別な形式のメソッド呼び出しですが、一部のものは言語に組み込みで、再定義できません。
さて、演算子の正体は特別な形式のメソッドだと云われています。そのあたりについて突っ込んでみてみましょう。
まずは、メソッドとはそもそもなんだったでしょうか。
⇒メソッドとは 【method】 - 意味・解説 : IT用語辞典 e-Words
オブジェクト指向プログラミングにおいて、各オブジェクトが持っている自身に対する操作。オブジェクトは「データ」と「手続き」から成っているが、その「手続き」の部分に当たる。プログラミング言語によっては「メンバ関数」と呼ばれることもある。
オブジェクト指向では、オブジェクトの持つデータを操作する方法はオブジェクト自身がメソッドとして内蔵しており、これを外部から呼び出すことによって操作を行なう。こうすることにより、操作の詳細をオブジェクト内部に隠蔽することができ、プログラムの再利用性や生産性を高めやすくなると言われている。
むむ。
『オブジェクトが持っている自身に対する操作』だそうですね。
それなら“オブジェクト”とは何なのでしょうか。
⇒オブジェクトとは 【object】 - 意味・解説 : IT用語辞典 e-Words
オブジェクト指向プログラミングにおいては、ソフトウェアが扱おうとしている現実世界に存在する物理的あるいは抽象的な実体を、属性(データ)と操作(メソッド)の集合としてモデル化し、コンピュータ上に再現したもの。オブジェクトを定義するモデルはクラスと呼ばれる。クラスに基づいて実際にコンピュータのメモリ上に展開されたオブジェクトのことをインスタンス(実体)と言うが、このインスタンスの意味でオブジェクトと呼ぶ場合も多い。
くらくらしてきました。カタカナと漢字の多い解説で涙が出ます。
順番に考えてみます。
- オブジェクトとは、現実世界に存在する実体をモデル化し、コンピュータ上に再現したもの
- そのモデルはクラスと呼ばれる
- クラスに基づいて実際に展開されたオブジェクトをインスタンス(実体)と云う
- オブジェクト≒インスタンス
……という感じでしょうか。
取り敢えず“クラス”とやらも調べてみてから考えましょう……
⇒クラスとは 【class】 - 意味・解説 : IT用語辞典 e-Words
オブジェクト指向プログラミングにおいて、データとその操作手順であるメソッドをまとめたオブジェクトの雛型を定義したもの。これを定義することで、同種のオブジェクトをまとめて扱うことができるようになる。クラスに対して、具体的なデータを持つ個々のオブジェクトは「インスタンス」と呼ばれる。なお、クラスの定義を他のクラスに受け継がせることを「継承」と言う。その際、元になるクラスを「スーパークラス」(super class)、あるいは「基底クラス」「基本クラス」(base class)などと呼び、新たに定義されたクラスを「サブクラス」(subclass)、あるいは「派生クラス」(derived class)と呼ぶ。
orz
これらの説明から、なんとか糸口を見つけなければなりません。
ぼーっと眺めてみると、3つの説明文に共通する記述があることに気が付きました。
・メソッドの説明文
オブジェクトは「データ」と「手続き」から成っている
・オブジェクトの説明文
属性(データ)と操作(メソッド)の集合としてモデル化
・クラスの説明文
データとその操作手順であるメソッドをまとめたオブジェクトの雛型
……と。
言い回しは少しずつ違いますが、
- データ(属性)
- メソッド(操作)
という2点が繰り返し出てきていますので、これが重要なポイントなのではないかと思いました。
データとメソッド
そもそもプログラミングというものは、実際に存在している解決すべき問題を“プログラミング言語”によって表現し、コンピュータにその解決を依頼する行為だと云えます。
その際には、現実世界に存在する(物理的・抽象的な)モノが関わってきます。
このような“モノ”のことを、オブジェクト(インスタンス)と呼んでいるようです。
オブジェクトはクラスと呼ばれるモデルに基づいて作られる実体、でした。逆に言うと、クラスはオブジェクトの雛型です。
つまり、オブジェクトがどのような特性を持っているのかは、クラスが知っているということです。
それではクラスはどのような存在かというと、『データと、その操作手順(メソッド)をまとめて定義したもの』だという話でした。
実例で考えてみましょう。せっかくなので、以前利用した自動販売機さんに再度登場願いましょう。
自動販売機プログラム
自動販売機をシミュレートするプログラムを考えてみます。まずは、その中に登場するモノを検討します。
- 自動販売機
- お金
- 飲み物
簡単に思いつくのはこんなとこでした。
これらは実際に存在するもの(実体)ですので、オブジェクト(インスタンス)ということになりそうです。
ということは、これらを定義するクラスが必要だ、ということです。
- 自動販売機クラス
- お金クラス
- 飲み物クラス
ということで良いのでしょうか。*1
さて、クラスは「データとその操作手順(メソッド)」を持つのでした。
それでは自動販売機クラスを例にとって、データとメソッドを検討してみます。
まず簡単にわかりそうなデータは、
- 飲み物(複数)
ではないでしょうか。
自動販売機ですから、飲み物を持っててくれないと困ります。
続いて自動販売機の操作ですが、
- お金を入れる(というか入れられる?)
- ボタンを押す(押される?)
- 飲み物を出す
- お金を返す
とかこんな感じでしょうか。自動販売機の立場に立って考えるところなのかどうかわからなくて、言い回しが微妙です。
- まず、お金を入れます
- 次に、欲しい飲み物のボタンを押……
いきなり躓きました。何と見通しの甘いことでしょう。
冷静に考えてみると、ちょっと情報が少なすぎるような気がします。
- 今現在、いくら自動販売機に入れてあるのかわからない
- どの飲み物を買える状態にあるのかわからない
これでは使い勝手が悪すぎます。この二つの情報を自動販売機が管理していなければいけません。
今一度考え直してみると、自動販売機クラスが持つデータは、
- 飲み物(複数)
- 現在投入済みのお金
となります。
あれ、「どの飲み物が買えるかどうか」はデータとして持たなくて良いのでしょうか?
色々と考えてみたのですが、どの飲み物が買えるかという情報は、既に自動販売機が持っている「飲み物(複数)」と「現在投入済みのお金」から自動的に計算されるような気がしたのです。
必要であれば計算で求められるので、わざわざ計算結果を自動販売機が常に持っていなくてもよさそうです。
そのかわり、「現在買える飲み物はどれかを知らせる機能」を自動販売機に持たせてあげようと思います。
ということで自動販売機の機能(操作、メソッド)は、
- お金を入れられる
- ボタンを押される
- 飲み物を出す
- お金を返す
- 現在投入済みの金額を表示する
- 現在購入可能な飲み物を知らせる
という感じに増えました。
投入済み金額をデータとして管理することにしたので、それを表示する機能もついでに追加しています。
まとめ
- オブジェクトはデータ(属性)とメソッド(操作)を持ちます
- クラスはオブジェクト(≒インスタンス)の定義モデルです
- つまり、クラスはオブジェクトが持つべきデータとメソッドを定義します
- 属性はオブジェクトの内部情報を表します
- 操作はオブジェクトが持つ機能、処理、振る舞い、メッセージといったものを表します
結婚式を挙げました
私事もいいとこで恐縮です。日曜日に挙式してきました。
勉強どころじゃない日々でしたが、おかげさまでとても素晴らしい日になりました。
あれだけ多くの方に祝福され、多くの方に感謝する日は二度とないような気がします。
ひととおり良い思いをさせて頂いたので、いい加減気持ちを切り替えて頑張ります。
あ、あと。
はてなパーカー欲しい!
演算子・被演算子・式
算術演算
前回は数値リテラルの使い方を学びました。
せっかく数値が扱えるようになったのですから、これを利用して何かをしたいところです。
というわけで、まずは簡単に四則演算をさせてみたいと思います。
コンピュータは『計算機』といわれるくらいですから、その程度は簡単にやってもらわないと困りますね。
というわけで、ソースはこんな感じです。
puts 1 + 2 # 足し算 puts 5 - 3 # 引き算 puts 9 * 9 # 掛け算 puts 18 / 6 # 割り算
↓実行すると……
3 2 81 3
こうなります。
掛け算の記号が『*』で、割り算の記号が『/』だということくらいに気をつければ、まったく予想通りの結果だと思います。
このときに利用した[+-*/]と言った記号を、“演算子”(operator: オペレータ)と呼びます。
特に今回使用したものは四則演算を行う演算子なので、“算術演算子”などと呼ばれることがあります。
また、演算子が作用する対象を“被演算子”(operand: オペランド)と呼びます。
例えば先ほどの例のうち、
18 / 6
における演算子は『 / 』で、オペランドは『 18と6 』になります。
さらに、この場合の演算子/はオペランドを2つ持ちます。このような演算子を“二項演算子”と呼びます。
オペランドが一つの演算子は“単項演算子”、3つだったら“三項演算子”などになります。
そして、『演算子とそれに必要なオペランドが成立した状態』を“演算子式”或いは単に“式”(expression)と呼びます。
式
式について、リファレンスの解説を確認してみましょう。
⇒式
Ruby の式には、変数と定数、さまざまなリテラル、それらの 演算や代入、if や while などの制御構造、 メソッド呼び出し、クラス/メソッドの定義があります。
式は括弧によってグルーピングすることができます。
空の式 () は nil を返します。
Rubyの式には値を返す式と返さない式があります。
この説明の中で現在わかっているのは、
というあたりでしょうか。
今まで学んできた文字列リテラルや数値リテラル。
あれらはデータとしての文字列や数値を表していると同時に、Rubyの言語構造の中では“式”と呼ばれる要素として扱われている、ということのようです。
また、メソッドの呼び出し――今まで利用した例だと、printやputsですね。これもまた“式”である、という点でリテラルと同じレベルで解釈されるようです。
そして、それらの式(の単一項)は、演算子によって組み合わせることが可能らしい、ということを知りました。
ところで、式の解説の中に気になる文があります。
Rubyの式には値を返す式と返さない式があります。
値を『返す』とはどういうことなのでしょうか。
式の評価
実は、Rubyにおける“式”という存在は、それ自体が解釈(実行・処理)された後の“値”を持ちます。
これを“式の値”と呼びます。
そして、この式の値を導き出す(ために計算やメソッドの呼び出しなどをする)ことを“式の評価”“式を評価する”と言います。
これは少々特殊な言い回しのようにも感じられますが、よく使われる言葉です。
例で考えてみます。
256
これは単に256という数値リテラルです。
しかし、先ほど学んだように、リテラルもそれ自体が式となります。式であるということ、はそれを“評価できる”ということにもなります。
実際、これを式として評価した場合、256というそのままの値を得が得られます。これがこの式の“式の値”になります。
言い回しを変えてみると、「上記の式を評価すると、256という値が返される」などと言えます。
0b100000000 + 0x100
では、このような場合はどうでしょうか。
今回は数値リテラルが2つありますね。まずは、この2つの式をそれぞれ評価します。
まず左辺(この場合、左オペランドとも)は2進整数リテラルですが、これを10進数に変換します(前回やりました)。
1 × 2^(9 - 1) → 1 × 2^8 → 1 × 256 → 256
1 × 16^(3 - 1) → 1 × 16^2 → 1 × 256 → 256
これで、両辺の式の値が得られました。
そして演算子「+」は、これら両辺の式の値に対して演算を行います。
256 + 256 → 512
これが、「0b100000000 + 0x100」という演算子式の式の値になります。
さて。この式がまたもや値を持つということは、この式に対してさらなる演算が可能だということです。
つまり、
0b100000000 + 0x100 * 0o400
という演算も可能になります。
演算子の優先順位
……と終わってしまうと、実は微妙です。
確かに上の式は演算可能なのですが、「0b100000000 + 0x100」の式の値に対する演算、ではなくなっています。
実のところ、普通の計算がそうであるように、Rubyでも乗除は加減演算よりも先に評価されるというルールがあります。
リファレンスをよく確認してみましょう。
⇒演算子式
ここに、演算子の一覧が挙げられています。
この一覧は演算子の“優先順位”の高い順に掲載されているようです。
すなわち、演算子式の中に複数の演算子が登場するとき、各式はここに挙げられている順序で評価される、ということです。
これを踏まえて考え直してみると、先ほどの例で足し算を先に評価したい場合、
(0b100000000 + 0x100) * 0o400
このように優先したい式を括弧でくくって、優先順位を調整する必要があります。
残された気になる点
これで式のこともわかったし、取り敢えず算術演算はできるようになったので多少なりともプログラムらしい感じに近づきつつあります。
しかし、次のコードを試したときに少し不安になりました。
puts 11 / 3
これは割り切れない計算なので、答えは「3.66666...」のようになるはずです。
実際電卓で計算することこんな感じです。
ところが、Rubyに計算させると
3
とだけ返してきます。これはゆとり教育の賜物でしょうか。
.
.
.
また、リファレンスマニュアルの演算子式の解説に、次のような文があります。
ほとんどの演算子は特別な形式のメソッド呼び出しですが、一部のものは言語に組み込みで、再定義できません。
え、演算子はメソッド??
突然言われると何のことやら……です。突然でなくても面食らいますが。
しかも再定義できるとかできないとか。演算子の意味を変えられるとでも言うのでしょうか。
これはもう少し別の視点で見直す必要がありそうです。
……と、そんなわけで。
次回はクラスとメソッドについてさらっと学ぶ予定です。