Scala: generic function taking function with not known arity as argument - scala

I have some functions like these ones (I don't know the arity, I just know that the return is of type Future[T]):
def a(a: Int): Future[String] = { Future("a") }
def b(b: Long): Future[Double] = { Future(1.0) }
I'd like to write a generic function WithLoading that could be used like this:
def a(a: Int): Future[String] = WithLoading { Future("a") }
def b(b: Long, c: Int): Future[Double] = WithLoading { Future(1.0) }
and would do the same result as:
def a(a: Int): Future[String] = { var loading = true; Future("a").map (_ => loading = false) }
def b(b: Long): Future[Double] = { var loading = true; Future(1.0).map (_ => loading = false) }
Is it is possible to do this? And if the answer is yes, could you please give me some advice?

Seems that WithLoading doesn't need to know about arity at all.
def withLoading[T](action: => Future[T]): Future[T] = {
doSmthWithLoading
val triggeredAction = action
val result = triggeredAction.onComplete(r => {
cleanupSmth
})
result
}

Related

In Scala, how to deal with heterogeneous list of the same parameterized type

I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))

Creating generic update function for Slick 3.1.1

I have this fucntion:
def updateInvoiceAdminStatusField(id: Int, newAdminStatus: AdminStatus): Future[Int] = {
db.run {
val adminStatus: Query[Rep[AdminStatus], AdminStatus, Seq] = InvoicesTable.filter(invoice => invoice.id === id).map(invoice => invoice.status)
adminStatus.update(newAdminStatus)
}
}
I thought of making it generic:
def updateInvoiceField[T](id: Int, fieldExtractor: (Invoices) => Rep[T], newValue: T): Future[Int] = {
db.run {
val adminStatus = InvoicesTable.filter(invoice => invoice.id === id).map(invoice => {
fieldExtractor(invoice)
})
adminStatus.update(newValue)
}
}
But this does not compile. Can somebody assist?
It's nearly good. With small changes like below it should work:
// I added below T: ColumnType
def updateInvoiceField[T: ColumnType](id: Int, fieldExtractor: (Invoices) => Rep[T], newValue: T): Future[Int] = {
db.run {
val adminStatus = InvoicesTable.filter(invoice => invoice.id === id).map(invoice => {
fieldExtractor(invoice)
})
adminStatus.update(newValue)
}
}
Notice I added this : ColumnType which basically mean you need to have proper implicit in scope - specifically the one that would convert T => ColumnType[T]. That's simply because otherwise T could be anything and Slick wouldn't be able to figure out how to convert it.
So for things like String, Int etc. you obviously have proper conversations already in place (imported from api in profile/driver). For you custom types you would need to use MappedColumnType to have proper conversion supplied. Example below (typesafe ID):
implicit def columnType[T]: BaseColumnType[Id[T]] =
MappedColumnType.base[Id[T], Long](toLong, fromLong)
private def fromLong[T](dbId: Long): Id[T] = Id(dbId)
private def toLong[T](id: Id[T]): Long = id.value

Type parameters and inheritance in Scala

Is there a simple way to return a concrete type in an override method? And what about creating an instance of a concrete implementation? And calling chained methods implemented in the concrete class, so they return a correct type, too? I have a solution (based on https://stackoverflow.com/a/14905650) but I feel these things should be simpler.
There are many similar questions, but everyone's case is a little different, so here is another example (shortened from https://github.com/valdanylchuk/saiml/tree/master/src/main/scala/saiml/ga). When replying, if possible, please check if the whole code block compiles with your suggested change, because there are subtle cascading effects. I could not make this work with the "curiously recurring template pattern", for example (not that I find it nicer).
import scala.reflect.ClassTag
import scala.util.Random
abstract class Individual(val genome: String) {
type Self
def this() = this("") // please override with a random constructor
def crossover(that: Individual): Self
}
class HelloGenetic(override val genome: String) extends Individual {
type Self = HelloGenetic
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: Individual): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual {type Self = A} :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual {type Self = A} :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
The CRTP version is
abstract class Individual[A <: Individual[A]](val genome: String) {
def this() = this("") // please override with a random constructor
def crossover(that: A): A
}
class HelloGenetic(override val genome: String) extends Individual[HelloGenetic] {
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: HelloGenetic): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual[A] :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual[A] :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual[A] = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
which compiles. For creating the instances, I'd suggest just passing functions:
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, makeIndividual: () => A, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(makeIndividual())
...
}
If you want to pass them implicitly, you can easily do so:
trait IndividualFactory[A] {
def apply(): A
}
class HelloGenetic ... // remove def this()
object HelloGenetic {
implicit val factory: IndividualFactory[HelloGenetic] = new IndividualFactory[HelloGenetic] {
def apply() = new HelloGenetic(Random.alphanumeric.take("Hello, World!".length).mkString)
}
}
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None)
(implicit factory: IndividualFactory[A]) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(factory())
...
}

Scala transformations

I am really new in Scala and I would like to ask a simple question.
I have a function that returns Future[Option[T]
def findOne(query: JsObject)(implicit reader: Reads[T]): Future[Option[T]] = {
Logger.debug(s"Finding one: [collection=$collectionName, query=$query]")
collection.find(query).one[T]
}
And I have to return Future[Option[PasswordInfo]].
I tried:
def find(loginInfo: LoginInfo): Future[Option[PasswordInfo]] = {
val result = find(Json.obj("loginInfo.providerID" -> loginInfo.providerID, "loginInfo.providerKey" -> loginInfo.providerKey))
result.onSuccess{
case something => Future.successful(Some(something).getOrElse(None))
}
}
My class:
case class PersistentPasswordInfo(
loginInfo: LoginInfo,
authInfo: PasswordInfo
) extends TemporalModel {
override var created: Option[DateTime] = _
override var updated: Option[DateTime] = _
override var _id: Option[BSONObjectID] = _
}
you need to map over the Future to get the Option, then map over the Option to get the PersistedPasswordInfo
def find(loginInfo: LoginInfo): Future[Option[PasswordInfo]] = {
val result = find(Json.obj("loginInfo.providerID" -> loginInfo.providerID, "loginInfo.providerKey" -> loginInfo.providerKey))
result.map(opt => opt.map(ppi => ppi.authInfo))
}
Future and Option are both Functors, they implement a method map with something like the following signature (assuming the type arg to the containing Future is A):
def map[B](f: A => B): Future[B]
so the code above changes Future by applying a function Option[PersistentPasswordInfo] => Option[PasswordInfo]
that function is created by applying map to on the contained Option with a function PersistentPasswordInfo => PasswordInfo

Combine two functions under the same name without overloading

Here is the code:
def transform1(f: String => String): Unit = {
val s = getString
f.andThen(putString)(s)
}
def transform2(f: String => Option[String]): Unit = {
val s = getString
f(s).foreach(putString(_))
}
How do you express these two ideas in one single function?
Method overloading does not work and seems discouraged by the community.
I didn't understand that why anyone may want this but here is a way to do it:
def transform(f: Either[(String => String), (String => Option[String])]: Unit = f match {
case Left(f) => // do transform1 here
case Right(f) => //do transform2 here
}
As I said at the begining you probably shouldn't want to do this; perhaps you should directly ask what you want.
The pattern to avoid overloading is to convert disparate arguments to a common, specific type. There could be any number of such conversions.
Not sure this is the most compelling example, however.
object X {
trait MapFlat[-A, +B] { def apply(x: A): B }
implicit class mapper[A](val f: A => A) extends MapFlat[A, A] {
override def apply(x: A) = {
val res = f(x)
println(res)
res
}
}
implicit class flatmapper[A](val f: A => Option[A]) extends MapFlat[A, Option[A]] {
override def apply(x: A) = {
val res = f(x)
res foreach println
res
}
}
def f[B](g: MapFlat[String, B]) = {
g("abc")
}
}
object Test extends App {
import X._
f((s: String) => s)
f((s: String) => Some(s))
}
One way to do it will be type classes, here's a sample -
trait Transformer[T] {
def transform(foo: String => T)
}
object Transformer {
implicit object StringTransformer extends Transformer[String] {
override def transform(foo: (String) => String): Unit = ??? // Your logic here
}
implicit object OptStringTransformer extends Transformer[Option[String]] {
override def transform(foo: (String) => Option[String]): Unit = ??? // Your logic here
}
}
class SampleClass {
def theOneTransformYouWant[T: Transformer](f: String => T) = {
implicitly[Transformer[T]].transform(f)
}
def canUseBothWays(): Unit = {
theOneTransformYouWant((s: String) => s)
theOneTransformYouWant((s: String) => Some(s))
}
}
Another way would be the magnet pattern
http://spray.io/blog/2012-12-13-the-magnet-pattern/
sealed trait TransformationMagnet {
def apply(): Unit
}
object TransformationMagnet {
implicit def fromString(f: String => String): TransformationMagnet =
new TransformationMagnet {
def apply(): Unit = ??? // Your code goes here
}
implicit def fromOptString(f: String => Option[String]): TransformationMagnet =
new TransformationMagnet {
def apply(): Unit = ??? // your code goes here
}
}
class SampleClass {
def theOneTransformYouWant(f: TransformationMagnet) = {
???
}
def hereWeUseItInBothWays(): Unit = {
theOneTransformYouWant((s: String) => s)
theOneTransformYouWant((s: String) => Some(s))
}
}
add a new parameter on the description typeOfTransform
add a conditional inside the function
if (typeOfTransform == type1){
//functionality1
}else {
//functionality2
}
Just for completeness, you can actually overload methods like this by adding implicit arguments which will always be available:
def transform(f: String => Option[String]): Unit = ...
def transform(f: String => String)(implicit d: DummyImplicit): Unit = ...