2006 年 4 月 23 日 23 時 50 分

関数とメソッド


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


そこそこ洗練されてきた property モジュールだが、
まだまだ課題点はある。

問題の一つは、登録時に setter/getter の
コードリファレンスを指定していることだ。

Perl におけるコードリファレンスは、
関数を指すリファレンスであり、
メソッドを指すリファレンスとはならない。

関数とメソッドに、構文上の違いはないが、
メソッドのリファレンスを取ると、
それはメソッドとしての意味を失い、
ただの関数のリファレンスとして扱われる。

こういうと難しいかもしれないので、今回も例を挙げよう。

    use strict;
    use warnings;

    package Base;

    sub new {
        my $package = shift;
        my $value = shift;
        bless({'value' => $value}, $package);
    }

    sub get_value {
        my $object = shift;
        $object->{'value'};
    }

    sub mul10 {
        10 * shift;
    }

    package Derived;

    our @ISA = ('Base');

    package main;

    my $obj = Derived->new(3000);
    print "Value: ", $obj->get_value, "\n";
    print "x10: ", Base::mul10(20), "\n";

Base は new と get_value, mul10 を持つ簡単なクラスだ。
new はクラスメソッドであり、
get_value はインスタンスメソッド、
mul10 は関数である。

それぞれどこが違うかみてみよう。

メソッドへの呼び出しには、アロー演算子が使われる。
メソッドの特徴は、継承を考慮するということだ。

クラスメソッドは、パッケージ名->メソッドの形だ。
Derived->new は、Derived の new メソッドを探す。
見当たらない場合、@ISA を参照して親クラスから探す。
最終的に見つかったメソッドの第一引数に、
'Derived' という文字列を渡して呼び出される。

インスタンスメソッドは、インスタンス->メソッドの形だ。
$object->get_value は、$object のパッケージから
get_value メソッドを探す。
$object は bless されているため、
自分のパッケージ名を知っているのだ。
見当たらない場合、@ISA を参照して親クラスから探す。
最終的に見つかったメソッドの第一引数に、
$object 自身を渡して呼び出される。

上記では、Derived 自身にはメソッドが定義されていないが、
Derived は Base を継承していることを @ISA で示しており、
上の 2 つのメソッドは、Derived からも呼び出せるのだ。

関数は、パッケージ名::関数名 として呼び出される。
mul10 は、Base パッケージに定義されているので、
Base::mul10 と限定名を使って呼び出しているのだ。
関数は、継承とは関係ないため、
Derived::mul10 とすれば見つからないというエラーとなる。

このように、サブルーチンは、呼び出し方によって、
メソッドとなったり、関数となったりするのだ。

さて、コードリファレンスは、
サブルーチンへの参照でしかない。
そのため、メソッドのリファレンスを取ったとしても、
それはただの関数のリファレンスになってしまうのだ、
そこには、継承の概念はない。

明日は、これがどのような問題となるか考えてみよう。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.