Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Why use implicit on function argument?

I have a following function:

def getIntValue(x: Int)(implicit y: Int ) : Int = {x + y}

I see above declaration everywhere. I understand what above function is doing. It is a currying function which takes two arguments. If you omit the second argument, it will invoke implicit definition which returns int instead. So I think it is something very similar to defining a default value for the argument.

implicit val temp = 3

scala> getIntValue(3)
res8: Int = 6

I was wondering what are the benefits of above declaration?

like image 988
user_1357 Avatar asked May 08 '14 15:05

user_1357


People also ask

Why do we use implicit in Scala?

Implicit parameters are the parameters that are passed to a function with implicit keyword in Scala, which means the values will be taken from the context in which they are called.

What is implicit by the argument of a function?

An implicit argument of a function is an argument which can be inferred from contextual knowledge. There are different kinds of implicit arguments that can be considered implicit in different ways. There are also various commands to control the setting or the inference of implicit arguments.

How does Scala implicit work?

The implicit system in Scala allows the compiler to adjust code using a well-defined lookup mechanism. A programmer in Scala can leave out information that the compiler will attempt to infer at compile time. The Scala compiler can infer one of two situations: A method call or constructor with a missing parameter.

What is implicit object in Scala?

In Scala, objects and values are treated mostly the same. An implicit object can be thought of as a value which is found in the process of looking up an implicit of its type.


1 Answers

Here's my "pragmatic" answer: you typically use currying as more of a "convention" than anything else meaningful. It comes in really handy when your last parameter happens to be a "call by name" parameter (for example: : => Boolean):

def transaction(conn: Connection)(codeToExecuteInTransaction : => Boolean) = {

   conn.startTransaction  // start transaction

   val booleanResult = codeToExecuteInTransaction //invoke the code block they passed in

  //deal with errors and rollback if necessary, or commit
  //return connection to connection pool
}

What this is saying is "I have a function called transaction, its first parameter is a Connection and its second parameter will be a code-block".

This allows us to use this method like so (using the "I can use curly brace instead of parenthesis rule"):

transaction(myConn) {

   //code to execute in a transaction
  //the code block's last executable statement must be a Boolean as per the second
  //parameter of the transaction method

}

If you didn't curry that transaction method, it would look pretty unnatural doing this:

transaction(myConn, {

   //code block

})

How about implicit? Yes it can seem like a very ambiguous construct, but you get used to it after a while, and the nice thing about implicit functions is they have scoping rules. So this means for production, you might define an implicit function for getting that database connection from the PROD database, but in your integration test you'll define an implicit function that will superscede the PROD version, and it will be used to get a connection from a DEV database instead for use in your test.

As an example, how about we add an implicit parameter to the transaction method?

def transaction(implicit conn: Connection)(codeToExecuteInTransaction : => Boolean) = {

}

Now, assuming I have an implicit function somewhere in my code base that returns a Connection, like so:

def implicit getConnectionFromPool() : Connection = { ...}

I can execute the transaction method like so:

transaction {
   //code to execute in transaction
}

and Scala will translate that to:

transaction(getConnectionFromPool) {
  //code to execute in transaction
}

In summary, Implicits are a pretty nice way to not have to make the developer provide a value for a required parameter when that parameter is 99% of the time going to be the same everywhere you use the function. In that 1% of the time you need a different Connection, you can provide your own connection by passing in a value instead of letting Scala figure out which implicit function provides the value.

like image 107
ThaDon Avatar answered Oct 05 '22 10:10

ThaDon