Tuple22 限界への対策

今年の初めに Scala の限界に関して書きました:

Scala は Tuple22 までしかサポートしません.

これは Scala が 22個のパラメータを超えた case class を定義できないことを意味します.22個を超えたパーティクルを持つシーケンスを含む複合型を定義するスキーマを扱えるよう回避策をいくつか用意しました.

まず,シーケンスが MaxParticleSize (20)個以上のパーティクルを持つとき,シーケンスを ChunkParticleSize (10)個ごとのチャンク(塊)に分けることにしました.例えば,30個の要素を持つシーケンスは 10個づつの要素を持った三つのチャンクに分かれます:

<xs:element name="foo">
  <xs:complexType>
   <xs:sequence>
     <xs:element name="string1" type="xs:string"/>
     <xs:element name="string2" type="xs:string"/>
     <xs:element name="string3" type="xs:string"/>
     ...
     <xs:element name="string30" type="xs:string"/>
   </xs:sequence>
  </xs:complexType>
</xs:element>

scalaxb は以上の要素から以下のコードを生成します:

case class Foo(arg1: FooSequence2,
  arg2: FooSequence3,
  arg3: FooSequence4) {
  def string1 = arg1.string1
  def string2 = arg1.string2
  def string3 = arg1.string3
  def string4 = arg1.string4
  def string5 = arg1.string5
  def string6 = arg1.string6
  def string7 = arg1.string7
  def string8 = arg1.string8
  def string9 = arg1.string9
  def string10 = arg1.string10
  def string11 = arg2.string11
  def string12 = arg2.string12
  def string13 = arg2.string13
  def string14 = arg2.string14
  def string15 = arg2.string15
  def string16 = arg2.string16
  def string17 = arg2.string17
  def string18 = arg2.string18
  def string19 = arg2.string19
  def string20 = arg2.string20
  def string21 = arg3.string21
  def string22 = arg3.string22
  def string23 = arg3.string23
  def string24 = arg3.string24
  def string25 = arg3.string25
  def string26 = arg3.string26
  def string27 = arg3.string27
  def string28 = arg3.string28
  def string29 = arg3.string29
  def string30 = arg3.string30
}
 
case class FooSequence2(string1: String,
  string2: String,
  string3: String,
  string4: String,
  string5: String,
  string6: String,
  string7: String,
  string8: String,
  string9: String,
  string10: String)
 
case class FooSequence3(string11: String,
  string12: String,
  string13: String,
  string14: String,
  string15: String,
  string16: String,
  string17: String,
  string18: String,
  string19: String,
  string20: String)
 
case class FooSequence4(string21: String,
  string22: String,
  string23: String,
  string24: String,
  string25: String,
  string26: String,
  string27: String,
  string28: String,
  string29: String,
  string30: String)

拡張によって複合型が 22個のパーティクルを超えることがあります.XML Schema は型システムの継承に似て,複合型を他の型から拡張することができます.一方,case class を継承することはできません.

 <xs:complexType name="barOne">
   <xs:sequence>
     <xs:element name="int1" type="xs:int"/>
     <xs:element name="int2" type="xs:int"/>
     <xs:element name="int3" type="xs:int"/>
     <xs:element name="int4" type="xs:int"/>
     <xs:element name="int5" type="xs:int"/>
     <xs:element name="int6" type="xs:int"/>
     <xs:element name="int7" type="xs:int"/>
     <xs:element name="int8" type="xs:int"/>
     <xs:element name="int9" type="xs:int"/>
     <xs:element name="int10" type="xs:int"/>
   </xs:sequence>
 </xs:complexType>

 <xs:complexType name="barTwo">
   <xs:complexContent>
          <xs:extension base="barOne">
        <xs:sequence>
         <xs:element name="int11" type="xs:int"/>
         <xs:element name="int12" type="xs:int"/>
         <xs:element name="int13" type="xs:int"/>
         <xs:element name="int14" type="xs:int"/>
         <xs:element name="int15" type="xs:int"/>
         <xs:element name="int16" type="xs:int"/>
         <xs:element name="int17" type="xs:int"/>
         <xs:element name="int18" type="xs:int"/>
         <xs:element name="int19" type="xs:int"/>
         <xs:element name="int20" type="xs:int"/>
       </xs:sequence>
     </xs:extension>
   </xs:complexContent>
 </xs:complexType>

<xs:complexType name="barThree">
  <xs:complexContent>
         <xs:extension base="barTwo">
      <xs:sequence>
        <xs:element name="int21" type="xs:int"/>
        <xs:element name="int22" type="xs:int"/>
        <xs:element name="int23" type="xs:int"/>
        <xs:element name="int24" type="xs:int"/>
        <xs:element name="int25" type="xs:int"/>
        <xs:element name="int26" type="xs:int"/>
        <xs:element name="int27" type="xs:int"/>
        <xs:element name="int28" type="xs:int"/>
        <xs:element name="int29" type="xs:int"/>
        <xs:element name="int30" type="xs:int"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

通常 barThree は 30個のパラメータを持った違法な case class を生成します.複合型の一つを別の case class に追い出すことで回避することができますが,scalaxb はどれを選ぶかを知り得ません.ここで登場するのが --wrap-contents です.このオプションを使うことでどの複合型を追い出すかを指定することができます.以下が --wrap-contents BarOne を使って scalaxb によって生成したものです:

case class BarThree(arg1: BarOnableSequence2,
  int11: Int,
  int12: Int,
  int13: Int,
  int14: Int,
  int15: Int,
  int16: Int,
  int17: Int,
  int18: Int,
  int19: Int,
  int20: Int,
  int21: Int,
  int22: Int,
  int23: Int,
  int24: Int,
  int25: Int,
  int26: Int,
  int27: Int,
  int28: Int,
  int29: Int,
  int30: Int) extends BarTwoable {
  def int1 = arg1.int1
  def int2 = arg1.int2
  def int3 = arg1.int3
  def int4 = arg1.int4
  def int5 = arg1.int5
  def int6 = arg1.int6
  def int7 = arg1.int7
  def int8 = arg1.int8
  def int9 = arg1.int9
  def int10 = arg1.int10
}