オーバーロードはできません?(2)〜キーワード引数〜

オーバーロードを代替するcurlの機能紹介の第一回目はキーワード引数です。

キーワード引数とは、引数の名前と値のペアを指定して任意の順番で渡すことのできる仕組みです。そして、その引数は省略でき、省略された場合は決められた初期値が用いられます。


以下のような姓、名、年齢の3つの属性を持つPersonというクラスを考えます。

{define-class Person
  field first-name:String
  field last-name:String
  field age:int
}


インスタンスを生成するときに名前や年齢を設定できるよう以下のようなコンストラクタを定義できます。

{constructor {default
                 first-name:String = "",
                 last-name:String = "",
                 age:int = 0
             }
  set self.first-name = first-name
  set self.last-name = last-name
  set self.age = age
}


キーワード引数のおかげで、コンストラクタは上記1種類しかないにも関わらず以下のように様々な引数の与え方が可能となります。

{Person}
{Person first-name = "山田", last-name = "太郎"}
{Person age = 20}
{Person first-name = "山田", last-name = "太郎", age = 20}


キーワード引数がない言語の場合、上記のようなコンストラクタ呼び出しのバリエーションを実現するためには、(言語がサポートしているのであれば)オーバーロードを駆使して複数のコンストラクタを定義してやるほかありません。Javaであれば以下のようになるでしょう。

class Person{
	String firstName;
	String lastName;
	int age;
	Person(String firstName, String lastName, int age){
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
	}
	Person(){
		this("", "", 0);
	}
	Person(String firstName, String lastName){
		this(firstName, lastName, 0);
	}
	Person(int age){
		this("", "", age);
	}
}


これでJavaでも異なる引数でコンストラクタを呼び出せるようになります。しかし、これでは例えば「名(firstName)だけ指定してインスタンスを生成する」といったことはできません。キーワード引数を使ったcurlの例ではそもそもそういった問題はなく、これがキーワード引数の強力なメリットです。
この例では現在属性が3つしかありませんが、さらに性別と住所という属性を追加することを考えてみましょう。上記のJavaの例では事態は深刻です。なぜなら、属性の組み合わせの数が大きく増えるため、そもそもそれぞれの組み合わせに対応するコンストラクタを用意することが現実的ではなくなります*1


今回のような目的のためのオーバーロードは、キーワード引数のおかげでcurlでは必要ありません。それどころか、コンストラクタ定義はひとつで済んでおり、そのコードは量は少なく簡潔明瞭です。

*1:おそらくこのような場合はコンストラクタで初期値設定できる属性の組み合わせを限定し、残りはインスタンス化後にセッターメソッドを用いて値を設定させることになるでしょう