Skip to content

Instantly share code, notes, and snippets.

@kjetilv
Created June 11, 2010 15:21
Show Gist options
  • Save kjetilv/434620 to your computer and use it in GitHub Desktop.
Save kjetilv/434620 to your computer and use it in GitHub Desktop.
A trait for setters or stupid, non-cascading objects in general
// A simple trait:
trait CascadingActions {
implicit def tToActioneerT[T](t: T) = Actioneer(t)
case class Actioneer[T](tee: T) {
def withAction(action: (T => Unit)): T =
withActions(action)
def withActions(actions: (T => Unit)*): T = {
actions foreach (_ (tee))
tee
}
}
}
// Yet with nice properties when you're dealing with
// an object that take a lot of setters, and you really
// wish it supported cascading:
def newStupid = {
val stupidTemporaryVariable = new StupidObject
stupidTemporaryVariable setSillyProperty "foo"
stupidTemporaryVariable setAnotherOne "bar"
stupidTemporaryVariable // mention it AGAIN here, just so it gets returned
}
// But instead:
def newStupid = new StupidObject withActions(
_ setSillyProperty "foo",
_ setAnotherOne "bar")
// Wow!
@retronym
Copy link

Cute hack, but this is almost as easy and a little more direct:

 val nso = new StupidObject
 {
  import nso._
  setSillyProperty "foo"
  setAnotherOne "bar"
}

@kjetilv
Copy link
Author

kjetilv commented Jun 11, 2010

Hmmm... did you try that? I typed in the following:

class StupidObject { 
    setFoo { 
        println("Foo") 
    }
} 
val nso = new StupidObject {
    import nso._
    setFoo
}
println(nso)

However, this made the compiler complain: illegal cyclic reference involving value

Removing the import fixes it, because what you are really doing is creating a subclass, right? But that fails if it's final. The compiler complains: illegal inheritance from final class StupidObject

I was a bit puzzled at first, because I couldn't see how the reference could be set to itself before it, well, imported itself. I may simply be confused, of course. Did you make it work?

@paulp
Copy link

paulp commented Jun 11, 2010

def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }

returning(new StupidObject)(x => { x setSillyProperty "foo" ; x setAnotherOne "bar" })

@retronym
Copy link

er, I meant:

class StupidObject {
  var sillyProperty: String = _
  var anotherOne: String = _
}

val nso = new StupidObject;

{
  import nso._
  sillyProperty = "foo"
  anotherOne = "bar"
}

@kjetilv
Copy link
Author

kjetilv commented Jun 11, 2010

That works too, although I think you mean

def returning[T](x: T)(f: T => Unit) = { f(x); x }

and for extra credit:

def returning[T](x: T)(fs: (T => Unit)*) = { fs foreach (_(x)); x }

or something.

@kjetilv
Copy link
Author

kjetilv commented Jun 11, 2010

@retronym: yes, that avoids the issue with StupidObject being final, and it doesn't introduce a new subclass. However, it is no longer a single expression, but is back to being a sequence of statements, the last one being the expression returned:

def newStupid {
    val nso = new StupidObject;
    {
        import nso._
        sillyProperty = "foo"
        anotherOne = "bar"
    }
    nso // ... and an expression at the end
}

@paulp
Copy link

paulp commented Jun 11, 2010

re "although I think you mean..." I meant exactly what I wrote; unfortunately the helpful markup processor betrayed me. If you look at the raw text you will see the untainted vision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment