mocking singleton objects

7,655 views
Skip to first unread message

Korny Sietsma

unread,
Feb 2, 2011, 4:43:43 AM2/2/11
to scala-melb
I've seen this asked on stack overflow, with no answers apart from "you can't" - but I thought I'd try here as well.

I have a class Person, and a companion object Person.

The companion object includes an effectively-global function Person.listToJson that converts a list of Person objects to a json string.  (This isn't the perfect way to do this in the long run, but it suffices our needs at this early stage).

I want to unit test a MainFilter class that gets a list of Person objects from a data source, does some manipulation on them, then calls Person.listToJson and returns the resulting string.
As I'm testing MainFilter not Person, I want to mock out the actual behaviour of Person.listToJson() - that's not the class under test.

How do I do this?  We're using Specs and Mockito.  I know in theory you can test static objects in Java via Powermock or JMockit - is there some sort of equivalent in Scala?

- Korny (missing rspec already)

--
Kornelis Sietsma  korny at my surname dot com http://korny.info
"Every jumbled pile of person has a thinking part
that wonders what the part that isn't thinking
isn't thinking of"

Jeremy Mawson

unread,
Feb 2, 2011, 6:15:27 AM2/2/11
to scala...@googlegroups.com
Hi Korny

I personally can't answer your question as I've not been unfortunate enough to need mock singletons (for that's effectively what objects are) even in Java.

Looking at the issue more broadly. Firstly I'm surprised you can't just throw List[Person] at your JSON library and get what you need. What library are you using? Twitter, Lift or something else?

Secondly, I'd replace your static reference to listToJson with a function that you can mock/inject.

scala> case class Person(name: String)
defined class Person

scala> object Person {                                             
     |   def listToJson(l: List[Person]): String = "some json here"
     | }
defined module Person

scala> val listToJson = Person.listToJson _
listToJson: (List[Person]) => String = <function1>

(The underscore lifts the method to a function).

Then, in MainFilter you replace your static reference with a val of type (List[Person]) => String. You may need to refer to this as mock[Function1[List[Person], String] in Specs.

This functional approach will serve you much better than static references.

Cheers
Jem


> --
> You received this message because you are subscribed to the Google Groups
> "Melbourne Scala User Group" group.
> To post to this group, send an email to scala...@googlegroups.com.
> To unsubscribe from this group, send email to
> scala-melb+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/scala-melb?hl=en-GB.
>

Ken Scambler

unread,
Feb 2, 2011, 6:16:44 AM2/2/11
to scala...@googlegroups.com

In Java, Person.listToJson is a static call; it can't be abstracted, it's forever stuck in the global namespace. In Scala, the same call is to a value named Person whose class exposes a listToJson() method, which could come from any scope.

The Cake Pattern is one way to separate concerns, and swap out classes, objects, methods and values at compile time:


trait PersonComponent {
  trait PersonCompanion {def listToJson(): String}
  val Person: PersonCompanion
  class Person {...}
}

trait MainFilterComponent {
  context: PersonComponent => // Will not compile unless mixed into a PersonComponent, which exposes the Person object.
 
  class MainFilter {
    def doStuff() = Person.listToJson() // Obtained from our context, yet to be mixed-in.
  }
}


object ApplicationProd extends PersonComponent with MainFilterComponent {
  object Person extends PersonCompanion {
    def listToJson() = "correct result"
  }
}

object ApplicationTest extends PersonComponent with MainFilterComponent {
  object Person extends PersonCompanion {
    def listToJson() = "mock result"
  }
}

--

Jeremy Mawson

unread,
Feb 2, 2011, 6:44:47 AM2/2/11
to scala...@googlegroups.com
I was curious about whether you needed to use the type Function1[List[Person], String] or if you could use the shorthand (List[Person]) => String. Seems you can use the shorthand. Here's a complete implementation and spec.

case class Person(name: String)
object Person {
  def listToJson(lp: List[Person]) = "some actual implementation"
}

class ClassUnderTest(listToJson: (List[Person]) => String) {
  def testIt(lp: List[Person]) = listToJson(lp)
}

import org.specs._
import org.specs.mock.Mockito
import org.mockito.Matchers._  

class ASpec extends Specification with Mockito {
  "a thing" should {
    "do whatever" in {
      val m = mock[(List[Person]) => String]
      val subject = new ClassUnderTest(m)
      m(Nil) returns "mocked!"
      subject.testIt(Nil) must_== "mocked! (this will fail on purpose)"
    }
  }
}

=====================

[info] == ASpec ==
[error] x a thing should
[error]   x do whatever
[error]     'mocked![]' is not equal to 'mocked![ (this will fail on purpose)]' (ASpec.scala:21)
[info] == ASpec ==

=====================

PS: You can think of this as classic GoF Strategy pattern, but much more succinct.

PPS: You can embed the prod function as a default argument, only overriding it at test-time if that suits. In that case the ClassUnderTest becomes:
class ClassUnderTest(listToJson: (List[Person]) => String = Person.listToJson(_)) {
  def testIt(lp: List[Person]) = listToJson(lp)
}
and constructed simply as new ClassUnderTest it will get the default implementation of list[person] => string.

Cheers

Jem

Ben Hutchison

unread,
Feb 2, 2011, 4:59:15 PM2/2/11
to scala...@googlegroups.com
On Wed, Feb 2, 2011 at 8:43 PM, Korny Sietsma <ko...@sietsma.com> wrote:
> I have a class Person, and a companion object Person.
> The companion object includes an effectively-global function
> Person.listToJson that converts a list of Person objects to a json string.
... I want to mock out the actual

> behaviour of Person.listToJson() - that's not the class under test.
> How do I do this?

I dont think there is a way.

This illustrates an aspect of Scala's object keyword that's important
to understand: it refers to a particular fixed instance, not some type
that can be abstracted in any way. Thats a serious limitation and thus
objects should be referred to directly with care; there is no
capability to directly abstract over the reference (there are indirect
ways like Ken mentions).

Somewhat ironically, IMO this makes objects perhaps the least
"Object-oriented" feature in Scala. To me, OO-polymorphism is the
defining feature and the defining value of OO- methods in general, yet
Scala objects don't support polymorphic variation of their own
methods!

That leads us to ask "are Objects any better than static methods?" I
think so, in that they are true objects, albeit a fixed instance. That
enables them to /implement/ abstractions, if not /be/ abstractions
themselves:

object Person extends IPerson
val realPerson: IPerson
val mockPerson: IPerson = mock(IPerson)

> - Korny (missing rspec already)

Scala's classes are immutable, while Ruby's are mutable. Immutability
of classes is the only sane response if one uses a static type system
like Scala, or else all the types are suspect. OO- polymorphism
provides a disciplined way to publish and use runtime extension
points, while remaining consistent with a statically typed logic.

The choice of whether to use a statically typed language is a
fundamental one, that will deeply affect which designs, idioms and
processes prove effective in the project.

-Ben

Korny Sietsma

unread,
Feb 3, 2011, 2:57:46 AM2/3/11
to scala...@googlegroups.com
Thanks for all the suggestions, folks.

I think the problem I have with Ben's comments, and others here, is that I see unit testing as a fundamentally different world to the rest of the code.
I'm testing a well-designed unit of code (not that I'm suggesting Person.listToJson is well defined, it's just a nice concise example!), and I want to mock or stub out all it's dependencies.

This isn't something I'd ever want to do in the main code - so I don't want to have to distort my code in order to make it testable.  Yes, sometimes making code testable makes for a better design - but not always.  A massively more complex and less readable design, for a start, has an uphill battle if it wants me to think it's "better".

I'm hoping for something like PowerMock or JMockit, which realise that the world of testing is special, and use dynamic magic to affect the behaviour of code under test so it is actually easy to test.  But it seems like these options are not there yet.  For now, I'll just work around the problem.

(Note that we are already using a version of the cake pattern to hook up major dependencies in the system.  But the dependency on which implementation of "listToPerson" I want is not actually ever going to change in the real system - it is only ever going to change in the unit test world.  So it seems massive overkill to use it to inject an implementation of a relatively simple function) 

- Korny


--
You received this message because you are subscribed to the Google Groups "Melbourne Scala User Group" group.
To post to this group, send an email to scala...@googlegroups.com.
To unsubscribe from this group, send email to scala-melb+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scala-melb?hl=en-GB.

Korny Sietsma

unread,
Feb 3, 2011, 3:04:03 AM2/3/11
to scala...@googlegroups.com
Just a couple of notes on this:

We're using the lift-json libraries, and yes you can just serialize the List[Person] object, but it's a bit messy - it's a couple of lines of code, including defining a Serialization.formats implicit val; it was more than really belonged in the MainFilter class.

More importantly, this is only interim code.  Eventually we won't have a List[Person] being thrown around, there'll be a proper PersonCollection class (or something), with it's own mechanism for transforming it to json.  This is one of the reasons I'm a bit frustrated at not being able to do this simply - I wanted to put in a simple unit test for the code I have now, commit it, and move on, with the expectation that I'll probably throw the code and the test away within a few days.

- Korny

Ken Scambler

unread,
Feb 3, 2011, 5:11:25 AM2/3/11
to scala...@googlegroups.com

Some thoughts:

Stable identifiers (ie vals, objects, function parameters) are a key concept in Scala, and it would break the type system if you could swap them at runtime.  I can't really think how mocking objects would work.  Having said that, you can redefine vals, objects and classes in the REPL, so maybe you can do something like this running as a script.

Your predicament doesn't feel like a real problem to me.  It seems to me that your MainFilter class fundamentally has a dependency on "how to serialise a list of Persons to JSON", and in a project of any size, you would want this responsibility obtained/injected from elsewhere, as a function like Jeremy's example, or in some Jsonifier[List[Person]] class or some such.  Even if you consider testing to be a different world, this would seem to be a pretty straightforward separation of concerns for the code itself.

On the other hand, you've said this is a quick throwaway prototype, and you don't want to overengineer it; fair enough, but what do unit tests achieve on a throwaway prototype?

Also, can't you do something like this with Mockito? (Just guessing, because I haven't used it)

class MainFilter {
  def listToJson(list: List[Person]) = Person.listToJson(list) // All use of the external dependency is through this overridable method
  def doStuff() = listToJson(somePersonList)
}

val mfMock= mock(classOf[MainFilter])
when(mfMock.listToJson(myList)) thenReturn "mock result"  // Mock the method hiding the dependency

Cheers,
Ken


Jeremy Mawson

unread,
Feb 3, 2011, 5:24:59 AM2/3/11
to scala...@googlegroups.com
Hi Korny

The fact you need something like PowerMock indicates that you're not doing TDD. Change that and you won't have a problem. I understand it could and should be easier to write characterisation tests against legacy code, but it isn't yet.

And using functions is simple. Without functions, what you're doing is "Java without semicolons". Embrace the ƒ!

Cheers
Jem

Jeremy Mawson

unread,
Feb 3, 2011, 5:31:49 AM2/3/11
to scala...@googlegroups.com
Hi Ken

I think this is a fair approach, although I would put doStuff in a dedicated facade. However some people think this just moves the problem rather than solving it. I think it's a fine approach because at least you isolate the unmockable delegate from the mockable ones within MainFilter.

Personally I like to pass functions because they are first class values like any other and, in my mind, more succinctly capture the behaviour we want. For example.

class X {
  def a = 1
  def b = 2
  def c = 3
}

class Z(x: X) {
  val i = x.b
}

In Z I pass x, even though I ignore two of its methods. Perhaps it is better (stronger?) to say:

class Z(derivesI: () => Int) {
  val i = derivesI()
}

Just a thought.

Jem



--

Korny Sietsma

unread,
Feb 3, 2011, 5:48:02 AM2/3/11
to scala...@googlegroups.com

Wow. So all that rspec I wrote, that wasn't TDD either?

- K

On 03/02/2011 9:25 PM, "Jeremy Mawson" <jem.m...@gmail.com> wrote:

Hi Korny

The fact you need something like PowerMock indicates that you're not doing TDD. Change that and you won't have a problem. I understand it could and should be easier to write characterisation tests against legacy code, but it isn't yet.

And using functions is simple. Without functions, what you're doing is "Java without semicolons". Embrace the ƒ!

Cheers
Jem


On 3 February 2011 19:04, Korny Sietsma <ko...@sietsma.com> wrote:

>
> Just a couple of notes on this:
>

> We're using the lift-json libraries, and yes you can just se...

--

> You received this message because you are subscribed to the Google Groups "Melbourne Scala User Gr...


--
You received this message because you are subscribed to the Google Groups "Melbourne Scala User ...

Jeremy Mawson

unread,
Feb 3, 2011, 6:44:55 AM2/3/11
to scala...@googlegroups.com
But that's Ruby. You can get away with it in an untyped language.

You received this message because you are subscribed to the Google Groups "Melbourne Scala User Group" group.

Jeremy Mawson

unread,
Feb 3, 2011, 6:48:43 AM2/3/11
to scala...@googlegroups.com
My point is, you have an implementation and now you want to test it. The specific implementation you're trying to test would be testable in Ruby, but in Scala you've hit a snag. If it was test driven your design would have been different.

Ben Hutchison

unread,
Feb 3, 2011, 7:30:14 AM2/3/11
to scala...@googlegroups.com
On Thu, Feb 3, 2011 at 8:59 AM, Ben Hutchison <brhut...@gmail.com> wrote:
> ... Scala's object keyword...refers to a particular fixed instance, not some type

> that can be abstracted in any way. Thats a serious limitation and thus
> objects should be referred to directly with care; there is no
> capability to directly abstract over the reference
>

Despite the fact that what I said above is true (ie direct/bare refs
to Scala Objects are not abstractable, leading to downstream
consequences like difficulty with mocking), I think we all must agree
that its very damn /convenient/ to just refer to an object relative to
a global namespace.

Is there some way we can have our cake and eat it too?

For example, imagine we're using a library that exposes a useful
family of Foo objects, and we want to make a "normal" regular Foo in
our client code.

package com.acme
trait Foo
class StandardFoo extends Foo
object Foo {
def standardFoo: Foo = new StandardFoo
}

Its probably alot less fuss to write "com.acme.Foo.standardFoo" than
using a FooFactory obtained the Cake pattern (I still dont understand
it properly!) or injection solutions like Spring/Guice. But can we do
this, and still retain the flexibility to vary the impl of standardFoo
at runtime, such a returning a MockFoo?

My own response to this challenge has been to make methods of scala
objects "ultra-thin" - they immediately redirect to an implicit
parameter which is the true "foo factory":

package com.acme
class Foo
object Foo {
def standardFoo(implicit factory: FooFactory) = factory.newFoo

implicit object defaultFooFactory extends FooFactory {
def newFoo = new StandardFoo
}
}
trait FooFactory {
def newFoo: Foo
}

This allows us 3 nice things which are quite hard to all have at the same time:

1. We can create standardFoos very easily with "com.acme.Foo.standardFoo"
2. By default we will get a StandardFoo back without having to do anything
3. If we want to override the default FooFactory, we just need to have
an alternate FooFactory in implicit scope and the library will use it
preferentially.


Scala really can be a joy to discover :)

-Ben

Travis Dixon

unread,
Feb 3, 2011, 3:33:49 PM2/3/11
to scala...@googlegroups.com
You could probably write multiple implementations of the object in different folder structures and then compile against a different one for your test, however managing all the different compilation configurations seems like it'd be a bit of a pain.

The main place I'm coming from there is that the focus on scala seems to be "get it right at compile time then don't change it", and while we're all used to changing things at runtime for testing, it's not actually the requirement, the requirement is just that we should be able to isolate a particular component.

Just throwing out a half baked idea there :)


-Ben

Korny Sietsma

unread,
Feb 3, 2011, 3:46:07 PM2/3/11
to scala...@googlegroups.com
That looks quite nice - I'll give it a go.

- Korny

On Thu, Feb 3, 2011 at 11:30 PM, Ben Hutchison <brhut...@gmail.com> wrote:

-Ben

--
You received this message because you are subscribed to the Google Groups "Melbourne Scala User Group" group.
To post to this group, send an email to scala...@googlegroups.com.
To unsubscribe from this group, send email to scala-melb+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scala-melb?hl=en-GB.

Ken Scambler

unread,
Feb 3, 2011, 4:38:55 PM2/3/11
to scala...@googlegroups.com

This is quite nice!  I wonder how it would look if you used it everywhere? I suspect it would work fine, but 100 implicit dependencies floating around scares me a bit; working out implicit precedence in your head can be tricky.

On 03/02/2011 11:30 PM, "Ben Hutchison" <brhut...@gmail.com> wrote:

On Thu, Feb 3, 2011 at 8:59 AM, Ben Hutchison <brhut...@gmail.com> wrote:

> ... Scala's object keyword...refers to a particular fixed instance, not some type

> that can be abstracted in any way. Thats a serious limitation and thus

> objects should be referre...


-Ben

--
You received this message because you are subscribed to the Google Groups "Melbourne Scal...

Ben Hutchison

unread,
Feb 3, 2011, 7:58:37 PM2/3/11
to scala...@googlegroups.com
On Fri, Feb 4, 2011 at 8:38 AM, Ken Scambler <ken.sc...@gmail.com> wrote:
> This is quite nice!  I wonder how it would look if you used it everywhere?

Good question! Ive spent some time thinking and experimenting to try
to get an answer for that. Its fair to say there are some problems...

Consider for example the following code we might wish to
interaction-test (based on my earlier example code):

object SUT {
def happyFoo = Foo.standardFoo.beHappy()
}

(In the example unit test sketch below, I'll replace the implicit
param FooFactory with a function Unit=>Foo, (relative to my earlier
example) to make the code simpler)

val aHappyFoo = Foo.standardFoo
val mockFoo = mock(Foo)
//record expectation
expect(mockFoo.beHappy()).andReturn(aHappyFoo)
implicit val fooFactory = ()=> mockFoo
SUT.happyFoo.should_== aHappyFoo

This wont work without some extra changes :(. We need to get the
implicit fooFactory into scope in SUT, which requires its
co-operation:

object SUT {
def happyFoo(implicit fooFactory: ()=>Foo) = Foo.standardFoo.beHappy()
}

Ive tried this style out in a larger codebase, my fledgling
Vector/Matrices/Geometry library. There's a tendency to accumulate
implicit param "line-noise" in all the signatures. For example,

To make Polygon one must pass an implicit PolygonFactory "pf", but
also, "pf" needs to be passed an implicit LineFactory "lf", and "lf"
needs to be passed a VectorFactory, which needs to be passed a
Numeric[T]-like instance, and also a ClassManifest[T] if we wish to
instantiate any Array's of primitives. Sigh....

What Im currently investigating is whether all these implicit params,
which essentially define the "configuration" of the library, can be
rolled into a single Configuration implicit param that's threaded
around:

implicit object MyConfiguration {
implicit val PolygonFactory = ...
implicit val LineFactory = ...
implicit val VectorFactory = ...
}

Nothing definite yet...

As an aside, several weeks ago I was searching around for some prior
art to inform my design when I noticed paper circa 2005 by Oleg
Kiselyov, a much revered Haskell programmer, on a similar topic:

Functional Pearl: Implicit Configurations:
"The configurations problem is to propagate run-time preferences
throughout a program, allowing multiple concurrent configuration
sets to coexist safely under statically guaranteed separation. This
problem is common in all software systems, but particularly acute
in Haskell, where currently the most popular solution relies on unsafe
operations and compiler pragmas."
[http://www.cs.rutgers.edu/~ccshan/prepose/p1214-kiselyov.pdf]

I wont claim to understand it (yet). My takeaway is that the problem
is non-trivial and worthy of effort to find good solutions.

-Ben

Ken Scambler

unread,
Feb 6, 2011, 12:03:28 AM2/6/11
to scala...@googlegroups.com
I think some of these suggestions here are similar to some other conventional techniques, despite the use of Scala's syntactic conveniences. Some illustrative comparisons of DI techniques I've used:


1) Constructor injection, many parameters
class FooModule(files: FileContext, icons: IconContext, vectors: VectorContext)

This is nice in that the class only sees what it needs to see, but it's utterly unscalable.  The context parameters need to passed down to child entities, who need to pass it on to their child entities;  the end-point is an upside down pyramid, where your top-level components accept almost everything in constructor parameters and pass progressively smaller parameter lists down the chain.  Furthermore, if a component near the bottom of your stack needs a new dependency, it needs to be threaded through the constructor of each component back up the tree.  Maintaining the dependency graph swiftly becomes non-trivial.

Tantamount to this is using structural types in Scala:
class FooModule(context: {def files: FileContext; def icons: IconContext, vectors: VectorContext})
If anyone remembers the over-long rambling code example I posted to this list in late '09, it used this pattern; I swiftly abandoned it.

Also, using mixins has the same problem:
class FooModule(context: FileContext with IconContext with VectorContext)
For any new dependency at the bottom, it would have to be threaded into every constructor up the tree, albeit without adding more arguments.

Passing dependencies into every single method, not just at the constructor level, is an extreme example of this, I think.  Using implicit values doesn't really help, because you don't want decisions made about which implementations to import made willy-nilly through-out your stack;  you'd want to define it once at the top, say, as ProdVectors and ProdFiles or TestVectors and TestFiles, and have it trickle down throughout everything else.



2) Constructor injection, single parameter
class FooModule(context: AppContext)

The disadvantage here is that AppContext is a globally shared kitchen sink, and woe betide anyone who infects it with mutable state or side-effecting functionality.  Also, every module in the application will have access to far more buttons and levers than it needs, and in a team environment this could get messy.  However, other than the kitchen sink thing, it scales beautifully; nothing ever needs any more than one parameter, and you can add as many dependencies as you want to it, and only modify the code in one place. 

I favour this one when using C++ and Java, I can overlook its flaws. We can do better in Scala though.

Ben's later example is tantamount to this pattern:

implicit object MyConfiguration {
 implicit val PolygonFactory = ...
...
}


3) IoC containers like Guice, Spring, etc.
I confess an amount of distrust for IoC frameworks; you can marvel at absence of explicit coupling between your components, and later curse the invisible implicit coupling your code now has on pervasive and opaque algorithms and initialisation sequences in the background.  You generally need to be carefully aware of the graph structure of your dependencies.

Perhaps this is not so bad in the frameworks mentioned; I haven't used them in anger.  Using JBoss Seam's DI facility, I found this to be a major impediment to debugging and understanding our "simplified" code.   I'm willing to be persuaded if others have conflicting opinions; I note the new CDI-compatible version of Seam has completely ditched their old DI system.

Options 1 & 2, in comparison have the advantage of being direct and clear.



4) The Cake Pattern. 
I think I need to elaborate here on CP's benefits and drawbacks, as there seems to be some confusion about it.  It's manifestly absurd in simple examples like the OP's; why have 15 lines of scaffolding and twice as many classes to support 5 lines of real code?  Well; you wouldn't.  But if you have an application of any size, and one that will keep growing, then its advantages become compelling.

The Cake Pattern's greatest advantage is its scalability.  Scalability is a key motivating factor behind the design of Scala (hence the name!), and features like Self Types and Path Dependent Types are there to make it possible.  There's essentially no difference in your application's complexity between 2 components and 100 components; they are all sewn together at compile time, and you need not consider how to thread them through the graph at each point.

The Scala Compiler is a more complex piece of code than any of us are likely to produce in our lives, and it uses this capability extensively to elegantly integrate 100's of known components and an arbitrary number of future unknown plugins and add-ons.

Scalaz uses a similar but simpler structure, providing dozens of different features and modules, but bound together elegantly.

For Ben's example:

To make Polygon one must pass an implicit PolygonFactory "pf", but
also, "pf" needs to be passed an implicit LineFactory "lf", and "lf"
needs to be passed a VectorFactory, which needs to be passed a
Numeric[T]-like instance, and also a ClassManifest[T] if we wish to
instantiate any Array's of primitives. Sigh....
His problems evaporate like so:

trait PolygonContext {
  context: LineContext => // LineContext's dependencies are its problem; not our problem here.
 
  def polygonFactory[A]: List[(A,A)] => Polygon[A]

  class Polygon[+A]
  def polyFunc1(): Int
  def polyFunc2(): Int
}

trait LineContext {
  context: VectorFactory => // We don't care about VectorFactory's dependencies downstream either

  def lineFactory[A]: ((A, A), (A, A)) => Line[A]
  class Line[+A]
}

Everything only need mention its own direct dependencies; there is no geometric explosion in interactions between components.  The Self Type annotation  (selfLabel: SelfType1 with SelfTypeN =>  restOfClass) forces the compiler to ensure that this dependency will always be inherited/mixed into an instances of the context, without creating a fixed link to it in the compiled bytecode.  If Ben had 100 factories to share around in different combinations, each module would still only worry about the ones it directly needed.

It has almost all of the advantages and none of the disadvantages of the above approaches, plus some:
a) Scalability: Linear increase in interactions as number of components increases.
b) Entirely assembled at compile time.
c) Directness: the assembly is performed directly by you in your application object, and not hidden behind layers of abstraction and opaque framework magic.

However, there is the overhead of writing a redundantly named context/component/module trait around your functionality; it would be silly to do it for every class, and silly to do it for simple apps that don't need to scale in size; unfortunately, this is far more obvious than its benefits to a casual glance at a trivial use case.


5) The sweet spot
I've settled into a hybrid usage where I'm happy, my main modules all use the Cake pattern (as I demoed at a meeting a few months back), and so my application looks like

object MyApp
    with Icons
    with Images
    with ApplicationConfigModule
    with // ad infinitum {

  // cf. OP's original problem: This would otherwise be a static/global value. 
  // Modules that use it would have "ApplicationConfigModule" in their Self Type.
  override object ApplicationConfig {
     val defautSaveDir = readFromProperties("app.savedir")
     val defaultImageDir = readFromProperties("app.imagedir")
  }
  override val iconFactory = new IconFactory
  override val imageFactory = new ImageFactory
}


// And testing:
object UnitTestApp
  with Icons
  with Images
  with ApplicationConfigModule
  with // ad infinitum {

 override object ApplicationConfig {
    val defaultSaveDir = "fake"
    val defaultImageDir = "fake"
 }
 override val iconFactory = new MockIconFactory
 override val imageFactory = new MockImageFactory
}

However:  on lower levels of detail I use constructor injection, and just pass in the whole context:

class LowLevelImpl(context: Vectors with Lines) {
  import context._
 //...
}

trait SomeMajorModule {
  context: Vectors with Lines with Icons with Images with Files =>

  class MajorThing
  def majorFunc()
 
  val lowLevelImpl = new LowLevelmpl(context)
}

I've been very happy with this; I get all the advantages of Cake, and avoid cumbersome overuse with simple constructor injection.

I hope this has all been relevant enough to the topic at hand!

Cheers,
Ken

Ben Hutchison

unread,
Feb 6, 2011, 1:25:46 AM2/6/11
to scala...@googlegroups.com
Ken,

Thanks for your detailed explanation. Its good to have someone like
yourself who really gets the Cake pattern locally to learn off.

Cake seems to have the compile-time configuration problem pretty
nicely addressed. For configuration at /runtime/ however, I still feel
that implicit param approaches are likely to prove successful. It
comes down to point (b) in your list below. Is that a show stopper for
some use cases?

Eg If I publish a compiled library/component to Maven, or load it into
an OSGI container, then it might be too late for the component's
clients to use compile time configuration.

Maybe not, if eg the component was compiled "abstract" (eg with yet
unmet self-types), and I then compile some extra code to tie it into a
configuration at container load time, just before execution. Michael
During at Day Software (large Swiss vendor of Java content repos ala
Jackrabbit) might be thinking along these lines, based on a talk he
gave at Scaladays.

-Ben

Ken Scambler

unread,
Feb 6, 2011, 1:43:01 AM2/6/11
to scala...@googlegroups.com
Hi Ben,


Cake seems to have the compile-time configuration problem pretty
nicely addressed. For configuration at /runtime/ however, I still feel
that implicit param approaches are likely to prove successful. It
comes down to point (b) in your list below. Is that a show stopper for
some use cases?


Well in the example I provided, it is "run-time configured", at least in the sense conveyed by the paper you linked to earlier.  The linking of dependencies is all done at compile time, but you can still load properties files, etc, to fill in the blanks at run time, especially with lazy vals.

trait ApplicationConfigModule {
  // This is the "global" value everyone refers to
  val ApplicationConfig:  {val defaultSaveDir, defaultImageDir: String}
}

object MyApp with ApplicationConfigModule /* with etc */ {
  override object ApplicationConfig {
     // Initialises values at runtime, from properties files, etc!
     lazy val defaultSaveDir = readFromProperties("app.savedir")
     lazy val defaultImageDir = readFromProperties("app.imagedir")
  }
}

Cheers,
Ken
Reply all
Reply to author
Forward
0 new messages