how implicit keyword works in scala? [duplicate] - scala

This question already has answers here:
Understanding implicit in Scala
(7 answers)
Closed 7 months ago.
I'm new in Scala but familiar with Java.
Please check this two methods
def jsonPar(name:String): ScallaopOption[Map[String, Map[String, String]]] : opt[Map[String, Map[String, String]]](name,required = true)(jsonMapper)
def jsonMapper : ValueConverter[Map[String, Map[String, String]]] =
scallop.singleArgConverter(json)
now there is opt method in ScallopConfBase class
def opt[A](name : scala.Predef.String, short : scala.Char, and so on upto 10 more params)(implicit conv : org.rogach.scallop.ValueConverter[A]) : org.rogach.scallop.ScallopopOption[A]
I'm stuck this code to understand, here are my concerns
opt needs to have 10 input params to execute, but in def jsonPar, only (name,required = true) is passed to opt, how ?
what's a importance of adding (implicit conv : org.rogach.scallop.ValueConverter[A]) : org.rogach.scallop.ScallopopOption[A] in opt method ?
what ScallaopOption[Map[String, Map[String, String]]] : opt[Map[String, Map[String, String]]](name,required = true)(jsonMapper) part is doing ?
can anyone share ? I'm trying to thing from java perspective, but still not able to understand.

Broadly, what implicit does is provide hints to the compiler to use when normal compilation fails.
For example, implicit conversions (which shouldn't generally be used) and implicit classes come into play when you try to call a method on an object whose type doesn't include that method. In that scenario, the compiler will, rather than reject the code immediately, search for an implicit conversion to a type which has that method and include a call to that conversion so that the method can be called. implicit classes work similarly (and use basically the same mechanism under the hood) as implicit conversions: if there's an implicit class available which can take that object as a constructor parameter, the compiler will effectively insert a new ImplicitClassName(originalObject).methodThatDoesntExistOnOriginalObject(...).
implicit parameters meanwhile rely on the idea of an implicit scope. If there's no explicitly provided argument for the implicit parameter, then the compiler will use an argument of that type from the implicit scope of the caller. Inside the method taking the implicit parameter, those parameters become part of the implicit scope so that that method can make calls using implicits.
The : ScallopOption[Map[String, Map[String, String]]] just means that the method returns a ScallopOption[Map[String, Map[String, String]]]. : ScallaopOption[Map[String, Map[String, String]]] : opt is not valid Scala; I suspect that the second : is an =.
You haven't provided the definition of opt, but it looks like it uses default parameters, so explicit parameters can be omitted in favor of the default values.

Related

Implicit Map makes Char methods not compile

So with this code the head and exists methods are not returning a Char but a String so i can't use any Char method.
implicit val mapTest: Map[String, Set[String]] = Map(
"foo" -> Set("foo")
)
val stringTest: String = "test"
//This don't compile
stringTest.head.isLetter
stringTest.exists(_.isLetter)
If i remove the implicit, it works fine. It works fine if i change the Map definition to Map[String, String], but using any Collection in the map makes is not compile.
Is there a way to make it work? I also tried defining the Char type after calling head but it still fails
Don't expose mapTest in implicit scope: as it offers .apply(key: String): Set[String] it's considered as an implicit conversion String => Set[String] .
Anyway implicit conversion should be defined/used with caution, due to readability drawbacks.
Using .head (or .get) is a code smell.
Implicit conversions may lead to seemingly magical changes to semantics of the code and loss of control by the developer, which your example nicely demonstrates. For this reason they are often discouraged and we are advised to find ways to refactor the code to not use them if at all possible.
If there is no way around it, consider moving the implicit conversion "out-of-scope" by wrapping it in another object like so
object FooImplicits {
implicit def mapTest: Map[String, Set[String]] = Map(
"foo" -> Set("foo")
)
}
and then try to avoid importing them at the top level, but instead import FooImplicits._ only where it is absolutely necessary.
Note that implicits are acceptable when defining typeclasses and extension methods.

Scala - calling a method with generic type parameter given a string value that determines the correct type

I am designing an API interface in a 2-tier architecture. It takes a string parameter fieldName from URL and returns a JSON string. fieldName refers to a field in my database table. You can think of its signature as:
def controller(fieldName: String): String
In the controller, I would like to call a method in my data access layer to perform the following query:
SELECT fieldName, SUM(salary) FROM Employee GROUP BY fieldName
because the type of the field varies, the type of the query result will be different. This method is parametrized by a generic type parameter T which corresponds to the type of the field with name fieldName.
def getTotalSalaryByField[T](fieldName: String): Map[T, Long]
if fieldName is "age", T should be Int.
if fieldName is "name", T should be String.
and so on.
given a particular fieldName at runtime, how do I call this method giving it the correct type?
I don't want to write a lot of if-else or pattern matching statements to select the type. It would look like this:
fieldName match {
case "age" => serializeToJson(getTotalSalaryByField[Int]("age"))
case "name" => serializeToJson(getTotalSalaryByField[String]("name"))
...
// 100 more for 100 more fields
}
This is ugly. If I were to write this in Python, it will take only one line:
json.dumps(getTotalSalaryByField(fieldName))
Is Scala somehow not suitable for rest backend programming? because this seems to be a common pattern people will encounter, and static typing gets in the way. I would like to see some suggestions as to how I should approach the whole problem in scala-ish way, even if it means remodeling, rewriting the DAL and controllers.
EDIT:
#drexin, the actual signature of the DAL method is
def myDAOMethod[T](tf: Option[TimeFilter], cf: CrossFilter)
(implicit attr: XFAttribute[T]): Map[T, Long]
T is the type of fieldName. Long is the type of y. As you can see, I need to select a type to be T based on fieldName from url parameter.
EDIT:
added some code and made the usecase clear
There is a difference between knowing the type of a variable at compile time and at runtime.
If the fieldName is not known at compile time (i.e. it's a parameter), and if the type of the column varies by fieldName, then you are not going to be able to specify the return type of the method at compile time.
You will need to use a DAO method that returns AnyRef, rather than one which returns T for a compile-time-specified type T.
Old answer:
The database access library can return the values without needing to know their type, and your code needs to do the same.
You are looking to use a DAO method which takes a type param T:
def myDAOMethod[T](tf: Option[TimeFilter], cf: CrossFilter)
(implicit attr: XFAttribute[T]): Map[T, Long]
... but as you state, you don't know the type T in advance, so this method is inapplicable. (T is used to convert the database column data into a String or an Int).
Your DAO should offer an untyped version of this method, something more like:
def doSelect(tf: Option[TimeFilter], cf: CrossFilter): Map[AnyRef, Long]
What database access library are you using?
If you are using Play framework then I would recommend you to use Play JSON APIs.
https://www.playframework.com/documentation/2.1.1/ScalaJson
Instead of
def getTotalSalaryByField[T](fieldName: String): Map[T, Long] = ???
you can write
def getTotalSalaryByField(fieldName: String): Map[JsValue, Long] = ???
since all types like JsNumber, JsString, JsNull are inherit from the generic JSON trait, JsValue.
wrap your queryResult with Json.toJson()
OR
def getTotalSalaryByField(fieldName: String): JsObject = ???
I think you have three options here:
use pattern matching (which is something you wanted to avoid)
use AnyRef and then try to guess proper type at runtime; maybe serializeToJson can do it itself?
use Type Providers: http://docs.scala-lang.org/overviews/macros/typeproviders.html
Third option is probably what you are looking for, but it bases on experimental scala features (i.e. macros). What I imagine it would be doing is connecting to your database during the compilation phase and inspecting the schema. If you are generating schema using some separate sql file(s) then it should be even easier. Then macro will generate all boilerplate with proper types hard-coded.
Probably you won't find working example for exactly what you need but there is one for RFC files which you can use as inspiration: https://github.com/travisbrown/type-provider-examples
I'm not 100% sure I understand your question, so apologies if I'm answering something else entirely.
You need Scala to be able to guess the type of your field based on the expected return type. That is, in the following code:
val result : Map[String, Long] = myDAOMethod(tf, cf)
You expect Scala to correctly infer that since you want a Map[String, Long], your x variable is of type T.
It seems to me that you already have everything you need for that. I do not know what XFAttribute[T] is, but I suspect it allows you to transform entries in a result set to instances of type T.
What's more, you've already declared it as a implicit parameter.
Provided you have an implicit XFAttribute[String] in scope, then, the previous code should compile, run, and be type-safe.
As a small improvement, I'd change the signature of your method to use context bounds, but that's primarily a matter of taste:
// Declare the implicit "parsers"
implicit val IntAttribute: XFAttribute[Int] = ???
implicit val StringAttribute: XFAttribute[String] = ???
// Empty implementation, fill it with your actual code.
def myDAOMethod[T: XFAttribute](tf: Option[TimeFilter], cf: CrossFilter): Map[T, Long] = ???
// Scala will look for an implicit XFAttribute[Int] in scope, and find IntAttribute.
val ages: Map[Int, Long] = myDAOMethod(tf, cf)
// Scala will look for an implicit XFAttribute[String] in scope, and find StringAttribute.
val names: Map[String, Long] = myDAOMethod(tf, cf)
I'm not sure whether your question implies that you'd also like to strongly tie the String "age" to the type Int. That's also possible, of course, but it's another answer entirely and I don't want to pollute this question with unnecessary rambling.

Implicit String conversion in scala doesnt compile

I've attempted to implement an implicit string conversion, as an experiment with creating scala object "factories", for example, in this case, I'd like to create an employee object from a string.
implicit def s2act(name: String) = new Actor[Employee](){
override def toString() : String = {
name
}
};
//two failed attempts at leveraging the implicit conversion below...
processActor("jim")
def boss : Actor = new String("Jim");
However, the above implicit binding fails to be identified by the compiler. Why does the compiler fail to process this implicit binding?
It seems to me that the error you should get from your code is that "class Actor takes type parameters".
a more correct code will be :
def boss : Actor[Employee] = new String("Jim");
I don't know what's the signature of processActor, but judging from the signature of boss I think the problem is you don't provide type parameter to Actor.
Actor itself is a type constructor, which means that it takes a type to construct a new type.
Actor is not a type, and you cannot use it in your function/method signature, but Actor[Employee] is a type.
Change your boss to this
def boss: Actor[Employee] = new String("Jim")
Related post: What is a higher kinded type in Scala?

Can structural typing work with generics?

I have an interface defined using a structural type like this:
trait Foo {
def collection: {
def apply(a: Int) : String
def values() : collection.Iterable[String]
}
}
}
I wanted to have one of the implementers of this interface do so using a standard mutable HashMap:
class Bar {
val collection: HashMap[Int, String] = HashMap[Int, String]()
}
It compiles, but at runtime I get a NoSuchMethod exception when referring a Bar instance through a Foo typed variable. Dumping out the object's methods via reflection I see that the HashMap's apply method takes an Object due to type erasure, and there's some crazily renamed generated apply method that does take an int. Is there a way to make generics work with structural types? Note in this particular case I was able to solve my problem using an actual trait instead of a structural type and that is overall much cleaner.
Short answer is that the apply method parameter is causing you grief because it requires some implicit conversions of the parameter (Int => Integer). Implicits are resolved at compile time, the NoSuchMethodException is likely a result of these missing implicits.
Attempt to use the values method and it should work since there are no implicits being used.
I've attempted to find a way to make this example work but have had no success so far.

Could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]

It seems I don't understand something important, maybe about erasure (damn it).
I have a method, which I wanted to create array of size n filled with values from gen:
def testArray[T](n: Int, gen: =>T) {
val arr = Array.fill(n)(gen)
...
}
And use it, for example as:
testArray(10, util.Random.nextInt(10))
But I get error:
scala: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
val arr = Array.fill(n)(gen)
^
Please, explain what I did wrong, why this error, and what kind of code it makes impossible?
That is because in testArray the concrete type of T is not known at compile time. Your signature has to look like def testArray[T : ClassManifest](n: Int, gen: =>T), this will add an implicit parameter of type ClassManifest[T] to your method, that is automatically passed to the call of testArray and then further passed to the Array.fill call. This is called a context bound.
The Array.fill method has the following signature:
def fill[T](n: Int)(elem: => T)(implicit arg0: ClassManifest[T]): Array[T]
In order to get an instance of ClassManifest[T] you need to know the concrete type. A ClassManifest can be obtained like this:
implicitly[ClassManifest[String]]
A ClassManifest is implicitly available for every concrete type.
For any implicit error, you can add the implicits you require to the method with the type parameter:
def wrap[T](n:Int)(elem: => T)(implicit c:ClassManifest[T], o:Ordering[T])
If you did not yourself introduce ClassManifest or Ordering, the writers of the library have (most likely) provided sensible defaults for you.
If you would call the wrap method:
wrap(2)(3)
It's expanded like this:
wrap[Int](2)(3)(implicitly[ClassManifest[Int]], implicitly[Ordering[Int]])
If you introduced a custom class Person here, you would get an error for not finding an implicit instance of Ordering[Person]. The writers of the library could not have known how to order Person. You could solve that like this:
class Person
implicit val o = new Ordering[Person] { // implement required methods }
wrap(2)(new Person)
The Scala compiler looks in different scopes for implicits, an Ordering would usually not be specified like this. I suggest you look up implicit resolution on the internet to learn more about it.