前書き

数値 / 文字列 / 列挙型など、これらはcomparableという比較可能な型として用意されています。comparableは主に「=」で左右が一致するかを確認できます。例えば「猫」という文字列と「犬」という文字列がある場合、猫同士であれば「=」が成功しifなどの条件が実行され、猫と犬の比較であれば「=」が失敗しelse側の処理が実行されます。

この比較ができる特性から「配列」や「マップ」でもcomparableかどうかが重要となってきます。

例えば配列の機能でもある「Find」関数は、その配列内にまったく同じ文字列 / 数字などがあれば条件が成功し、そのインデックスを返すことができます。「まったく同じ」であるかの確認は当然「比較」であるため、Find関数はcomparableの型の配列にしか使えません。

マップに関しても同じで、マップは「カギ」と「要素」のペアで収納させる変数です。要素をセットしてあげて、必要な場面で「キー」を渡すと、マップ内のすべてのキーから検索し、それと関連付けられた「要素」を返してきます。この「キー」は比較可能なものでなければ配列からの検索ができません。

デフォルトのクラスは比較できない

長々と話してきましたが本題です。

pet := class:
    Name:string = "ペットの名前"
    Age:int = 5

このようなクラスを定義するとします。

もし、ある条件下でペット同士の比較がしたくなった場合

if:
    CheckPet = OwnedPet
then:
    Print("ペットを所有しています。")

のような「=」での比較をするでしょう。しかし、このままではVerse言語側でエラーとして扱われます。というのも、Verseで定義されたクラスはデフォルトで比較が行えないようになっています。

比較するために

では、どうすれば比較できるようになるかですが。

pet := class<unique>:
    Name:string = "ペットの名前"
    Age:int = 5

のように、classの後にunique指定子を付け足してあげます。すると、このクラスはcomparableとして扱われ、「=」を用いた比較が行えるようになります。

if:
    CheckPet = OwnedPet
then:
    #エラーが出なくなる
    Print("ペットを所有しています。")

例えばこのように比較を行ったり、

var IntPerPet:[pet]int = map{}
var PetArray:[]pet = array{}

if:
    Value := IntPerPet[TargetPet]
    Index := PetArray.Find[TargetPet]
then:

のようにマップや配列にして検索を行うこともできます。ここでの比較方法は、同じインスタンスであるかです。

使用例

pet := class<unique>:
    Name:string = ""

pet_manager_device := class(creative_device):
    var OwnedPetsPerAgent:[agent][]pet = array{}

    HasPet(InAgent:agent, InPet:pet)<transacts><decides>:void=
        PetArray := OwnedPetsPerAgent[InAgent]
        PetArray.Find[InPet]

使用する場面はそんなに多くはないかもしれませんが、一例として紹介します。例えばプレイヤーが所有しているペットを配列で一覧として保存し、HasPet関数で持っている場合はif文が成功するような機能を作る場合に便利です。

もしこれを<unique>を使わずに実装する場合

pet := class<unique>:
    ID:string = ""
    Name:string = ""

pet_manager_device := class(creative_device):
    var OwnedPetsPerAgent:[agent][]pet = array{}

    HasPet(InAgent:agent, InPet:pet):logic=
        if(PetArray := OwnedPetsPerAgent[InAgent]):
            for(PetElement : PetArray, PetElement.ID = InPet.ID):
                return true
        reutrn false

のようにクラス内に別の比較可能な変数を用意し、それと一致するかで確認となります。ケース・バイ・ケースでこちらの方が良い場合もありますが、標準APIの配列操作やその他のcomparableに対する関数が使えなくなるので、特別な理由がなければ<unique>の方が良いかもしれません。