Thread Rating:
  • 389 Vote(s) - 2.89 Average
  • 1
  • 2
  • 3
  • 4
  • 5
引数の定義はキーワードor位置 どちらがよい?
09-05-2013, 04:33 PM,
#1
引数の定義はキーワードor位置 どちらがよい?
引数の渡し方に関して、Curlでは位置引数と、キーワード引数の2種類ありますが、
ソースの可読性を考えると、複数の引数を渡す場合には、キーワード引数のほうが優れていると思っています。
キーワード自体が、その変数の意味をあらわしてくれるからです。

たとえば、花嫁と花婿を渡すと結婚する、というプロシージャを考えたとき、

Code:
{define-proc {marry1 bride:String, groom:String}:void}

位置引数(marry1 プロシージャ)だと、プログラマは、花嫁と花婿の順番を間違えやすいと思います。
(日本語だと「新郎・新婦」で順番が逆)

Code:
{define-proc {marry2 bride:#String = null, groom:#String = null}:void
    {if bride == null or groom == null then
        {error "花嫁(bride)と、花婿(groom)はどちらもnullを許可しません"}
    }
}

しかし、だからといって、キーワード引数(marry2 プロシージャ)にしてしまうと、
順番の間違いやすさがなくなるかわりに、初期値の指定が必要になります。
ここでは、花嫁、花婿が最初から決まっている、というのもおかしな話なので、 null を初期値にしましたが、
どちらかが不在のまま結婚はできないので、プロシージャのなかで null 判断をしています。

Code:
{define-proc {marry3
                 bride:String = {uninitialized-value-for-type String},
                 groom:String =  {uninitialized-value-for-type String}
             }:void
}
Nullable でない型を指定しようとすると、uninitialized-value-for-type を使う方法があると思いますが、
これも、結局は、初期化されないままの値が渡される可能性はあるので、
marry2 プロシージャ と同じ問題は残っています。

複数の引数を定義するとき、どのような実装がわかりやすいのでしょうか。
よいアイディアをお持ちの方がいらっしゃれば、アドバイスください。
09-05-2013, 05:21 PM,
#2
RE: 引数の定義はキーワードor位置 どちらがよい?
ワタスなら、こうかな・・・・。
Code:
{define-enum public Sex man, women}
{define-class public Person  
  field public-get name:String  
  field public-get sex:Sex  
  {constructor public {default name:String, sex:Sex}
     ....  
  }
}

{define-proc public {marry4 p1:Person, p2:Person}:void
     ....
}

|| 呼び出す。
{marry4 {"Nasu", Sex.man}, {"Bee", Sex.woman}}

いかがナス?

-B
09-05-2013, 07:46 PM,
#3
RE: 引数の定義はキーワードor位置 どちらがよい?
引数のクラスのフィールド値などで判断できるなら、確かに、ナスBさんの方法が言うことナスですね。


では、値や、型では判別できないものの場合はどうでしょうか。

たとえば、ある配列が、ある配列を満たすかどうかをチェックするプロシージャを考えたとき、
位置引数よりも、キーワード引数で、基準となる配列(standard)と、チェックする対象(target)と名前をつけたほうが、
どちらがどちらを満たすのか、わかりやすいと思います。

2つくらいであれば、位置引数でも、変数名の定義と、ヘルプの記述を行えば、
それほど混乱することはなさそうですが、
これが、3つ、4つと、同じ型で目的の異なる必須の引数が増えると、
さすがに位置引数ではわかりづらい気がします。

もともと、「必須の引数は位置引数」、「任意の引数は、キーワード引数」という考え方なのだと思いますが、
「必須の引数で、位置ではなく、可読性の高い渡し方はないか」ということです。


複数の必須引数を渡すような場合は、それらをまとめるクラスを作る、つまり、
nasuB さんのような渡し方をするのが望ましいのでしょうか。
09-14-2013, 11:40 AM,
#4
RE: 引数の定義はキーワードor位置 どちらがよい?
Either style can make sense, one note is that a clean way to do mandatory keyword arguments is to check if a keyword argument was supplied with {keyword-supplied?}
09-19-2013, 09:21 AM, (This post was last modified: 09-26-2013, 02:40 PM by umemura.)
#5
RE: 引数の定義はキーワードor位置 どちらがよい?
nasuBさん、wbardwellさん、アドバイスありがとうございます。

いまでは、私は、位置引数を利用するケースは下記の3つだと考えています。
・必須の場合
・ひとつのみの場合
・順番に意味がある場合

たとえば、Frameクラスであれば、「ひとつのみ」のグラフィックを受け取りますし、
VBox であれば、複数のオブジェクトをプログラマが意図した順番(=引数の順番)に並べます。

しかし、marry1プロシージャの場合「複数の引数」を「位置引数」で受け取りますが、
引数の順番はプロシージャ側が勝手に決めたものです。
プログラマが、誤った順番でコーディングしてしまった場合、
プログラマは、プロシージャ中身をドキュメント等で読み、仕様を理解しないといけません。
これは、プログラマにとって、使いづらいプロシージャです。

そのため、「複数で、かつ順番にはあまり意味がない引数」を渡す場合には、
どのような仕組みがよいのか、このスレッドで質問指させてもらいました。

私は、皆さんがこの問題をどのように解決しているのか興味があります。
もしかしたら、「複数で、かつ順番にはあまり意味がない引数」を渡さなければいけないような設計自体が間違っており、
もっとよい設計やデザインパターンがあるのではないかと期待しています。

今のところ、私は、「必須だが、複数で、かつ順番にはあまり意味がない引数」を渡す方法を以下の種類で考えています。

①引数に意味を持たせる・・・クラスでラップし、フィールドにフラグを持たせる、等
②キーワード引数を利用する
③引数をまとめた、受け渡し専用のクラスを作成し、利用する(チェックを行うのは②と同様)


①は nasuBさんの方法で、「順番に意味がないかわりに、引数の中に意味を持たせる」という方法です。
これには、プログラマが、より多くのクラスを意識する必要がある、という小さなデメリットと、
コードが非常に読みやすくなるという大きなメリットがあると思います。


②は、キーワード引数の名前で、引数の意味を表すことを目的としています。
引数の型はNullableにせず、初期値にuninitialized-value-for-type を利用します。
その引数の値が必須であれば、受け側でkeyword-supplied? を利用したチェックを行い、
指定されていなければエラーをスローします。

Code:
{define-proc public {calc-add
                        default:int = {uninitialized-value-for-type int},
                        target:int = {uninitialized-value-for-type int}
                    }:int
    def error-msg = "default と target には必ず値を指定してください"
    {assert {keyword-supplied? default}, error-msg}
    {assert {keyword-supplied? target}, error-msg}
    {return default + target}
}
{CommandButton
    label = "指定なし",
    {on Action do
        {popup-message {calc-add}}
    }
}
{CommandButton
    label = "片方のみ指定",
    {on Action do
        {popup-message {calc-add default = 10}}
    }
}
{CommandButton
    label = "正しく指定",
    {on Action do
        {popup-message {calc-add default = 3, target = 9}}
    }
}


③は、②とよく似ています。
受け渡し専用クラス(DTO)を用意し、値のチェックなどを、このクラスの中で行うことで、
プロシージャ内に余計なロジックを入れずに済みます。

ただし、②と③は、実行するまで、エラーになるのかどうかわからないことが問題です。

もっと良い方法や別のアイディアがあれば、アドバイスをいただけるとうれしいです。

Forum Jump:


Users browsing this thread:
1 Guest(s)

MyBB SQL Error

MyBB has experienced an internal SQL error and cannot continue.

SQL Error:
1017 - Can't find file: 'mybb_threadviews' (errno: 2)
Query:
INSERT INTO mybb_threadviews (tid) VALUES('963')