【しばらく編集不可モードで運営します】 編集(管理者用) | 差分 | 新規作成 | 一覧 | RSS | FrontPage | 検索 | 更新履歴

サブマリンパラメータ - かなり下位のルーチンでしか使われないパラメータをどうするか。

目次

かなり下位のルーチンでしか使われないパラメータをどうするか。 (途中の階層のルーチンはただ受け取って渡すだけ)

実例

Perlでwiki engineを書いていますが、表示系の部分で

main

という呼び出し関係があり、$book, $pageというパラメータはmainと_name_ref()でしか実際使いません。

Format::normal(), _format_inline() では使わない値を、ただ_name_ref()が必要だからというだけで受け渡ししているわけです。

スクリプトの概要

一つのCGIで複数のWikiを運営できるようなスクリプトです。 $book という変数は複数のWikiのそれぞれにつけられた名前を表します。

main

Format::normal($book, $page, $source);

_format_inline($book, $page, $source);

_name_ref($book, $page, $1, $2);

対策

ダイナミックスコープ変数の使用

言語がサポートしていれば、ですが。例えばEmacs-lispなら

  (defvar *book* nil)
  (defvar *page* nil)
  (defun format-normal (source)
    (format-inline source))
  (defun format-inline (source)
    (name-ref *book* *page* source))
  (defun name-ref (book page source)
    (message "%s %s %s" book page source))
  
  (let ((*book* "book")
        (*page* "page"))
    (format-normal "source"))

コンテキスト構造体を使う

下位ルーチンで使うパラメータを全部ひとつのコンテキスト構造体に 押し込んで、適宜参照する。Perlならhashtableでいいかも。

  参照
  name_ref($context->{book}, $context->{page}, $1, $2);
  
  呼び出す側
  Format::normal({book => "book", page => "page"}, $source);

副作用無しにするには、associative listを使う方法もある。 それならパラメータの変更はリストの前に非破壊的に追加するだけだから。

OOP機能を使う

package Format の各ルーチンを Format クラスのメソッドとして実装する。

main

 $format = Format->new($book, $page, $source);
 $format->normal();

Format::new

 my $self = shift;
 $self->{book} = shift;
 $self->{page} = shift;
 $self->{source} = shift;
 bless $self;

Format::normal

 $self->_format_inline();

Format::_format_inline

 $self->_name_ref($1, $2);

パッケージの各ルーチンは bless した Hash を暗黙の第一パラメータ($self)にとる。 意味的には、上のコンテキスト構造体とほとんど同じ。

コメント