Scala: Why use an implicit function argument?

I have the following function:

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

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

 implicit val temp = 3 scala> getIntValue(3) res8: Int = 6 

I was wondering what are the advantages of the above declaration?

+7
scala implicit convention
source share
3 answers

Here is my “pragmatic” answer: you usually use currying as more “convention” than anything else meaningful. This is very convenient when your last parameter is 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 it is: "I have a function called transaction , its first parameter is Connection, and its second parameter will be a code block."

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

 transaction(myConn) { //code to execute in a transaction //the code block last executable statement must be a Boolean as per the second //parameter of the transaction method } 

If you did not use this transaction method, it would look rather unnatural:

 transaction(myConn, { //code block }) 

How about implicit ? Yes, this may seem like a very ambiguous design, but you get used to it after a while, and the nice thing about implicit functions is that they have domain definition rules. Thus, this means that for production you can define an implicit function to get this database connection from the PROD database, but in your integration test you will define an implicit function that will replace the PROD version, and it will be used to get the connection from the database DEV data instead for use in your test.

As an example, how about adding an implicit parameter to a 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, for example:

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

I can execute the transaction method as follows:

 transaction { //code to execute in transaction } 

and Scala will translate this:

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

In general, Implicits is a pretty good way of not forcing the developer to provide a value for the required parameter when this parameter is 99% of the time, which will be the same everywhere you use this function. For 1% of the time, when you need another connection, you can provide your own connection by passing a value instead of letting Scala determine which implicit function provides the value.

+4
source share

In your particular example, there are no practical advantages. In fact, using implicits for this task will only confuse your code.

The standard use for implicits is Type Class Pattern . I would say that this is the only practical case that is practically useful. In all other cases, it is better to have obvious things.

Here is an example class:

 // A typeclass trait Show[a] { def show(a: a): String } // Some data type case class Artist(name: String) // An instance of the `Show` typeclass for that data type implicit val artistShowInstance = new Show[Artist] { def show(a: Artist) = a.name } // A function that works for any type `a`, which has an instance of a class `Show` def showAListOfShowables[a](list: List[a])(implicit showInstance: Show[a]): String = list.view.map(showInstance.show).mkString(", ") // The following code outputs `Beatles, Michael Jackson, Rolling Stones` val list = List(Artist("Beatles"), Artist("Michael Jackson"), Artist("Rolling Stones")) println(showAListOfShowables(list)) 

This template comes from the Haskell functional programming language and has proven to be more practical than standard OO methods for writing modular and decoupled software. The main advantage of this is the extension of existing types with new functionality without changing them.

There are not as many details here as syntactic sugar, def instances, etc. This is a huge question and, fortunately, it has a lot of coverage on the Internet. Just google for the "scala type class".

+7
source share

There are many benefits beyond your example. I will give only one; at the same time, it is also a trick that you can use in certain cases.

Imagine that you are creating a trait that is a common container for other values, such as a list, set, tree, or something like that.

 trait MyContainer[A] { def containedValue:A } 

Now, at some point, it will be useful for you to iterate over all the elements of the contained value. Of course, this only makes sense if the contained value has an iterable type.

But since you want your class to be useful for all types, you do not want to limit A a Seq or Traversable type, or something like that. Basically, you need a method that says: "I can only be called if A is of type Seq ." And if someone calls it, say, MyContainer[Int] , this should lead to a compilation error.

It is possible. You need some evidence that A has a sequence type. And you can do this with Scala and implicit arguments:

 trait MyContainer[A] { def containedValue:A def aggregate[B](f:B=>B)(implicit ev:A=>Seq[B]):B = ev(containedValue) reduce f } 

So, if you call this method on MyContainer[Seq[Int]] , the compiler will look for the implicit Seq[Int]=>Seq[B] . This is very easy to solve for the compiler. Because there is a global implicit function called identity , and it is always in scope. Its type signature looks something like this: A=>A

It simply returns any argument passed to it.

I do not know what this template is called. (Can someone help?) But I think this is a convenient technique, which is sometimes useful. You can see a good example of this in the Scala library if you look at the signature of the Seq.sum method. In the case of sum , another type of implicit parameters is used; in this case, the implicit parameter indicates that the contained type is numeric, and therefore the sum can be built from all contained values.

This is not the only use of implications, and, of course, not the most noticeable, but I would say that this is an honorable mention. :-)

+4
source share

All Articles