Sawyer
Sawyer

Reputation: 15927

restrict implicit parameter resolution scope

I constantly find I need to write function with inner recursive helper function, and it takes the same parameter list as its outer function, but only an additional accumulator argument:

def encode(tree : Tree, text: String):String = {
    def rec(tree: Tree, text:String, result:String):String = ???

    rec(tree, text, "")
} 

I want to simplify this into :

def encode(tree : Tree, text: String)(implicit result:String = "" ):String

this can remove the inner function definition, but it has a problem of that, see if I need to call a function lookup inside encode, and lookup also takes implicit parameter of type String, the implicit result:String = "" implicitly pass to lookup function.

 def lookup(tree : Tree, text: String)(implicit result:String = "" ):String

I don't want this happen, is there a way to restrict the implicit parameter in lookup from resolving outside of that function? Or other better ideas?

Upvotes: 0

Views: 139

Answers (3)

gzm0
gzm0

Reputation: 14842

How about using a normal default argument instead and then passing the accumulator explicitly in the implementation:

def encode(tree : Tree, text: String, result : String = "" ): String = {
  //snip
  encode(new_tree, new_text, new_result)
}

// call
encode(my_tree, my_text)

Upvotes: 2

pagoda_5b
pagoda_5b

Reputation: 7383

Your idea is nice but the use of implicit parameters of such general type is discouraged, lest you stumble into implicit definition conflict (e.g. for too many implicit Strings visible in your scope).

IIRC, the book from Martin specifically mention such issues.

You could define an explicit Wrapper hierarchy class around your String, whose type changes for each specific method

abstract class Wrapper[A](value: A) { def apply(): A = value }

case class EncodeWrapper[A](value: A) extends Wrapper(value)
case class LookupWrapper[A](value: A) extends Wrapper(value)

def encode(tree : Tree, text: String)(implicit result: EncodeWrapper[String] = EncodeWrapper("") ):String

def lookup(tree : Tree, text: String)(implicit result: LookupWrapper[String] = LoodupWrapper("") ):String

with the obvious downside that you need to "wrap/unwrap" the String in the method body.

This could be mitigated through implicit conversion between the wrapper and wrapped types within the method, but it's still a bit clumsy, especially for very compact helper functions...

Of course everything simplifies when your method's return type is more specific and the probability for implicit collisions gets very low.

Upvotes: 0

cmbaxter
cmbaxter

Reputation: 35463

Have you considered supplying the implicit to lookup explicitly in that scenario. Like so:

def encode(tree : Tree, text: String)(implicit result:String = "" ):String = {
  lookup(tree, text)("other string")
}

Upvotes: 0

Related Questions