MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSA Developer News[MOSADeN=モサ伝]第315号

2008-10-07

目次

  • りんご味Ruby         第33回  藤本 尚邦
  • 藤本裕之のプログラミング夜話   #146
  • 高橋真人の「プログラミング指南」  第144回

りんご味Ruby   第33回  藤本 尚邦

■ Rubyプログラミングでのsyntax sugar

前回のMechanizeのコードの中にたくさん出てきた with が気になった方はいらっしゃるでしょうか。

 page.links.with.text("使い方")           # 「使い方」へのリンク全て
 page.forms.with.name('textFormEntry')    # textFormEntryフォーム全て
 form.fields.with.name('text')            # name属性がtextの全フィールド
 form.radiobuttons.with.name('eid').with.value('CR-EJ')[0].check


実は、これらの with は省略することができます。

 page.links.text("使い方")
 page.forms.name('textFormEntry')
 form.fields.name('text')
 form.radiobuttons.name('eid').value('CR-EJ')[0].check


この with は WWW::Mechanize::List クラスのインスタンスメソッドで、その定義は以下の通りです。

 def with
   self
 end


何もせずに単純にレシーバオブジェクト自身を返しているだけですね。したがって、withを省略しても意味的には同じことで、もちろん結果も同じになります。

with を使うと、使った分だけメソッド呼び出しが増えることになります。メソッドの呼び出しはそれなりに時間的コストのかかるものですから、with を使えば使うほどプログラムの実行速度を遅くすることにもなります。withは、速度を犠牲にしてでもソースコードを読みやすくするという目的のために存在しているメソッドということになるでしょう。

このWWW::Mechanize::Listのソースは、たったの72行で、しかもその大半はコメントに埋め込まれたドキュメントでコード自体は数行程度ですので、せっかくですから目を通してみるとよいでしょう。OSX 10.5付属のRubyとRubygemsを使ってインストールしている場合には、

/Library/Ruby/Gems/1.8/gems/mechanize-0.7.8/lib/www/mechanize/list.rb

にあります(インストール・更新の状況により若干違うかもしれません)。このソースを見ていたら:

     alias :and :with

のように with の別名として and が宣言されていました。ですから、例えば

 

form.radiobuttons.with.name('eid').with.value('CR-EJ')

のところは

 

form.radiobuttons.with.name('eid').and.value('CR-EJ')

と書くこともできます。

ソースのコメントのところにも書いてありますが、このような with や and みたいなものは syntax sugar と呼ばれています。ウィキペディアによると、syntax sugar は、糖衣構文、構文糖衣、構文糖などと訳すことがあるようです。

(補足 — 厳密に考えると、これら with や and は構文ではなく、WWW::Mechanize::Listクラスのインスタンスメソッドなので、「構文による味付け」というような意味合いを持つ syntax sugar というフレーズで呼んでいいものかどうか、やや微妙なところもあります)

Rubyプログラミング用に公開されているライブラリでは、プログラムを(自然言語的な意味で)読みやすくすることを考えて、このようなメソッド呼び出しによる疑似的な syntax sugar が用意されているものがたくさんあります。Rubyon Rails が登場したあたりから、主に海外のライブラリ開発者によってこの傾向が加速しているような気がします。

Rubyは遅いと言われがちですが、プログラミングには、速度を犠牲にしてでもコードの読みやすさを優先すべきときもあるのかもしれません。

■ [おまけ] 文字列オブジェクトに翻訳メソッドを追加する

文字列に翻訳機能があるといいかもしれませんね。

 "おはようございます".translate(:je)
 => "Good morning"


というような感じでしょうか。ということで、YahooHonyakuクラスの初歩的な応用として、Stringクラスに翻訳を実行するメソッドを追加してみましょう。

class String
 require 'YahooHonyaku'
 @@translator = YahooHonyaku.new

 def translate(mode)
   @@translator.translate(mode, self)
 end
end


これだけで、Rubyの文字列クラスに、自身を翻訳した文字列を返す translateというメソッドを追加しました。このようにRubyでは、実行時に既存のクラスにメソッドを追加することができます。

@@translatorは(文字列クラスの)クラス変数です。Rubyプログラムでは、`@@’で始まる変数名がクラス変数になります。翻訳器オブジェクトを翻訳のたびに生成するのは無駄にコストが高くつくので、文字列クラスのインスタンスすべてが、クラス変数を介して同じ翻訳器を共有するようにしました(本当は、Cocoa流に、YahooHonyakuクラスに YahooHonyaku.shared_translator みたいなクラスメソッドを用意すべきかもしれませんが省略します)。

藤本裕之のプログラミング夜話 #146

 実を言えばオレは懐疑的だが(ちうか,こういうのに対して「あるある,あるよね!」みたいな甘い態度でいると早晩スピリチャル系詐欺師にケツの毛まで抜かれることになるぜ,というのがオレの基本的スタンスである),ユング派心理学に「シンクロニシティ(共時性)」という概念がある。

 日本語でいう「ムシの知らせ」というヤツでね,永年思い出しもしなかった親戚の夢を見たら次の朝そのヒトの訃報が届いたとかそういうやつ。マトモな科学者は「そんなの偶然やんけ」と言うところ,フロイドの(ピンク・フロイドぢゃないよ,ところでこのヒトの名前はSigmund Freudというスペルなのになんで多くのヒトが「フロイト」と濁らないで覚えているのだろうか。ハンフ
リー・ボガートと逆である)影響を受けてかちとオカルトかがったところがあったユング先生は「いやそうやない。これにはワシラが知ってる因果では説明できないツナガリがあるんや,ウケケケケケ」と断じたわけである。

 もっと詳しく知りたいヒトにはWikipediaを調べるなりちょっと旧いがF・D・ピート著「シンクロニシティ」(信じてないオレでもこの本は面白かったよん)を繙いてもらうなりするとして,今回はユング先生だったら「見よ,これぞシンクロニシティ」と言うだろう出来事から……。

 前回最後でワタシは,「次回から,この薄暗いじめじめしたところ……それぢゃ漱石の猫の出生地だ,この先行き拡大することもなさそうなパソコン用アプリケーション市場で,どのようなアプリケーションであれば生き残って行けるのか,どのようなアプリケーションがそれでも売れているのかを見て行きたい」と書いた。書いたものの,忙しくてさぁ,それを調べる時間が取れないで
いたのである。

 が,そしたらなんと9月25日。ナゴヤの出張先で打ち合わせの合間にブラウズしてたgoo のページにそのものズバリ,「自分のパソコンに追加インストールしているソフトランキング」というのが掲載されてるのを見つけちゃったわけである。これぞまさしくシンクロニシティ,怪しげなオカルト詐欺師に「ほらねフジモトさん,こういうことが起きるのはあなたについている守護霊がとっても強いからなのよ」とか言われそうである。ま,ホントにその守護霊とやらが強いなら,こんな遠回りの支援ではなく,いきなり万馬券が当たるとか数年前に書いた本が突然売れ出して増刷掛かるとかもっと直接助けて欲しいもんです,とこの場を借りて申し上げておきますが。

 とにかくこのランキングによるとあなた,道は険しいのである。1位ウィルス駆除ソフト,2位ファイル圧縮解凍ソフト,3位オフィス用ソフト(これってつまりマイクロソフト・オフィスってことだろ?),4位音楽プレイヤー(バンドル以外の音楽プレイヤーってことはWindowsにiTunesを入れてるってことか?),5位葉書・年賀状作成ソフト……と,上位はほとんど定番があっていまさらクイコムことは不可能と思われるジャンルが並んでいる。我が身をユーザに置き換えても,これまで聞いたこともないような会社から「もんのすごい効果のウィルス駆除ソフトが出ました」と言われて買うかと言われたら否定的だ(そんなんだったら「あんまりマメに更新を迫らない駆除ソフトです」の方が魅力的だったりする)。

 以下画像処理,CD・DVDライティング,インターネットブラウザ(これはつまりIEやSafariに満足しないでFirefoxとかOperaを入れてるってことなんだろうが,これらがほぼ無料であることを考えると,これ以上上のランクにいる有料のソフトがどんだけ強いかわかるよね),動画プレイヤーと続いて10位がゲームである。

 ここまで見てきて曲がりなりにも新規参入定番化……定番化は難しいとしても,それなりに成功が望めそうなのはこのゲームくらいだろ。このゲームという分野にだけはまだ,ニューフロンティアというか,「今までだれも思いつかなかった」とか「なんでこんなモノはこんなに流行ったのか解らない」とかいうシロモノが生まれる余地が残っているような気がする。
 
 ちうことで,次回は「ゲームを作って一発当てる可能性」についてしつこく不覚……不覚をとってどうする,深く考えて行ってみたい。あっと,それから本文中で言及しているランキングのURLは以下の通り。いつまで掲載されているかわかんないので必要のある人(そんなヒトいるのか?)はアーカイブを。

http://ranking.goo.ne.jp/ranking/009/add_install/&f=news&LID=news

                       (以下次回 2008_10_03)

高橋真人の「プログラミング指南」第144回

プログラマのためのオブジェクト指向再入門(50)

〜XcodeによるPowerPlant X入門(33)〜

 こんにちは、高橋真人です。
 前回からの続きですが、「新たな整数型を定義する」ということは、前回の最後に示したFoo(UInt32)とFoo(OSType)が定義できるようになる、即ち、UInt32とOSTypeがコンパイラに別々の型として認識されるようにする、ということです。
 そのために必要なのが、前回出てきたIntegerTypeという名のクラスです。

template 
struct IntegerType {
   IntegerType()                       : mValue(0) { }
   IntegerType(TValueType inValue)     : mValue(inValue) { }
   operator TValueType() const         { return mValue; }
   operator TValueType&()              { return mValue; }
   TValueType      Get() const         { return mValue; }

   TValueType      mValue;
};


 これが、クラス定義です。説明を簡単にするため、ここでの説明に関係しない要素は省いて、より単純化してあります。オリジナルの完全な形は前述のPPxTypes.hをご覧ください。
 このクラスの意味は後で説明しますが、とりあえずは使い方をご覧いただきます。前回のプログラムを以下のように変更します。

#include 

// ※この部分は、あとで説明。

struct UInt32Struct {};
typedef IntegerType   UInt32_t;

struct OSTypeStruct {};
typedef IntegerType   OSType_t;

void Foo(UInt32_t a);
void Foo(OSType_t a);

int main()
{
   OSType_t value = 'TEXT';
   Foo(value);
}

void Foo(UInt32_t a)
{
   std::cout << "a is UInt32." << std::endl;
}

void Foo(OSType_t a)
{
   std::cout << "a is OSType." << std::endl;
}


 引数の型が、UInt32とOSTypeから、それぞれUInt32_tとOSType_tに変わっていますが、これは既存のシンボルとぶつかることを避けているだけの話です。
 また、main関数でのFoo()の呼び出し部分に直接値を与えずに、変数を作って、それを介して値を渡していますが、これは当然のことで、'TEXT'という“生の”値はC/C++処理系にとっては既にint(GCCの場合。CodeWarriorではlong)の型として認知されていますから、そのままではUInt32_tにもOSType_tにもなりません。
 わざわざ変数を作るのを潔しとしないのであれば、単にFoo((OSType_t)'TEXT');というようにキャストするだけでも問題ありません。
 ところで、上記のコードの※印のところですが、今回の冒頭に掲げたIntegerTypeの定義部分を記述していただくか、PPxオリジナルのIntegerTypeをそのまま使うのであれば、

#include 
using namespace PPx;


という2行を入れていただければOKです。
 さて、今回の変更のキモは、UInt32_tとOSType_tという新たな型を導入していることです。定義内容をつぶさに見ていくと、やっていることは全く一緒です。
 たとえば、定義したい型がUInt8(unsigned char)なのであれば、

struct UInt8Struct {};

と、独自に型を一つ作っておいた上で、あらかじめ定義してあるIntegerTypeのテンプレート引数に、UInt8と共に与えます。具体的には、

IntegerType

という感じです。これにtypedefを使って新たな名前を付けてやれば完成となります。

typedef IntegerType     UInt8_t;

 いろいろと、複雑に見える仕組みがあるように見えるかもしれませんが、このような手順を経ることによって、言語にもともと組み込まれている型と全く同じような使い方ができるのです。たとえば、

UInt8_t a = 'A';

std::cout << a << std::endl;

a = a + 0x20;

std::cout << a << std::endl;

UInt32_t b = 10;
UInt32_t c = a + b;

std::cout << c << std::endl;

というような書き方ができるのです。つまり、もともとの型の性質を維持したままで、なおかつ型の識別も可能になるという付加価値を付けられることになります。

 ところで、今回の解説を読んでいて「structなのにクラスと言っている」と疑問を持たれた方がおいでかもしれません。実は、C++ではstructもクラス定義のためのものになっています。詳しい話はまたいずれ。

◇MOSAからのお知らせと編集後記は割愛します◇

 

 MOSA Developer News   略称[MOSADeN=モサ伝]
        配信停止 mailto:mosaden-ml@mosa.gr.jp
 記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
      記事投稿受付 http://www.mosa.gr.jp/?page_id=850
Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
特定非営利活動法人MOSA  http://www.mosa.gr.jp/
Copyright (C)2007 MOSA. All rights reserved.