0

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?

2
  • 1
    My intuition tells me this is not a good use of implicit parameter lists... Unfortunately, I cannot explain or justify the intuition. Commented May 2, 2013 at 16:54
  • @RandallSchulz Martin used this pattern in PIS 2nd P494. The maxListImpParm example, basically it means, the method has some additional information I want to pass, here the information is an accumulator. The problem here, is not this pattern, it happens anywhere you have implicit parameters, it just passed implicitly sometimes this is against my intention, if the lookup is not defined by me, I might have not known, the parameter had ever passed to it. Commented May 2, 2013 at 17:03

3 Answers 3

2

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)
Sign up to request clarification or add additional context in comments.

3 Comments

I thought default argument couldn't be omitted. My mistake~
The point is the API caller don't have the supply an accumulator and the method can be recursive without helper function.
@Sawyer I meant what is the point of supporting default arguments, if they cannot be omitted upon function call :)
0

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")
}

1 Comment

I can do this, but one of the purpose of the implicit argument for lookup is to let it be called without the second parameter list, nor should it, otherwise I would just define it as a normal parameter. Currently I did the same as you suggested, just wonder if there's a better approach.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.