Tuple case mapping don't work with generic Array[T] in scala - arrays

I don't understand why the compiler cannot understand the case instruction mapping on tuple when i try to use with generics Array[T].
class Variable[T](val p: Prototype[T], val value: T)
class Prototype[T](val name: String)(implicit m: Manifest[T])
// Columns to variable converter
implicit def columns2Variables[T](columns:Array[(String,Array[T])]): Iterable[Variable[Array[T]]] = {
columns.map{
case(name,value) =>
new Variable[Array[T]](new Prototype[Array[T]](name), value)
}.toIterable
}
Error say :
error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: fr.geocite.simExplorator.data.Variable[Array[T]]
case(name,value) =>

I'm also not sure about the wording of the error, but first of all, you will need the manifest for T because it is required for constructing new Prototype[Array[T]] (the array manifest can be automatically generated if a manifest for its type parameter is in scope).
Is there any reason you absolutely need arrays? They come with the irregularity of Java's type system, they are mutable, and they offer very little advantage over for example Vector. Lastly, and that's probably why carry around the manifests, unlike arrays standard collections do not require manifests for construction.
class Variable[T](val p: Prototype[T], val value: T)
class Prototype[T](val name: String)
implicit def cols2v[T](cols: Vector[(String,Vector[T])]): Vector[Variable[Vector[T]]] =
cols.map {
case (name, value) => new Variable(new Prototype(name), value)
}

Related

In Kotlin, how to define a property of a generic type with a upper bound limit?

What is the Kotlin equivalent of the following Java code?
class Test {
Class<? extends Number> types = new Class[] {
Integer.class, Long.class, Short.class, Byte.class, Float.class, Double.class
};
}
You can use out keyword:
var types: Array<Class<out Number>> = arrayOf(
Integer::class.java,
Long::class.java,
Short::class.java,
Byte::class.java,
Float::class.java,
Double::class.java
)
out modifier is used to indicate covariance (similar to ? extends T in Java). Covariance - is the ability to change the generic type argument from a class to one of its parents, i.e. assign List<String> to List<Any>.
What you need here is a covariant array, or out variance on your generic parameter:
var types: Array<Class<out Number>> = arrayOf(
Int::class.java,
Long::class.java,
Short::class.java,
Byte::class.java,
Float::class.java,
Double::class.java
)
This sort of thing is covered in the documentation under variance (although it might take a while to untangle it all, if you're new to it).
In addition to other answers, you could produce the same code in Kotlin using Kotlin data types as;
var types: Array<KClass<out Number>> = arrayOf(
Int::class,
Long::class,
Short::class,
Byte::class,
Float::class,
Double::class
)
Here we use KClass which is the Kotlin class reference type and out is covariance type annotation (producer).

Getting unexpected error when using structure type

I'm new to Scala programming, so please bear with me if it's a silly question. I was expecting the following code to work, since a has a mkString method.
val a = "abc".toCharArray
case class A[T: {def mkString(): String}](i: T) {
val s = i.mkString
}
A(a)
But it gives the following error:
Error:(3, 16) AnyRef{def mkString(): String} does not take type
parameters case class A[T: {def mkString(): String}](i: T)
Error:(4, 14) value mkString is not a member of type parameter T val
s = i.mkString
I'm using Scala 2.11.6.
Any help will be really appreciated! Thank you !
The type bounds [A : B] is a shorthand way of saying there exists an instance of the typeclass B for type A, so these are equivalent:
def foo[A : B]: C
def foo[A](implicit b: B[A]): C
The syntax you're probably looking for is [A <: B], which means A must be a subclass of B.
But then you have the issue that mkString isn't actually in the Array class; it's defined in ArrayOps (with an implicit conversion from Array) as described in the documentation:
This member is added by an implicit conversion from Array[T] to
ArrayOps[T] performed by method genericArrayOps in scala.Predef.
You can work around that with:
val a = "abc".toCharArray
case class A[T](i: T)(implicit conv: T => {def mkString: String}) {
val s = conv(i).mkString
}
A(a)
At least three mistakes there:
It should be <:, not :. The structural type is not a typeclass.
def mkString(): String is not the same as def mkString: String.
raw JVM arrays know nothing about convenient scala methods like mkString. You need a WrappedArray for that.
This here works:
import scala.language.reflectiveCalls
val a = "abc".toCharArray
import collection.mutable.WrappedArray
case class A[T <: { def mkString: String }](i: T){
val s = i.mkString
}
A(a: WrappedArray[Char])

Scala type inference: can't infer IndexedSeq[T] from Array[T]

In Scala 2.11.2, the following minimal example compiles only when using type ascription on the Array[String]:
object Foo {
def fromList(list: List[String]): Foo = new Foo(list.toArray : Array[String])
}
class Foo(source: IndexedSeq[String])
If I remove the type ascription in fromList, it will fail to compile with the following error:
Error:(48, 56) polymorphic expression cannot be instantiated to expected type;
found : [B >: String]Array[B]
required: IndexedSeq[String]
def fromList(list: List[String]): Foo = new Foo(list.toArray)
^
Why can't the compiler infer the Array[String] here? Or does this issue have to do something with the implicit conversion from Array's to IndexedSeq's?
The issue is that the .toArray method returns an Array of some type B which is a superclass of the T in List[T]. This allows you to use a list.toArray on List[Bar] where an Array[Foo] is required if Bar extends Foo.
Yes, the real reason this doesn't work out of the box is that the compiler is trying to figure out which B to use and also how to get to an IndexedSeq. It seems like it's trying to resolve the IndexedSeq[String] requirement but B is only guaranteed to be a String or a superclass of String; hence the error.
This is my preferred work around:
def fromList(list: List[String]): Foo = new Foo(list.toArray[String])

How to use Slick's mapped tables with foreign keys?

I'm struggling with Slick's lifted embedding and mapped tables. The API feels strange to me, maybe just because it is structured in a way that's unfamiliar to me.
I want to build a Task/Todo-List. There are two entities:
Task: Each task has a an optional reference to the next task. That way a linked list is build. The intention is that the user can order the tasks by his priority. This order is represented by the references from task to task.
TaskList: Represents a TaskList with a label and a reference to the first Task of the list.
case class Task(id: Option[Long], title: String, nextTask: Option[Task])
case class TaskList(label: String, firstTask: Option[Task])
Now I tried to write a data access object (DAO) for these two entities.
import scala.slick.driver.H2Driver.simple._
import slick.lifted.MappedTypeMapper
implicit val session: Session = Database.threadLocalSession
val queryById = Tasks.createFinderBy( t => t.id )
def task(id: Long): Option[Task] = queryById(id).firstOption
private object Tasks extends Table[Task]("TASKS") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def title = column[String]("TITLE")
def nextTaskId = column[Option[Long]]("NEXT_TASK_ID")
def nextTask = foreignKey("NEXT_TASK_FK", nextTaskId, Tasks)(_.id)
def * = id ~ title ~ nextTask <> (Task, Task.unapply _)
}
private object TaskLists extends Table[TaskList]("TASKLISTS") {
def label = column[String]("LABEL", O.PrimaryKey)
def firstTaskId = column[Option[Long]]("FIRST_TASK_ID")
def firstTask = foreignKey("FIRST_TASK_FK", firstTaskId, Tasks)(_.id)
def * = label ~ firstTask <> (Task, Task.unapply _)
}
Unfortunately it does not compile. The problems are in the * projection of both tables at nextTask respective firstTask.
could not find implicit value for evidence parameter of type
scala.slick.lifted.TypeMapper[scala.slick.lifted.ForeignKeyQuery[SlickTaskRepository.this.Tasks.type,justf0rfun.bookmark.model.Task]]
could not find implicit value for evidence parameter of type scala.slick.lifted.TypeMapper[scala.slick.lifted.ForeignKeyQuery[SlickTaskRepository.this.Tasks.type,justf0rfun.bookmark.model.Task]]
I tried to solve that with the following TypeMapper but that does not compile, too.
implicit val taskMapper = MappedTypeMapper.base[Option[Long], Option[Task]](
option => option match {
case Some(id) => task(id)
case _ => None
},
option => option match {
case Some(task) => task.id
case _ => None
})
could not find implicit value for parameter tm: scala.slick.lifted.TypeMapper[Option[justf0rfun.bookmark.model.Task]]
not enough arguments for method base: (implicit tm: scala.slick.lifted.TypeMapper[Option[justf0rfun.bookmark.model.Task]])scala.slick.lifted.BaseTypeMapper[Option[Long]]. Unspecified value parameter tm.
Main question: How to use Slick's lifted embedding and mapped tables the right way? How to I get this to work?
Thanks in advance.
The short answer is: Use ids instead of object references and use Slick queries to dereference ids. You can put the queries into methods for re-use.
That would make your case classes look like this:
case class Task(id: Option[Long], title: String, nextTaskId: Option[Long])
case class TaskList(label: String, firstTaskId: Option[Long])
I'll publish an article about this topic at some point and link it here.

Scala: how to specify type parameter bounds implying equality?

Don't be put off by the long text, the points are quite trivial but require a bit of code to illustrate the problem. :-)
The Setup:
Say I would like to create a trait, here modeled as a Converter of some kind, that itself is generic but has a typed method convert() that returns an appropriately typed result object, say a Container[T]:
trait Converter {
def convert[T]( input: T ) : Container[T]
}
trait Container[T] // details don't matter
My question is about type constraints on methods, in particular for enforcing equality, and has two closely related parts.
Part 1: Say now that there was a specialized container type that was particularly suitable for array-based contents, like so:
object Container {
trait ForArrays[U] extends Container[Array[U]]
}
Given this possibility, I'd now like to specialize the Converter and in particular the return type of the convert() method, to the specialized Container.ForArrays type:
object Converter {
trait ForArrays extends Converter {
// the following line is rubbish - how to do this right?
def convert[E,T <: Array[E]]( input: T ) : Container.ForArrays[E]
}
}
So that I can do something like this:
val converter = new Converter.ForArrays { ... }
val input = Array( 'A', 'B', 'C' )
val converted : Container.ForArrays[Char] = converter.convert( input )
Basically I want Scala, if the type of converter is known to be Converter.ForArrays, to also infer the specialized return type of convert[Char]() as Container.ForArrays[Char], i.e. the matching container type plus the array type of the input. Is this or something like it possible and if so, how do I do it? E.g. how do I specify the type parameters / bounds on convert() (what is provided is just a stand-in - I have no idea how to do this). Oh, and naturally so that it still overrides its super method, otherwise nothing is gained.
Part 2: As a fallback, should this not be possible, I could of course push the convert function down into the Array-focused variant, like so:
trait Converter // now pretty useless as a shared trait
object Converter {
trait ForValues extends Converter {
def convert[T]( input: T ) : Container[T]
}
trait ForArrays extends Converter {
def convert[E]( input: Array[E] ) : Container.ForArrays[E]
}
}
OK. Now say I have an even more specialized Converter.ForArrays.SetBased that can internally use a set of elements of type E (the same as the 'input' array element type) to do some particular magic during the conversion. The set is now a parameter of the trait, however, like so:
case class SetBased( set: Set[F] ) extends Converter.ForArrays {
// the following line is also rubbish...
def convert[E = F]( input: Array[E] ) : Container.ForArrays[E] = {...}
}
Again, this is about the type parameters of the convert() method. The difficulty here is: how do I glue the type parameter of the class - F - to the type parameter of the method - E - such that the Scala compiler will only let the user call convert() with an array whose elements match the elements of the set? Example:
val set = Set( 'X', 'Y', 'Z' )
val converter = new Converter.ForArrays.SetBased( set )
val input = Array( 'A', 'B', 'C' )
val converted : Container.ForArrays[Char] = converter.convert( input )
No, you can't. For the same reason you can't narrow argument types or widen return types when overriding a method (but can narrow return type). Here is what you can do, however (for your fallback solution):
trait Converter {
type Constraint[T]
}
trait ForArrays extends Converter {
def convert[E]( input: Array[E] )( implicit ev : Constraint[T] ) : Container.ForArrays[E]
}
case class SetBased[F](set: Set[F]) extends Converter {
type Constraint[T] = T =:= F
def convert[E]( input: Array[E] )( implicit ev : E =:= F ) = ...
}
I'm going to assume that Container.ForArrays is a subclass of Container, without this, Converter.ForArrays.convert won't match the signature of the overridden Converter.convert
Try writing it something like this:
object Converter {
trait ForArrays extends Converter {
def convert[E] (input: Array[E]): Container.ForArrays[E]
}
}
Regarding your fallback solution. If two types are the same, then just use the same type param!
case class SetBased (set: Set[F]) extends Converter.ForArrays {
def convert (input: Array[F]): Container.ForArrays[F] = {...}
}

Resources