This page is no longer maintained — Please continue to the home page at www.scala-lang.org

A way around cyclic reference restrictions to achieve default value effects?

No replies
John Ky
Joined: 2009-10-06,
User offline. Last seen 42 years 45 weeks ago.
Hi all,

The following code describes some immutable types:

case class AsnBmpString extends AsnCharacterString {
}

case class AsnBoolean(value: Boolean) {
}

object AsnBoolean extends AsnBoolean(false)

class AsnCharacterString extends AsnType {
}

abstract class AsnChoice extends AsnType {
}

abstract class AsnEnumeration extends AsnType {
  def toString: String
}

case class AsnGeneralString extends AsnCharacterString {
}

case class AsnGraphicString extends AsnCharacterString {
}

case class AsnIa5String extends AsnCharacterString {
}

case class AsnInteger(value: Long) extends AsnType {
}

object AsnInteger extends AsnInteger(0) {
}

case class AsnIso646String extends AsnCharacterString {
}

sealed case class AsnNull {
}

object AsnNull extends AsnNull

case class AsnNumericString extends AsnCharacterString {
}

case class AsnPrintableString(value: String) extends AsnCharacterString {
}

object AsnPrintableString extends AsnPrintableString("") {
}

case class AsnReal(value: Double) extends AsnType {
}

object AsnReal extends AsnReal(0.0) {
}

class AsnSequence extends AsnType {
}

class AsnSet extends AsnType {
}

case class AsnT61String extends AsnCharacterString {
}

case class AsnTeletexString extends AsnCharacterString {
}

trait AsnType {
}

case class AsnUniversalString extends AsnCharacterString {
}

case class AsnUtf8String extends AsnCharacterString {
}

case class AsnVideotexString extends AsnCharacterString {
}

case class AsnVisibleString extends AsnCharacterString {
}

  case class MySequence(
    field0: Option[AsnInteger],
    field1: AsnReal,
    field2: AsnPrintableString,
    field3: MyChoice
  ) extends AsnSequence {
    def field0(f: (Option[AsnInteger] => Option[AsnInteger])): MySequence = copy(field0 = f(field0))
    def field1(f: (AsnReal => AsnReal)): MySequence = copy(field1 = f(field1))
    def field2(f: (AsnPrintableString => AsnPrintableString)): MySequence = copy(field2 = f(field2))
    def field3(f: (MyChoice => MyChoice)): MySequence = copy(field3 = f(field3))
  }

  object MySequence extends MySequence(
    Some(AsnInteger),
    AsnReal,
    AsnPrintableString,
    MyChoice.default
  ) {
  }

  abstract class MyChoice extends AsnChoice {
    def _choice: Int

    def choice0: Option[AsnNull] = None

    def choice1: Option[AsnInteger] = None

    def choice2: Option[AsnReal] = None

    def choice0(f: (MyChoice => AsnNull)): MyChoice =
      MyChoice.Choice0(f(this))

    def choice1(f: (MyChoice => AsnInteger)): MyChoice =
      MyChoice.Choice1(f(this))

    def choice2(f: (MyChoice => AsnReal)): MyChoice =
      MyChoice.Choice2(f(this))
  }

  object MyChoice {
    object default extends Choice0(AsnNull)
   
    case class Choice0(_element: AsnNull) extends MyChoice {
      def _choice: Int = 0
     
      override def choice0: Option[AsnNull] = Some(_element)
    }
 
    case class Choice1(_element: AsnInteger) extends MyChoice {
      def _choice: Int = 1
     
      override def choice1: Option[AsnInteger] = Some(_element)
    }
 
    case class Choice2(_element: AsnReal) extends MyChoice {
      def _choice: Int = 2
     
      override def choice2: Option[AsnReal] = Some(_element)
    }
  }

  case class MyEnum(_value: Int) extends AsnEnumeration {
  }

  object MyEnum extends MyEnum(0) {
    def value0: MyEnum = MyEnum(0)
    def value1: MyEnum = MyEnum(1)
    def value2: MyEnum = MyEnum(2)
    def value3: MyEnum = MyEnum(3)
  }

It also lets me transform the immutable values easily:


    // Create a sequence, initialising all fields.
     val mySequence = MySequence(
        Some(AsnInteger(1)),
        AsnReal(1.0),
        AsnPrintableString("Hello world"),
        MyChoice.Choice1(AsnInteger(2)))

    // Create copy of sequence field0 and field1 initialised to different values
    val mySequence2 =
      ( mySequence
          .field0{
            case Some(AsnInteger(x)) => Some(AsnInteger(x + 2))
            case None => None
          }
          .field1{_ => AsnReal(3.0)}
      )
    println(mySequence2)
    println(mySequence2.field3._choice)
    println(mySequence.field3{_.choice2{_ => AsnReal(9.9)}})
    println(AsnNull)
    println(MySequence)
    println(MyChoice)
    // Using the MySequence constructor can be tedious because you need
    // always supply values for all fields.  An easier way to construct
    // the sequence is supported: MySequence is itself a value with
    // fields initialised to default values, so the alternative way to
    // construct objects is:
    val moo =
      ( MySequence
          .field0{_ => Some(AsnInteger(12))}
          .field1{_ => AsnReal(123.0)}
      )
    println(moo)
    println(moo.field3.choice2{_ => AsnReal(1.23)}._choice)
    println(MyEnum.value1)

However, for the choice type the need to write MyChoice.default instead of just MyChoice annoys me a lot and I am disallowed from fixing it by writing:

object MyChoice extends MyChoice.Choice0 {

The error is:

illegal cyclic reference involving object MyChoice    TestGeneratedCode.scala    /asn1runtimetest/src/test/asn1/genruntime    line 50    Scala Problem

Any other way I can do this?

Cheers,

-John


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland