第140回 ブロックを渡せるのはRubyだけじゃない! Perlだって渡せるんだ!

YAPCが始まりましたね。
去年は参加したのですが(聴衆の方ですが)、今年は非常にとてつもなく残念な事に参加できません。


でも気分だけでもひたりたいのでPerlのお話を少々。

Rubyに備わったブロックという概念

Rubyは言語自体に高階関数をブロックという形でもっており、
eachなどで使われているのは有名です。


例:

array = [1,3,5,9]
array.each{|i| puts i}

eachに与えている { }の部分がブロックです。
自前でブロックを受け取る関数を作りたければ yield を使えばよいでしょう。


今回のお話の内容は「Perlでもブロックを渡せる」ということなので、
eachの機能, yieldの機能は知っておられるという前提で先にすすみたいと思います。


Perlのブロックを使った例

それではRubyの話はこれくらいにしてPerlの話にまいりましょう。
まずPerlでこの高階関数のように振る舞うブロックを使った組込関数を見ていきたいと思います。
今回はmapを使った例を紹介します。

use Data::Dumper;

my @c = 1..5;
my @d = map { $_ * 2 } @c;  # @cの各要素を2倍した配列を返す

print Dumper \@d;

結果:

$VAR1 = [
          2,
          4,
          6,
          8,
          10
        ];

ソース中のコメントにも書きましたが 各要素を2倍した配列を返しています。

map ブロック 配列

という書式です。


ブロックを引数にとる関数の作り方

このようにブロックを引数にとる関数は自前でつくることができます。
このことにより、あたかもPerlにもとから備わっている組込関数もしくは文法のように振る舞わせることが(書くことが)可能となります。


定義の仕方は簡単。以下のようにプロトタイプを使えばよいだけです。

sub(&){  }

このようにPerlのプロトタイプで&を指定することでブロックを受け取ることができます。

sub hoge(&){
 $code = shift;
 $code->();
}

hoge { print 'Hello World' . "\n" }   # ブロックを渡す

これだけだと、だから何?という感じですので、
実用的な例を紹介しましょう。
Perlの5.8から組み込まれたList::Utilに備わったfirstを使うと

use List::Util qw(first);

my @c = 1..5;
my $d = first { $_ > 3 } @c;  #最初に3を超えるものを取得
print $d . "\n";

このように最初に3を超えるものを取得することができます。


これを自作するならば、

sub first(&@){
  my $code = shift;
  for(@_){
    return $_ if $code->();
  }
}

my @c = 1..5;
my $d = first { $_ > 3 } @c;
print $d . "\n";

このようになります。
実際、バージョン1.21のList::Util::PP.pmの44行目にほとんど同じソースを発見できました。

try{ }catch{ }構文だって作れる

このブロックを使えば、try{ }catch{ }構文だって作れます。
これをやったのがError.pmです。どのようにやってのけているのかは

プログラミングPerl〈VOLUME1〉

プログラミングPerl〈VOLUME1〉

に少し説明されていました。

概略だけ簡単に説明すると、

sub try(&$){  }
と
sub catch(&){  }

を使い、実にうまい具合に tryのブロックが先に処理されるように実装されているようです。


DSLだって作れる

ブロックを渡せることによって最近流行のDSLだって作る事ができます。
これをやっているのが、Web::Scraperです。

2007-05-09

scraper {

}

のブロックの中にどのような処理を行なってほしいのか示すことができます。

ブロックを受け取れるようにできるのは第1引数だけ

最後に注意事項です。
プロタイプに&を書いてブロックをもらうことができるのは、
ブロックを第1引数にもらうときだけとなります。





参考:
http://perl-mongers.org/2009/01/re_map.html
第81回 高階関数を理解できないとRubyは理解できない - bingo_nakanishiの他言語出身者のためのPerl入門

第139回 PHP入門

1章 さあプログラミングをはじめよう

こんにちは。ビンゴ中西です。
今回は、プログラミングは初めてという方を対象に、PHPというプログラミング言語を使って
プログラムの楽しさを知ってもらおうと思います。(注:今回はPerlではなくてPHPです。)


なお、PHPを動かすことはできるけど、自分でプログラムというのを書くには
なにから覚えていったらいいのかわからないという方を対象としています。

まず実行

<?php

print('Hello World!');

?>

さあ、上の1行をエディタというものを使って打ってみよう。
実行すると、

Hello World!

と表示されましたね!!! おめでとう大成功です。

聞き慣れない単語も徐々に覚えていこう

ここで、「エディタ」とか「実行する」という聞き慣れない単語が出てきたと思います。
基本的に、プログラムは、「エディタ」と呼ばれるソフトを使って書いていきます。
「実行する」とはプログラムを動かすことです。
僕が、初めてプログラムをやったときは、
もうエディタが何かもさっぱりわからないし、プログラムをどうやって実行していいかもわからない。
1週間ぐらいかかって実行できた記憶があります。

Wordではなくエディタ

ああ、そういえば、「Word」っていうソフトで文字を打ったことあるぞ! と思って、
「Word」を使ってプログラムを書いてはいけません。
プログラムというのは、上記のように文字をコンピュータが解釈して「なにかを起こしてくれる」ものなのですが、
「Word」で書いた文章は、「Word」が読み込むためにあります。

これは、どういうことかというと、「Word」で書かれたもの(ファイル)は、「Word」だけが理解できる情報を持っています。

これに対して、「エディタ」と呼ばれる部類のものは、そういった余計な情報は付けません。
ですから、僕らが打った情報だけをそのまま保持してくれる「エディタ」がプログラミングには、必要なのです。


2章 print ってなんだろう

さて、

print('Hello World!');

というのを詳しく見ていこうと思います。
最後の ; (セミコロン)なんかも気になりますねぇ。
プログラムというのは、複数の「文」というものによって成り立ちます。
僕らが使っている日本語なら、
「今日は、いい天気です。」
というので1文です。 最後の「。(句点)」が文の終わりを示しています。

PHPに置いては、「;」が文の終わりを示しています。


print というのは、画面に文字列を表示するための命令です。
これで、Hello World! という文字列が画面に表示されたわけです。
おや、'(シングルクォート)は表示されていませんね。
'(シングルクォート)は、その間にあるものが「文字列」であるということを表しています。
こんな感じで、プログラム言語というのは、色んな記号を用いて、「意味」を示すことができます。

3章 変数を使おう

「変数」というものを学びたいと思います。これは、「へんすう」と読みます。
なかなかどんなものか想像しづらいですが、ゆっくり見ていきましょう。
「変数」というのは「箱」をイメージするとわかりやすいです。
いつまでも「箱」のイメージでは、成長(プログラミング能力)は止まってしまいますが、
ひとまず、成長が止まるところまでは、「箱」のイメージにしておきましょう。

では、この「箱」の機能を紹介したいと思います。

  • けっこう何でも入れれる
  • 名前を付けなければいけない
  • 箱の中身をとりだすことができる


ざっとこんな感じです。
「けっこう何でも入れれる」のところですが、それでは学習しづらいので、今回は、
「数字」を入れてみましょう。

<?php

$x = 1;

?>

これで、 $xという名前の「変数」(箱ですね)に、数字の1が入りました。

まさに驚愕ですね。何がなんだかという感じかと思います。
PHPでは変数であることを示すために頭に「$(ドル)」がつきます。
今回はxという名前の変数を用意したことになります。

=(イコール)が気になる

=(イコール)はなんでしょうか?非常に気になりますね。

この記号は、「代入」という意味で使われます。
「だいにゅう」と読みます。「代入」とは聞き慣れないかもしれませんが、「なにかを入れる」という意味です。


えー「=(イコール)」は「等しい」っていう意味だぞ と反論されるかもしれませんが、
それは数学においてのお話です。 プログラミング言語では、数学とは記号の意味を変えてしまって、「代入」という意味で使います。


数学と同じ意味では、「==」とイコールを2つ書くことにPHPの世界ではなります。
初めのうちは、やや親しみにくいですが、「=」で「代入」を意味するのは、プログラムの世界では常識ですので、慣れていきましょう。

プログラマたちはどう理解しているか

プログラマの人たちは、

$x = 1;

というのを見た瞬間に、「$xに1を代入する」とこのプログラムを読むことができます。
プログラムの世界では変数というものに値を代入できることを覚えましょう。


4章 変数をもっと使う

「変数」というものを初めて見たわけですが、
ここで変数の機能をもう一度確認してみましょう。

  • けっこう何でも入れれる
  • 名前を付けなければいけない
  • 箱の中身をとりだすことができる

でした。

三章で、

  • けっこう何でも入れれる
  • 名前を付けなければいけない

の部分は説明しましたが、

  • 箱の中身をとりだすことができる

の説明をまだしていませんでしたので、4章ではこの部分の説明をしたいと思います。
3章で、

<?php

$x = 1;

?>

を書きましたが、本当に1が入ったか確認する方法はないのでしょうか?
あります。print を使いましょう。 printは画面に表示するという意味でしたね。

print($x);

としてみましょう。

全体のソース(内容)は、

<?php

$x = 1;
print($x);

?>

となります。

実行してみましょう。

1

と表示されれば成功ですよ。
こんな風に、printを使うことで、変数の中身をとりだして見ることができました。


足し算させてみよう

さて、

いま、変数に数字の1を入れましたよね。

これに8を足して9という値を作り出してみましょう。

<?php

$x = 1;
$y = $x + 8;

?>

$y = $x + 8 のところが学習ポイントです。

$y は 9 になっていますよ。

ご自身で、 print $y; と付け加えてみて、表示させてみてください。


動作はこの絵のように$xの値が取り出されて、8が足され、
$yに代入されているのです。



では、次はどうでしょうか?

<?php

$x = 1;
$x = $x + 8;

?>

次の部分がむずかしいですね。

$x = $x + 8;

この処理を絵で表すとつぎのようになります。

先に右辺が処理されるのです(評価されるという)。

そして、その右辺が評価された結果が$xに代入されています。
つまり、$xが上書きされているイメージです。

このように「変数」の中身は書き換えたり(上書きしたり)して、どんどん値を変えます。

これが「変数」と呼ばれる所以なのです。

第138回 MONOPOLYの短縮ゲーム

MONOPOLYは下手をすると何時間も勝負をつけるのに時間がかかってしまうときがある。

そこで、短縮ゲームというのが存在するらしい。
説明書に載っているのは、まずプレー前にあらかじめ権利書をよくきってから
2枚ずつプレーヤーに配り、その土地のお金を支払ってから始めるというものだ。


また普通は、家を4件立ててからホテルにするが、3つ建てたらホテルにできる というのも載っている。他にもある。



だが、ここで問題にしたいのは権利書をよくきるという行為だ。
権利書はカラーごとに用意しておいたほうが、ゲームを円滑にすすめることができるだろう。


そこで、権利書はランダムにPerlに選んでもらおうではないか。

use strict;

# プレーヤー名
my @player = ('木村', '田中');

# 権利書を配る数
my $num    = 2;


my @masu   = (
              # ダークパープル
              '地中海通り', 'パルティック通り',
         
              # 鉄道
              'リーディング鉄道', 'ペンシルマニア通り', 'B&O鉄道', 'ショートライン鉄道',

              # 公共
              '電力会社', '水道会社',

              # ライトブルー
              'オリエンタル通り', 'バーモント通り', 'コネチカット通り',
  
              # ライトパープル
              'セントチャールズプレース', 'ステーツ通り', 'バージニア通り',

              # オレンジ
              'セントジェームスプレース', 'テネシー通り', 'ニューヨーク通り',

              # レッド
              'ケンタッキー通り', 'インディアナ通り', 'イリノイ通り',

              # イエロー
              'アトランティック通り', 'ベントノール通り', 'マービンガーデン',

              # グリーン
              'パシフィック通り', 'ノースキャロライナ通り', 'ペンシルバニア通り',

              # ダークブルー
              'パークプレース', 'ボードウォーク'
            );


for(@player){
  print $_ . 'さん' . "\n";
  
  for(1..$num){
    print '-->';
    print +(splice @masu, rand @masu , 1), "\n";
  }

  print "\n";
}


だれか私に「権利書」の英訳を教えてほしい。
わからないので変数名を「$masu」にしてしまった。


@player にはプレーヤーの名前を書いていけばいい。
$num には配りたい権利書の数を書けばいい。


あとは実行するだけだ。

木村さん
-->ステーツ通り
-->ニューヨーク通り

田中さん
-->パークプレース
-->リーディング鉄道

第137回 Perlは空気を読んでくれない Perlには空気を読ませると考える

Perlは空気を読む言語といわれています。

確かに楽な言語です。そして楽しい言語でもあります。
しかし、そう思えるようになったのは、Perlをある程度思ったとおりに動かせるようになってからです。

Perlは空気を読んでくれる?

Perlが空気を読んでくれるというならば、
あなたがテキトーに書いたソースでも、あなたが思った通りに動いてくれてもいいはずです。
「俺はこういうつもりで書いたのに、なんでPerlはそう思って動かないの!?」
こうなります。


また、空気を読むということでPerlからいきなり、
「今回の実行では、こうしといたよ。 前の実行とはなんとなく違う気がしたから、ちょっとだけ違う動きにしたけど。」
と言われてしまったら困ってしまいます。


プログラムですから、明確な理由がなく毎回違う動きになっては困るのです。


Perlが空気を読むってどういうこと?

ではPerlが空気を読むというのはどういうことなのでしょうか?
次のソースを見てください。

if( @c ){  }

これでPerlは配列の大きさが0でなければifの中を実行してくれます。
これは、このソースを何回実行しても同じ意味です。
Perlは常に配列の大きさが0でない場合にifの中を実行してくれます。


なぜこのような処理になるのでしょうか?
Perlでは、

if(ここ){}

「ここ」の部分はスカラーなブール値とみなします。



@cをスカラーなブール値とみなしたときどのように処理が進むかと言いますと、


@c → スカラーだと配列の大きさ → 数字をブールで評価すると0なら偽、そうでないなら真


こうなります。


これは、こうなると知っていないければ、こんなソースを書くことはできません。
つまり、プログラマは強い意志をもってここはスカラーな値でブールで判断して!と思って書いているのです。


Perlは空気を読んでくれない Perlには空気を読ませる

Perlは空気を読んでくれますが、簡単には読んでくれません。
こちらが、空気を読んでくれるように、ほのめかさないといけません。


先ほどの例だと、
「ifの中に配列を置いておいたよ。いつものやりかたでやっておいて」
とこうなります。

Perlに振る舞ってほしいように暗に示すのです。
この暗に示すやりかたを覚えてプログラムを書くとすばらしく奇麗なソースになるのです。
プログラマとPerlの間に「阿吽の呼吸」がうまれます。
上級者は誰よりもうまくPerlと呼吸を合わせます。これがPerlが空気を読むということなのです。


Perlのソースはそうそう簡単に読めなくならない

Perlのソースは省略が多くてすぐに読めなくなると言われることがあります。
ですが、私はそんな風には思えません。Perlを書くにはかなりの知識を要求されます。
Perlが暗にどのように振る舞うのか知らなければいけません。
これを知らずにしてソースコードを省きまくることはできません。
もし省略したソースを書く人がいたらその人は知っています。
強い意志をもって、プログラムを書いています。そして、そうでなければいけません。
プログラム自体を覚えはじめの人にはまだ省略した書き方はできません。
まだ知識をつけることがたくさんあります。
プログラムを覚えたばかりの人は、アルゴリズム的にも冗長になったりして、短くなって読みにくいどころか、
余計な処理や、ときには重複した処理がはいったりします。私はそういった点のほうがソースが読みにくくなるのではないかと思います。

第136回 PHPでダックタイピング

PHPでもクラスベースのオブジェクト指向が書けますね。
しかもPHPは動的型付けではなりませんか、ということは
とっても簡単にオブジェクト指向を使って強力なプログラミングが行なえます。

PHPでポリモーフィズム

ポリモーフィズムは便利ですね。

すごく便利ですし、プログラムが超スマートになります。
プログラミングの発想も日本語で考えるような発想になって大変自然です。

しかもPHPならダックタイピングで書けます。


次のソースを見てください。

<?php

class Dog{ 
  function say(){ print 'わん' . "\n"; }
}

class Cat{
  function say(){ print 'にゃん' . "\n"; }
}

$animals = array(new Dog, new Cat);

foreach($animals as $animal){
  $animal->say();
}

?>

Dog(犬)クラスとCat(猫)クラスを作りました。
それぞれにsay()というメソッドを実行してもらいたいので、foreachを使いました。
このようにforeachで同じ処理を回すやりかたは大変便利です。
DogもCatも同じ処理をするということが一目でわかります。
参考:第68回 関数ではなくforで処理を共通化する - bingo_nakanishiの他言語出身者のためのPerl入門



では、このソースを実行してみましょう。
結果:

わん
にゃん

1回目のループで「わん」が表示され、
2回目のループで「にゃん」が表示されました。


1回目のループでは感覚的に

Dog->say()

2回目のループでは

Cat->say()

が実行されたイメージです。
これは arrayに入れた順番「array(new Dog, new Cat) 」通りですね。
1回目のループはDogのsay, 2回目のループはCatのsayと簡単に理解できます。



オブジェクト指向を使わない場合

オブジェクト指向を使わないで書いた場合、どのようになってしまうのでしょうか?
プログラムを学び始めてすぐにif文を習います。
if文を覚えただけで、結構バリエーションに富んだプログラムが書け、うれしくなります。
if文でプログラムを学ぶことを満足してしまうと次のようなソースを書いてしまうかもしれません。

<?php

$animals = array('Dog', 'Cat');

foreach($animals as $animal){
  if($animal == 'Dog'){
    print 'わん' . "\n";
  }else if($animal == 'Cat'){
    print 'にゃん' . "\n";
  } 
}

?>

if文で文字列'Dog'の場合なら「わん」
'Cat'の場合なら「にゃん」と表示するという処理になりました。



これがifの中でする事が多くなると、

  if($animal == 'Dog'){









  // 何百もあるソース









  }else if($animal == 'Cat'){

となって今どこのifの中を読んでいるのかパッと見ではわからなくなってしまいます。
そこで'Dog'だった場合に行なう処理を関数にしようとします。
そうするとifの中に書く量は減ります。

  if($animal == 'Dog'){
    dog();
  }else if($animal == 'Cat'){
    cat();
  } 

関数になったわけですが、オブジェクト指向の場合は初めからこの部分がメソッドです。
例:

$animal->do();


ここで、foreachの部分も含めて見比べてみましょう
オブジェクト指向:

foreach($animals as $animal){
  $animal->do();
}


if文:

foreach($animals as $animal){
  if($animal == 'Dog'){
    print 'わん' . "\n";
  }else if($animal == 'Cat'){
    print 'にゃん' . "\n";
  } 
}

どちらが読みやすいでしょうか?


私はオブジェクト指向の方がごちゃごちゃしていなくてすっきりしているように感じます。



意味的な違い

プログラムの意味的な違いはどうでしょうか?

オブジェクト指向の方は、1回目のループで「Dogの処理が、2回目のループでCatの処理が行なわれる」とさっと読めますが、if文の方では、「CatでなくてDogの場合ならDogの処理、DogでなくてCatの場合ならCatの処理」というように「〜でなくて」という部分がどうも気になります。

もっとifのパターンが増えると、「〜でなくて〜でなくて〜でなくて〜でなくて」となって読むのが大変になってきます。「でなくて」の部分はプログラム的には「else」に当たる部分ですね。



まとめ

オブジェクト指向のパワーを知って、
うまく使うと激的にソースが変わり、書く為の思考回路、読む為の思考回路もごろっと変わります。


オブジェクト指向をうまくつかって設計ができるとかなり強力になります。
といってもこれがいつも簡単に思いついてサクっとコーディングできるのならば誰も設計で苦労はしなくなるのですが....
設計のひとつの手段としてオブジェクト指向だともっとうまく書けるかもという発想は大切だと思います。



「ダックタイピングを用いたポリモーフィズム」と「継承などを用いたポリモーフィズム」の違い

ポリモーフィズムの実装方法によるパワーの違いはこのあたりに書きました。
第126回 ダックタイピング と インタフェース - bingo_nakanishiの他言語出身者のためのPerl入門
第127回 Ruby vs Java ダックタイピングとインタフェースで見る多態性 - bingo_nakanishiの他言語出身者のためのPerl入門

第135回 Perlに true, falseなんてない

あ、そこの君!
だまされたと思ってこれを実行していきなさい。

if( false ){
  print "ああああ\n";
}

どんな結果になったかね?
そうだ。

ああああ

こう表示されただろう。


ことの発端

この事実に気づいたのは、あるJS使いから

if( !false ){
  print "ああああ\n";
}

が trueにならないんだけど、どういうこと?
と質問があったからだ。



とあるC言語経験者の発言

そもそもC言語にも true, falseはないよね。
と言うのは、あるC言語経験者の発言。


ブーリアン型 - Wikipedia

C言語では、C89 にはブーリアン型が定義されていない(C99には定義されている)。ブーリアン型がない代わりに true/false は 0 かどうかで判断される。


C++では、標準化の過程で bool、true、false というキーワードが導入され、基本データ型としてサポートされた。その大きさは処理系で定義される。

だそうです。


Perlにも true, falseなんてないのさ

Perlの真偽値のルールは以下のような感じです。
Perlにおける真偽値 - Perl入門ゼミ



ラクダ本にバッチリ、ルールが載っていますが、残念ながら会社に置いてきているので参照できませんでした><

プログラミングPerl〈VOLUME1〉

プログラミングPerl〈VOLUME1〉


結局、 if( false ){ } はなんで真なの?

で、なんで

if( false ){
  print "ああああ\n";
}

で

ああああ

このように表示されてしまうのでしょう。


それは
クォートされていないワードは文字列として扱うからなんです。
http://outsider.imawamukashi.com/Perl/pragmatic_module.html

大丈夫! use strict; が僕らを守ってくれるぞ

そ!そんな馬鹿な話が!!
とお思いの方!

今や常識, use strict;を書けば僕らを守ってくれるぞ。

use strict;
if( false ){
  print "ああああ\n";
}

結果:

Bareword "false" not allowed while "strict subs" in use at e line 4.
Execution of e aborted due to compilation errors.

じゃあ今まで 1 == 1 は trueとか教わってたけど いったい何が返ってきてるんだ?

ん〜 trueとfalseがないなら比較演算子はなにを返してきてるんだろう...
実行してみました。

use Data::Dumper;

print Dumper false;                 # use strictを付けてないので 文字列の'false'
print Dumper true;                  # use strictを付けてないので 文字列の'true'

print Dumper 'aa' eq 'aa';          # 1
print Dumper 1 == 1;                # 1

print Dumper 'aa' ne 'aa';          # ''
print Dumper 1 != 1;                # ''

print Dumper !('aa' eq 'aa');       # ''
print Dumper !('aa' ne 'aa');       # 1

真だと 1
偽だと ''
のようですね。

openは何を返しているのだろう?

use strict;
use Data::Dumper;

# 存在しないファイル
print Dumper open my $c, '<', 'aaaaaaaa.txt';     # undef

# 存在するファイル
print Dumper open my $c, '<', 'p.txt';            # 1

存在しないファイルの場合は undef
存在するファイルの場合は 1なので、
Perlが偽、真と判断できるものがちゃんと返ってきていますね。


ということで

真偽にあたる true, falseは、まああるけども、
予約語的な true, falseはないですよ。
というお話でした。


今回は、上記のようなお話でしたから、Perlのifは使い辛いと感じられたかたもいらっしゃるかもしれませんが、私はPerlは極めて自然に真偽値を判断してくれていると思います。

第134回 モンキーパッチングをPerlでやるとこうだろうか

をすごく楽しく読んでいるとモンキーパッチングという発想がでてきました。

簡単に言うと、クラスを後から(実行時に)書き換えて、能力を追加することである。
起源は他人のバグを後付けで回避するところから始まったとのことです。

Ruby

class Bar
  def initialize(n)
    @name = n
  end
  def say1
    puts @name + 'です'
  end
end

bar = Bar.new('バー');
bar.say1

class Bar
  def say2
    puts @name + 'やがな'
  end
end

bar.say2

結果:

バーです
バーやがな

Perl

Perlにはクラスというのは存在せず、ただパッケージに属した関数を呼んでいるだけなので、
この書き方はできません。

use strict;
package Bar;
sub new {
  my $thing = shift;
  my $class = ref $thing || $thing;
  bless { @_ }, $class;
}

sub say1 {
  my $self = shift;
  print $self->{'name'} . 'です' ."\n";
}

package main;
my $bar = Bar->new( 'name' => 'バー' );
$bar->say1();

sub say2 {
  my $o = shift;
  print $o->{'name'} . 'やがな' . "\n";
}

say2($bar);

結果:

バーです
バーやがな

このようにsay2関数を作って、オブジェクト指向の書き方を崩すしか方法はないのでしょうか?

第1引数は暗黙的に補われる書式を思い出してみる

$o->say();

という書き方をした場合、$oがsayメソッドの第1引数に渡る事を思い出してみると、

use strict;
package Bar;
sub new {
  my $thing = shift;
  my $class = ref $thing || $thing;
  bless { @_ }, $class;
}

sub say1 {
  my $self = shift;
  print $self->{'name'} . 'です' ."\n";
}

package main;
my $bar = Bar->new( 'name' => 'バー' );
$bar->say1();

sub say2 {
  my $o = shift;
  print $o->{'name'} . 'やがな' . "\n";
}

$bar->main::say2();   # ここをオブジェクト指向っぽく書けた


結果:

バーです
バーやがな

このようにオブジェクト指向の書き方で書けました。
結局のところ、やはりインスタンス変数にあたるモノが属しているパッケージの関数を呼ぶわけではなく、強引にmainパッケージの関数を呼び出す書き方をしているだけですので、ここまでする必要があるかはいささか怪しいところがありますが、このようにも書けますということでした。


そもそもRubyはクラスを編集している

そもそもRubyはクラスを編集できているので、あたらしくそのクラスを元にnewしたものは追加されたメソッドが呼べます。

class Bar
  def initialize(n)
    @name = n
  end
  def say1
    puts @name + 'です'
  end
end

bar = Bar.new('バー')
bar.say1

class Bar
  def say2
    puts @name + 'やがな'
  end
end

bar.say2


other_bar = Bar.new('他のバー')
other_bar.say1()
other_bar.say2()

結果:

バーです
バーやがな
他のバーです
他のバーやがな

オープンクラスすごしです。



Perlはあくまでもmainのsay2を呼んだだけですので、

$other_bar = Bar->new( 'name' => '他のバー' );

としたところで、

$other_bar->main::say2();

としなければなりません....




※もっと良い方法がある。その方法だと、こんな不具合がでる。ということをご存知の方がいらっしゃいましたら教えていただけるとうれしいです。