読者です 読者をやめる 読者になる 読者になる

その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

Digest::MD5のもろもろに関して

Perl

第一部

まず,id:amagitakayosiさんのブログ記事に関しまして.
http://amagitakayosi.hatenablog.com/entry/2014/01/31/174915

これの結果がおかしいのは,普通に関数で呼び出すべき所をクラスメソッドみたいな感じで呼んでいる為です.これではclassがdigestの計算文字列として渡ってしまう.従って,下記のように修正すればちゃんと動きます.

この件については以上!!

第二部

Digest::MD5が提供しているOOPはそこまでメリット無いから使わなくても良いのじゃ,という話です.

例えば以下のように書いてみましょう.

hexdigest()メソッド等の,digest算出メソッドでdigestを計算すると,add($str)メソッドで指定した対象文字列がクリアされてしまいます.つまり,この例だと1回目のhexdigest()ではadd($str)で指定したfoobarを元にdigestを計算していますが,2回目のhexdigest()では文字列がクリアされてしまうので空文字列を元にdigestを計算してしまいます *1

従って,所望の機能を実現するためには以下のように書く必要があります.

digest計算のたびにadd($str)で計算対象文字列を指定してやらなきゃ駄目な訳ですね!
これだったらOOP使わずに普通に関数で呼んだほうが楽そうなイキフンが……


と思ったら牧さんが似たようなことを書かれてました.
http://lestrrat.ldblog.jp/archives/23704683.html


しかし,digest計算がオブジェクトの状態に対して破壊的な変更を行うというのは直感的ではない気がしますし *2OOPインタフェースにもそれほど便利なメソッドが生えているわけではないし,オブジェクトの状態はダイジェスト計算の度に吹き飛ぶし,だったらこれオブジェクトにしなくても良いし,それくらいなら関数でええやん,という様々な理由からDigest::MD5OOPインタフェースは使わず,関数を使った方が良いのではないか,という結論に達しました.ダイジェスト計算の度に文字列情報が揮発するのであれば,その文字列は引数として与えたほうが自然な気もしています.


ここらへん,空文字列でdigestを計算しようとしたら例外を投げてくれる,あるいは例外とはいかないまでも警告を出してくれるとかだったらハマる人減りそうで良いと思ったんですが,それやると後方互換がぶっ壊れるから大変そうですね……


[追記]
PerlのDigest::*名前空間のモジュールのOOPインターフェースはある程度統一されているので,様々なダイジェストを取り扱うメソッドなんかがあった時にそのメソッドにDigest::HogeHogeのインスタンスを渡してやれば,ポリモルフィズムを使ってワイワイできるので便利っちゃ便利.

[追記2]
勝手に自分の中でケリが付きました.

  • 基本的には関数を使う
  • OOPインタフェースは変なハマり方をする恐れがあるのでなるたけ使わない
  • ポリモルフィズムを使って他のDigestモジュールとワイワイやりたい時にのみOOPインタフェースを使う
  • もしもそういう実装になった時は一回外を走って頭冷やしてから考え直す

[追記3]
ケリは付いていなかった.コメント参照のこと.

*1:ここはドキュメント (https://metacpan.org/pod/Digest::MD5) にしっかり書かれていますね -> “Once it has been performed, the Digest::MD5 object is automatically reset and can be used to calculate another digest value. ”

*2:少なくとも僕には