11

I want to do some funky closure-like stuff. I want a method to return an anonymous object whose guts make reference to the parameters of the method. Here is the code that I wrote that illustrates my intent:

object SessionManagement {

  implicit class SessionManagementExtensions( val c : ChainBuilder ) {

    def set( dest: String ) = object {

      def from( src: String ) =
        c.exec( session => {
          val list = session( src ).as[Vector[String]]
          val i = if ( list.size == 0 ) -1 else Random.nextInt( list.size )
          val value = if ( i > 0 ) list(i) else "INVALID_" + dest
          session.set( dest, value )
        })

      def to[T]( v: Expression[T] ) =
        c.exec( session => session.set( dest, v ) )

    }

}

What I'm TRYING to do is have a call to "set" return an object that allows me to then chain together a call to ".to", like so:

.set( SOMETHING ).to( OTHER )

But I can't say

def foo = object { ... }

Is there a way in Scala to get what I am after? Do I have to define a class and instantiate it?

John Arrowwood
  • 2,370
  • 2
  • 21
  • 32

2 Answers2

14

You can simply return a new anonymous object. Your syntax was almost right: just replace object by new:

def set( dest: String ) = new {
  def from( src: String ) =
    ...

  def to[T]( v: Expression[T] ) =
    ...
}

However, this will give a structural type at call site, which will have to use reflection to use the methods. To prevent this, define a trait with the API of your object:

trait SetResult {
  def from(src: String): ReturnTypeOfFrom
  def to[T](v: Expression[T]): ReturnTypeOfTo
}

def set( dest: String ): SetResult = new SetResult {
  def from( src: String ) =
    ...

  def to[T]( v: Expression[T] ) =
    ...
}

Note that I used ReturnTypeOfFrom and ReturnTypeOfSet because I've no idea what your methods return. Btw, this is a bad habit: public methods should always have an explicit result type.

sjrd
  • 21,805
  • 2
  • 61
  • 91
0

I'm not sure what you want to do, so hopefully this will give you starting point.
You can not have anonymous object but you can have inner objects, so you can do:

implicit class SessionManagementExtensions(val c: ChainBuilder) {

  object MyInnerObject {

    def from(src: String) =
      c.exec(session => {
        val list = session(src).as[Vector[String]]
        val i = if (list.size == 0) -1 else Random.nextInt(list.size)
        val value = if (i > 0) list(i) else "INVALID_" + dest
        session.set(dest, value)
      })

    def to[T](v: Expression[T]) =
      c.exec(session => session.set(dest, v))

  }

  def set(dest: String) = MyInnerObject

}
roterl
  • 1,883
  • 14
  • 24