The implicit
keyword is a very obscure thing to programmers who come from Java and other languages like C
and C++
, so knowing about the implicit
keyword in Scala is very important. How is implicit
used in Scala?
Many may find it a duplicate of other post but it is not that. It is different.
Edit ::
Most of the times the question "What is the usage of implicits in Scala?" is answered in the sense of things like "how to write/use implicit conversions?", "how to use implicit type classes?" and so on.
For new Scala programmers (at least those I know), such answers most of the time put forward the impression that implicits
are actually just a "beautifying" tool to cut down things like,
val s = (new RichInt(5)).toString + ":: Well"
to just
val s = 5 + ":: Well"
And most of just treat implicit as nothing more than this shortening tool which they can always avoid if desired.
Some of the programmers with more "bare-metal" philosophy tend to even dislike the existence of implicit
which hides such details.
Somehow the important question which is "What is the "use and importance" of implicits
in Scala?" has somehow gone ignored and unanswered.
Specially programmers who know Scala enough to understand "how to use implicits
" to some extent and are sometimes trouble by the "hidden magic" wonder about the question - "What is so special about implicits that the Scala creators even choose to have implicits
?"
I am not very sure whether the OP also thought about these questions while exploring the implicits
as a Scala programmer.
And surprisingly, I have not found answers to these questions anywhere easily accessible. One reason is that answering even one of the use cases for the actual "need/benefits" of implicits
will require a lot of explanation.
I think these questions are worth the focus of community for helping the new Scala programmers. I have tried to simply explain one of the use cases for the implicits
. I hope to see more people (who are more knowledgeable) interested in answering this.
What
implicit
actually does.It is actually very simple,
implicit
does exactly what the name implies. It marks things as a "go to" instance/value in the corresponding scope, if there is ever a need to look for the "go to" instance of the said type.So we can say that an
implicit
instance/value of typeA
is the "go to" instance of typeA
whenever there is a need for a "go to" instance of typeA
.To mark any instance/value as
implicitly
("go to") available in corresponding scope, we need to useimplicit
keyword.How do we summon
implicit
instances/values when needed?Most direct way to summon an
implicit
is to useimplictly
method.Or we can define our
methods
withimplicit
parameters to expect the availability of animplicit
instance in the scope they are being used in,Keep in mind that we could have also defined the same method without specifying
implicit
parameter,Notice that the first choice with
implicit
parameter makes it clear to the user that themethod
expects implicit parameter. Because of this reason, theimplicit
parameter should be the choice in most cases (exceptions are always there).Why do we actually use
implicit
?This is a bit different from possible ways in which we can use
implicit
values. We are talking about why do we "actually" need to use them.The answer is to help the compiler with ascertaining
type
and help us in writing type-safe code for problems which will otherwise result in run-time type comparisons and we end up loosing all the help which the compiler can provide us with.Consider the following example,
Lets say we are using a library which has following types defined,
Considering that this is an open
trait
, you and anyone else can define their own classes to extend thisLibTrait
.Now, we want to define a
method
which works with only some of the implementations ofLibTrait
(only those having some particular properties and thus can perform that special behaviour which you need).But, the above will allow everything which extends
LibTrait
.One choice is to define methods for all of the "supported" classes. But since you don't control the extension of
LibTrait
, you can not even do that (it is also not a very elegant choice).Another choice is to model these "Restrictions" for your method,
Now, only subtypes of
LibTrait
supporting this particular behaviour will be able to come up with an implementation ofMyRestriction
.Now, in most simple way, you define your method using this,
So, now users first have to convert their
instances
to someimplementation
ofMyRestriction
(which will ensure that your restrictions are met).But looking at the signature of
performMySpecialBehaviour
you won't see any resemblance to what you actually wanted.Also, it seems that your restriction are bound to
class
and not the instances themselves, so we can just progress withtype class
usage.Users can define type-class
instance
for theirclass
and use your it with yourmethod
But looking at the signature of
performMySpecialBehaviour
you won't see any resemblance to what you actually wanted.But, if you were to use consider the use of
implicits
, we can bering more clarity to the usageBut I can still pass the type class instance as in impl_3. So why
implicit
?Yes, that is because the example problem is too simple. Lets add more to it.
Remember that the
LibTrait
is still open for extension. Lets consider you or someone in your team ended up having with following,Notice that
YoutTrait
is also an open trait.So, each of these will have their own corresponding instances for
MyRestriction
,And you have this other method, which calls
performMySpecialBehaviour
Now, how do you pick the
MyRestriction
instance to provide. The thing is, you can still do it in a round-about way by also providing aMap
withClass
as key andMyRestriction
instance as value for all yourtypes
. But it is an ugly hack it won't be effective at compile time.But if you use the
implict
basedimpl_4
, your the same method will look like this,And will work as long as the
MyRestriction
instances for all the subtypes forYoutTrait
are in scope. Otherwise the code will fail to compile.So, if someone adds a new subtype
YourTraitClassXX
ofYoutTrait
and forgets to ensure that theMyRestriction[YourTraitClassXX]
instance is defined and is made available in the scope where anyotherMethod
calls are being made, the code will fail to compile.This is just one example but it should suffice to show "why" and "what" are the actual uses of
implicits
in ScalaThere is so much more to say about
implicits
but that will make the answer too long; which it already is.The use case in this example, puts a bound on the parameter type
A
to have an instance oftype class
TypeClass[A]
in scope. It is calledContext Bound
and such methods are in general written as,Or,