他の言語(Java)っぽくPerlを使う話


この記事はPerl Advent Calendar 2018の2日目の記事です。

皆さん、PerlでOOPしてますか?
私は今年Perlに入門したのですが、Perlのオブジェクト指向はかなり独特だと感じました。
MouseやMooseを使って簡単に書くことはできますが、やはりそれでも他言語の構文との差はあるように思います。

そこで、Perlの柔軟な文法を活かしてclass構文を作ってみることにしました。

方針

  • できるだけJavaっぽくする
  • blessは裏側でやる
  • クラス名をクォートで囲わなくてはいけない箇所を減らす
  • 素のPerlよりも堅牢になる仕組みを組み込む

実装

https://github.com/yumlonne/p5-Class-JavaLike
突貫で作っていたためコード汚いです

現在実装できているのは以下の機能です

  • class構文
  • アクセス修飾子(public・protected・private)
  • 変数宣言(public var => @array)
  • コンストラクタ
  • メソッド
  • 引数型チェック
  • 単純な継承

使用例

use Class::JavaLike;
use Class::JavaLike::Classes;
use Types::Standard -types;

# classの定義
class Point2D => sub {
    # 変数の定義
    public var => qw(x y);

    # コンストラクタ
    public new => args[Int, Int] => returns[classes->Point2D] => constructor {
        my ($self, $x, $y) = @_;
        $self->x = $x;
        $self->y = $y;
        return $self;
    };

    # addメソッド
    public add => args[classes->Point2D] => returns[classes->Point2D] => method {
        my ($self, $that) = @_;
        return classes->Point2D->new($self->x + $that->x, $self->y + $that->y);
    };

    # プライベートなnegateメソッド
    private negate => args[] => returns[classes->Point2D] => method {
        my $self = shift;
        return classes->Point2D->new(-$self->x, -$self->y);
    };
};

こんな感じでclassを定義できます。
裏側では、パッケージClass::JavaLike::Class::${ClassName}にメソッド群を植え付けています。
このクラスは以下のように使えます。

# usage
my $p1  = classes->Point2D->new(10, 20);
my $p2  = classes->Point2D->new(22, 18);
my $res = $p1->add($p2);

say $res->x;    # -> 32
say $res->y;    # -> 38

classes->Point2Dは単に'Class::JavaLike::Class::Point2D'という文字列を生成しています。
同様のことがclassof('Point2D')でできますが、クォートが冗長だと思い、AUTOLOADを使ってクォート無しで指定できるようにしました。

また、継承ができるので、Point2Dを継承させてPoint3Dを作ることもできます。

class Point3D => extends Point2D => sub {
    public var => 'z';
    public new => args[Int ,Int ,Int] => returns[classes->Point3D] => constructor {
        my ($self, $x, $y, $z) = @_;
        $self->x = $x;
        $self->y = $y;
        $self->z = $z;
        return $self;
    };

    public add => args[classes->Point3D] => returns[classes->Point3D] => method {
        my ($self, $that) = @_;
        return classes->Point3D->new($self->x + $that->x, $self->y + $that->y, $self->z + $that->z);
    };
};

展望

戻り値の型チェックや再代入不能な変数(val)の導入などなど、Perlでのプログラミングを堅牢にする仕組みを導入できそうですね!
まだまだ未完成なので、今後も改善していきます。

最後に

Perlの文法を使い、何ができるか考えるのがすごく面白かったです。
みなさんもやってみてはいかがでしょうか。

明日は omokawa_yasu さんです!お楽しみに!!