4

I try to feel the advantage of implicit parameters in Scala. (EDITED: special case when anonymous function is used. Please look at the links in this question)

I try to make simple emulation based on this post. Where explained how Action works in PlayFramework. This also related to that.

The following code is for that purpose:

object ImplicitArguments extends App {

  implicit val intValue = 1 // this is exiting value to be passed implicitly to everyone who might use it

  def fun(block: Int=>String): String = { // we do not use _implicit_ here !
    block(2)  // ?? how to avoid passing '2' but make use of that would be passed implicitly ?
  }

  // here we use _implicit_ keyword to make it know that the value should be passed !
  val result = fun{ implicit intValue =>  {  // this is my 'block'
                         intValue.toString     // (which is anonymous function)
                       }
  }

 println(result) // prints 2

}

I want to get "1" printed.

How to avoid passing magic "2" but use "1" that was defined implicitly?

Also see the case where we do not use implicit in definition, but it is there, because of anonymous function passing with implicit.

EDITED: Just in case, I'm posting another example - simple emulation of how Play' Action works:

  object ImplicitArguments extends App {

  case class Request(msg:String)

  implicit val request = Request("my request")

  case class Result(msg:String)

  case class Action(result:Result)
  object Action {
    def apply(block:Request => Result):Action = {
     val result = block(...) // what should be here ??
     new Action(result)
    }
  }

  val action = Action { implicit request =>
    Result("Got request [" + request + "]")
  }

  println(action)

}
Community
  • 1
  • 1
ses
  • 13,174
  • 31
  • 123
  • 226
  • `block(2)` always gives 2 as the argument to `block`. Probably you don't understand definition of implicit parameters, not only how to "feel advantage". – Display Name Sep 17 '13 at 16:27
  • From the first lines of the [scala tutorial on implicit parameters](http://docs.scala-lang.org/tutorials/tour/implicit-parameters.html) "A method with implicit parameters can be applied to arguments just like a normal method. In this case the implicit label has no effect. However, if such a method misses arguments for its implicit parameters, such arguments will be automatically provided". It would be all kinds of confusing if an implicit parameter could override the behaviour of something you pass explicitly – Paolo Falabella Sep 17 '13 at 16:30
  • I know what I'm passing and I'm not wonder why it prints "2" (plz be patient when reading). There are several cases how implicit is used. Plz read those two links I provided. @Starge B. plz don't be too much personal. I'm sensitive :). – ses Sep 17 '13 at 16:34
  • regarding the part in the edit: your `implicit request` only puts the `request` into local implicit scope - meaning you can now call functions that take implicit request and compiler will plug it in. as for the `Action.apply` body... here you call the block with actual request....do the actual IO – edofic Sep 17 '13 at 17:24
  • Say, if in block(...) in apply() I would use implicitly[Request], then does not matter whether I use "implicit request" or not - it will use request that is defined implicitly somewhere. Even if I would pass my own request to Action { myOwnRequest =Result }. The puzzles me. I guess what I need just to use currying to pass my request as second parameter apply(...)(implicit request:Request) – ses Sep 17 '13 at 19:16

2 Answers2

6

Implicits don't work like this. There is no magic. They are just (usually) hidden parameters and are therefore resolved when invoking the function.

There are two ways to make your code work.

you can fix the implicit value for all invocations of fun

def fun(block: Int=>String): String = { 
  block(implicitly[Int]) 
}

implicitly is a function defined in Predef. Again no magic. Here's it's definition

def implicitly[A](implicit value: A) = value

But this means it will resolve the implicit value when declaring the fun and not for each invocation.

If you want to use different values for different invocations you will need to add the implicit paramter

def fun(block: Int=>String)(implicit value: Int): String = { 
  block(value) 
}

This will now depend on the implicit scope at the call site. And you can easily override it like this

val result = fun{ _.toString }(3)

and result will be "3" because of the explicit 3 at the end. There is, however, no way to magically change the fun from your declaration to fetch values from implicit scope.

I hope you understand implicits better now, they can be a bit tricky to wrap your head around at first.

edofic
  • 727
  • 8
  • 15
  • I've added an "edit" to the bottom my question. (still reading your answer) – ses Sep 17 '13 at 17:18
  • Ok. implicitly[Int] this is what I wanted. Do you think Play' Action uses implicitly as well? – ses Sep 17 '13 at 17:22
  • No. Play's `Action` is just a description of a computation. It get's executed with the real request that comes in from the network. Play is very functional in it's design. There are iteratees communicating with netty that produce the input, then Action is used as a function to transform the request into response and sent back through the same steps. *Very* roughly speaking. Play is open source and you can browse it on github https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/mvc/Action.scala – edofic Sep 17 '13 at 17:28
  • Then there is no sense to use "implicit" there "val action = Action { implicit request =>" because anyhow anyhow it will use "Request" implicitly due to "implicitly()" method inside the code – ses Sep 17 '13 at 18:16
0

It seems that for that particular case I asked, the answer might be like this:

That this is not really a good idea to use implicit intValue or implicit request along with implicitly() using only one parameter for the function that accept (anonymous) function.

Why not, because:

Say, if in block(...) in apply() I would use implicitly[Request], then it does not matter whether I use "implicit request" or not - it will use request that is defined implicitly somewhere. Even if I would pass my own request to Action { myOwnRequest =Result }.

For that particular case is better to use currying and two arguments and.. in the second argument - (first)(second) to use implicit

Like this:

def apply(block:Request => Result)(implicit request:Request):Action2

See my little effort around this example/use case here.


But, I don't see any good example so far in regards to how to use implicit by passing the (anonymous) function as argument (my initial question):

fun{ implicit intValue =>  {intValue.toString}

or that one (updated version):

val action = Action { implicit request =>
    Result("Got request [" + request + "]")
  }
ses
  • 13,174
  • 31
  • 123
  • 226