Software Engineering Lecture 5/18

Software Engineering Lecture 5/18

動けば良いだけのプログラミングから、読めるプログラムへ

動かせるだけが精一杯、人のプログラムをコピーして手直し。それでいいのか?

例えば、「プログラム書法第二版」Brian W.Kernighan ISBN4-320-02085-5 C3041 は、Fortan を使ったすごく古い本だが、今でも有効な規則が多く載っている。

もちろん、今となっては、まちがっている規則もたくさんある。 「一時変数はなるべく使わない」なんていう規則はもはや時代遅れ だといえる。

Reference in Perl

Perlのデータは、配列と[1,2,3]と連想配列{'a',1,'b',2} を使う ことができる。


これらは、リスト(1,2,3)と違って無名配列(Anonymous Array) 、無名連想配列(Anonymous Hash)と呼ばれる。これらは名 前がないので、直接$a{'test'}などというようには扱えない。実際 には、これらは配列への参照であり、以下のように使う。
pw071: {1} % perl5 -de 0

Loading DB routines from perl5db.pl version 1
Emacs support available.

Enter h or `h h' for help.

main::(-e:1):   0
  DB<1> @a = (1,2,3,4,5)

  DB<2> p "@a"
1 2 3 4 5
  DB<3> @b = @a

  DB<4> p "@b"
1 2 3 4 5
  DB<5> $a[2]="kono"

  DB<6> p "@a"
1 2 kono 4 5
  DB<7> p "@b"
1 2 3 4 5
  DB<8> $a = [1,2,3,4,5]

  DB<9> p $a
ARRAY(0x805b3b4)
  DB<10> p @$a
12345
  DB<11> p "@$a"
1 2 3 4 5
  DB<12> $$a[1] = "kono"

  DB<13> p "@$a"
1 kono 3 4 5
  DB<14> $b = $a

  DB<15> $$b[2] = "kakazu"

  DB<16> p "@$b"
1 kono kakazu 4 5
  DB<17> p $b
ARRAY(0x805b3b4)
  DB<18> p $b->[2] = "higa"
higa
  DB<19> p "@$b"
1 kono higa 4 5
  DB<20> $c = {}

  DB<21> $c->{'kono'} = 'teacher'

  DB<22> $c->{'higa'} = 'student'

  DB<23> p %$c
higastudentkonoteacher
  DB<24> $c{'kono'} = 1

  DB<25> $c{'higa'} = 2

  DB<26> p keys %c
higakono
  DB<27> p $c
HASH(0x8134cc0)
プログラムの中に現れるPerlのデータは、\ を付けることによって参照 を取ることができる。
  DB<28> $d  = \%c

  DB<29> p $d
HASH(0x8152b00)
  DB<30> $d->{'shimabukuro'} = 'student'

  DB<31> p keys %c
higashimabukurokono
  DB<32> 

問題

以下の例題を動かしてみて、Perlの参照の振る舞いを理解すること。 出力を確認し、結果を提出する事。

     $a=[1,2,3,4];
     $a->[5]=3;
     print "@$a, $a->[2]\n";
     $b={};
     $b->{First}='Cat';
     $b->{Second}='Dog';
     $b->{Third}='Pig';
     foreach $key ( keys %$b)  { print "$key is $b->{$key}\n"  }
     @a =  ( 1,2,3,4);
     $refa = \@a;
     $refa->[5]=3;
     print "@$refa, $refa->[2]\n";


Package / Module

大規模なプログラムでは、変数や手続き名の数は数百以上になる。良く使われる 語彙は500程度と言われているので、必然的に同じ名前を使うか、無意味な識別 名を使う必要に迫られる。一方で、iとかjとかは一時変数として便利なので、 良く使うことが多い。しかし一時変数などは、データフローを持つ構造化技法 にはなじまない。

そこで名前空間というのを考える。名前空間が異なる場合は、そこでは同じ 同じ字面でも異なる名前をさすことになる。名前空間は、パッケージ(Package) または、モジュール(Module)と呼ばれる。C では、static というキーワード によりファイルに局所的な名前を作成することができる。これにより疑似的な 名前空間を作ることができる。

名前空間では、他の名前空間の名前を輸入(import) したり、自分の名前を 公共的なものと宣言する(export)する機能がついていることが多い。しかし、 名前空間と、その中の名前の対でアクセスすることでも十分である。これらの 名前空間はセキュリティなどとからめて使われることも多いが (Java などは そうである)本来は、セキュリティと名前空間の概念は直交している。

Perl のpackage は、package Hogehoe; と記述することによって作られる。 package 形式になったファイルは、hogehoge.pm という(Perl Module) 拡張子をつける。これにより、use hogehoge; という形で Module を 使用することができる。(通常のファイルは do "filename.pl"; というのを使う) ( perlmod を参照すること)



Object

オブジェクトのIDは、オブジェクトへのポインタあるいはユニーク な識別子であり、データベースでのキーと同じ役目を果たす。しか し、オブジェクトのIDは普通はプログラマが直接指定することはな い。

オブジェクトの間の関係は、

などが一般的だ。これらをさらに細かく、has-a, part-of などに分ける 手法もあるが、オブジェクトとしての実現という視点から見ると、 オブジェクトの属性(インスタンス変数)に代入されたオブジェクトID というだけだと言える。

オブジェクトの中身を直接いじることなく、オブジェクトIDを 通してオブジェクトにアクセスすることにより、インタフェースと 実装の分離を安全におこなうことができる。しかし、 その分、実行は遅くなる。オブジェクトIDからメッソドを探す という操作が必要だからである。もし、メソッドを呼び出す時に、 そのオブジェクトが何かを指定してやれば、そういうデメリットはない。 C++などは、そういう発想で作られている。

継承関係は、あるオブジェクトからすべての属性を引き継ぎ、さらに 何んらかの属性をつけ加えることを意味する。実際には、属性だけで なく、 オブジェクトの振る舞いもなんからの形で引き継いでいることを さす。ただし、今の所を、属性以外の条件はそれほど明確ではない。 継承するオブジェクトのプログラム理論的な意味をすべて引き継ぐ という考え方もあるが、それを厳密に行うのは実はかなりやっかい なことだし、実用的でもない。

データベースといっても、オブジェクトには一般的な検索方法は 存在しない。もしデータベースが欲しければ、 それは自分で実装しなくてはならない。(あるいは買ってきてもいいね)



Object in Perl

Perlのオブジェクトは、Package と無名データを結び付けることによって 作られる。 ( perlobj Perl のオブジェクト を参照すること、さらに、 perlbot Bag'o Object Tricks For Perl5 (the BOT) も見る方が良い。)

無名データをオブジェクトの持つ内部構造として、 これにオブジェクトの操作方法を記述した Package を対応させると Perl のオブジェクトができあがる。この二つを結び付けるのが bless という演算子 だある。

例えば猫のオブジェクトをPerlで記述すると、 cat.pl のようになる。


package Mammal;

sub new {
       my $type = shift;
       my %params = @_;
       my $self = {};
       $self->{'Name'} = $params{'Name'};
       $self->{'Sex'}  = $params{'Sex'};
       $self->{'Weight'}  = $params{'Weight'};
       $self->{'Color'}  = $params{'Color'};
       bless $self, $type;
}

package Cat;

@ISA = qw( Mammal );

sub new {
       my $type = shift;
       my %params = @_;
       my $self = Mammal->new(@_);
       $self->{'Character'}  = $params{'Character'};
       bless $self, $type;
}

# method の書き方

  sub miyao {   my ($self,$arg) = @_;    $self->{Name} = $arg; }

  sub name_print {   my ($self) = @_;    print $self->{Name}; print "\n";}

# 使い方

 $a = Cat->new(Name=> Jackey, Sex=>F);
 print $a->{Name};print "\n";
 $a->name_print;

のようになる。

問題

上に出てきた猫に、methodを付けてみよ。method は package で宣言される subroutine で、インスタンス変数を変更したり、印刷したりする。まず、 猫をたたくと怒るようにしてみよう。そして、怒ると鳴き声が変わるように してみよう。



カード

Perl5 で書いたカードの例題を見てみよう。 SimpleCard.pm SimpleCardPile.pm これらは、たとえば以下のようの使う。

foreach $suit ('s','h','d','c') { 
   for($i=1;$i<14;$i++) { 
     push(@card, CardPlay::SimpleCard->new(-suit=>$suit,-number=>$i)); 
   }
} 

$pile = CardPlay::SimpleCardPile->new(-contents=>\@card);

$pile->print;
$pile->shuffle;
$pile->print;
$pile->first->print;
$pile->last->print;



宿題

SimpleCardPile.pm を使って、カードを配布して、五枚づつ、5人のユーザに 配るプログラムを作成せよ。ポーカーの役の判定のプログラムを SimpleCardPile.pm に付加してみよ。
kono@ie.u-ryukyu.ac.jp まで、来週までにメールで送ること。 Subject には、 Software Engineering Lecture 5/18__ Perlの宿題 を付けること。

この講義の問題を提出する時には、 Subject: Practice on Software Engineering Lecture 5/11
とすること。