This question already has answers here:
In Scala, is there an easy way to convert a case class into a tuple?
(5 answers)
Closed 5 years ago.
I have a case class with two fields and a function which accepts the same arguments. Is where a way to pass contents of case class to this function without explicitly specifying all fields or ugly unapplying?
case class User(name: String, age: Int)
val user = User("Peter", 23)
def func(name: String, age: Int) = {...}
func(user.name, user.age) //works
Function.tupled(func(_,_))(User.unapply(user).get) //works, but ugly
// func(_,_) is explicit because it can be a method of a class
The simplest vanilla Scala solution is the one Tom suggested in the comments:
(func _).tupled(User.unapply(user).get)
If happen to have Shapeless in scope (maybe it's already a dependency), you could also use it to convert user to a tuple:
import shapeless._
val gen = Generic[User]
(func _).tupled(gen.to(user).tupled)
Related
This question already has answers here:
How to create an instance of type T at runtime with TypeTags
(4 answers)
Closed 2 years ago.
In Scala, even if the solution is not elegant, is it possible to instantiate/create a new object of a generic type T? Is it possible to achieve this using reflection?
For example, I am interested in something like the following:
case class Person(name: String, age: Int)
Let's say I wanted to do the following to create an object of type Person:
def createObject[T](fieldValues: Seq[Any]): T = {
... T(fieldValues)
}
val person = createObject[Person](Seq("Bob", 20))
No, it is not possible. T is a parameter. You do not know anything about it. You do not even know if it can be instantiated at all. It might be a trait or an abstract class or a singleton type or a compound type.
That is the whole point of parametric polymorphism. To write code that does not need to know anything about the types it is dealing with.
Just as an example, it is perfectly legal to call your method like this:
val goodLuck = createObject[Nothing](Seq(1, 2))
Well, Nothing is literally defined as "the type which cannot have an instance". How are you going to instantiate this?
Technically speaking it's possible using reflection. You could for example catch runtime class of type T using ClassTag then find proper constructor and create instance:
def createObject[T](fieldValues: Seq[Any])(implicit ct: ClassTag[T]): Option[T] = {
//we lookup for matching constructor using arguments count, you might also consider checking types
ct.runtimeClass.getConstructors.find(_.getParameterCount == fieldValues.size)
.flatMap {constructor =>
Try(constructor.newInstance(fieldValues: _*).asInstanceOf[T]).toOption
}
}
createObject[Person](Seq("Bob", 20)) //Some(Person("Bob", 20))
createObject[Person](Seq(20, 10)) //None
In case there's no constructor matching parameters, that function fails returning None.
It should work, but it'd be best if you can avoid this approach because you lose all type safety.
This question already has answers here:
Error with varargs for function-objects in Scala?
(2 answers)
Closed 7 years ago.
I am quite new to Scala (and Spark, if this is somehow Spark-specific), so please forgive the super simple question.
To me, it seems like this code should compile just fine:
sqlContext.udf.register("json_extract_string", (rawJson: String, keyPath: String*) => {
[String]UDFs.jsonExtract(rawJson, keyPath:_*)
})
Yet compiling gives the error:
Error:(31, 89) ')' expected but identifier found.
sqlContext.udf.register("json_extract_string", (rawJson: String, keyPath: String*) => {
^
Why is this?
The function being called looks like this:
object UDFs {
def jsonExtract[T: Manifest](rawJson: String, keyPath: String*): Option[T] = {
implicit val formats = DefaultFormats
val json = parse(rawJson)
keyPath.foldLeft(json)(_ \ _).extractOpt[T]
}
}
In scala it is not permitted for anonymous functions to have variable length arguments, see this answer Scala: How do I define an anonymous function with a variable argument list?
There is a shorter form of what you're trying to express which should work:
sqlContext.udf.register("json_extract_string", UDFs.jsonExtract[String]_)
This:
[String]UDFs.jsonExtract(rawJson, keyPath:_*)
is not valid Scala.
If you need to cast, you have to explicitly call asInstanceOf:
UDFs.jsonExtract(rawJson, keyPath:_*).asInstanceOf[String]
But typically such casting is a code smell and a sign that you've gone down the wrong path.
This question already has answers here:
Scala foreach strange behaviour
(5 answers)
Closed 7 years ago.
Given these case classes:
case class FeatureDistance(id: Long, distance: Double)
case class SearchResult(score: Float, id: Long)
Why does this not compile?
val distances = List[FeatureDistance](FeatureDistance(1L, 10f))
val results = distances.map(SearchResult(0f, _.id))
But this does:
val results = distances.map(fd => SearchResult(0f, fd.id))
The compilation error says: missing parameter type for expanded function ((x$3) => x$3.id)
Is it because _ is only scoped to the map function so it's not visible in the SearchResult.apply call?
After doing a bit of research, I found a post on the old scala forums that contains this quote:
When you use "_" as a place holder for an anonymous parameter of a function, the scope of that function is the innermost parenthesis containing it.
So, it's just a question of scope. I suspect this has to do with problems that could otherwise result from having nested function calls that use more than one underscore. For instance:
//suppose we have some x:List[List[Int]]
x.map(_.map(_ + 1))
This question already has answers here:
How to check constructor arguments and throw an exception or make an assertion in a default constructor in Scala?
(2 answers)
Closed 7 years ago.
Suppose that I have the following class defined in Scala:
class ClassA(val n: Int) {
...
}
I want to limit this class instances to only those that have n between 5 to 10 using Factory Pattern. For example, In case I write something like:
val a = new ClassA(11)
This raises an exception with an appropriate error message, or at least it returns null or something. How can I achieve this behaviour?
Update:
It is possible to achieve this in java with Factory pattern.
Update2:
This questions seems to be answered here, notably with a verbose title though. I tweak the title and content to save the question being deleted, because of two reasons: 1) The example in this one is concise, 2) the provided answer by #Chris Martin explains briefly the way Factory pattern can be reached in Scala by Using Companion Objects.
The conventional way to write a factory in Scala is to define an apply method on the companion object.
Here's an example using Either (because null is never/rarely used in Scala, and exceptions are ugly):
class A private (n: Int) {
override def toString = s"A($n)"
}
object A {
def apply(n: Int): Either[String, A] =
if (n < 5) Left("Too small")
else if (n > 10) Left("Too large")
else Right(new A(n))
}
A(4) // Left(Too small)
A(5) // Right(A(5))
A(11) // Left(Too large)
This is the essentially the same as the Java example you referenced. The A constructor is private, so the class can only be instantiated via the factory method.
This question already has an answer here:
using variable length argument in scala
(1 answer)
Closed 7 years ago.
I have an interface
object Leaf {
def apply(keys: Int*): Leaf = {
new Leaf(keys)
}
}
where Leaf class is defined as follows:
class Leaf(keys: Seq[Int]) extends Node(true, keys, Seq())
Is this possible to pass a Sequence as a keys parameter? Of course I could create second varargs method, but i wonder if there is a method which converts a Sequence into varargs paremeter.
Yes, and I think you mean varargs not varchar :)
Leaf(sequence: _*)