4
votes

The following example from A Tour of Scala shows how implicit can be used to provide the appropriate missing members (add and unit) based on the type. The compiler will pick the right implicit object in scope. The library also uses that with List.sortBy and Ordering or List.sum and Numeric for instance.

However is the following usage in class B a valid/recommended usage of implicit parameters (as opposed to not using implicit in class A):

class I

class A {
  def foo(i:I) { bar(i) }
  def bar(i:I) { baz(i) }
  def baz(i:I) { println("A baz " + i) }
}
(new A).foo(new I)

class B {
  def foo(implicit i:I) { bar }
  def bar(implicit i:I) { baz }
  def baz(implicit i:I) { println("B baz " + i) }
}
(new B).foo(new I)

Where I primarily use the implicit to save myself some typing at the call site when passing a parameter along the stack.

2
Although valid according to language rules, personally, I wouldn't use implicits for these situations. I'd use them either to: 1) Change the behaviour of a method depending on the calling environment. 2) Impose a requirement on the call which depends on the type parameter of the surrounding class or the method itself. But, this is just my personal view when and how they should be used. Perhaps there are other valid and useful patterns.axel22

2 Answers

3
votes

It doesn't really look like an idiomatic use of implicits, which tend to be suited for type classes and dependency injection. There's absolutely no point in passing about a class with no members...

It's also more common to define an implicit val or object of type I before making the call to (new B).foo

Having said all that, you supplied an obviously a very abstract example. So it's not too hard to imagine a reasonable use-case for implicits that follows a similar pattern.

3
votes

This is very much a fine use case. I actually recommend this when scope determines the parameter to use. It provides an elegant way to pass some sort of context into a Plugin class so that utility functions will use the context. For example:

trait Context

object UtilityLib {
  def performHandyFunction(implicit x : Context) : SomeResult = ...
}

trait Plugin {
   def doYourThing(implicit ctx : Context) : Unit
}

class MyPlugin extends Plugin {
  def doYourThing(implicit ctx : Context) : Unit = {
    UtilityLib.performHandyFunction
  }
}

SomePluginAPI.register(new MyPlugin)

You can see an example in a database migration system I was toying. Check out the Migration class and its MigrationContext.