I am trying to implement Phantom Reference in Scala to replace finalize(). I have a file object, which needs to be GC'ed using Phantom Reference. While there are some code samples in java, I am not able to find anything in Scala. I did try writing in Scala like this :
val q = new ReferenceQueue()
val phantom = new PhantomReference(file,q)
But I am getting the following error
found : java.lang.ref.ReferenceQueue[Nothing]
[error] required: java.lang.ref.ReferenceQueue[_ >: java.io.File]
[error] Note: Nothing <: Any, but Java-defined class ReferenceQueue is invariant in type T.
[error] You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
[error] val phantom = new PhantomReference(file,q)
I understand I am missing something trivial, but I am not very proficient in Scala. Can someone help?
Because of the way type inference works in Scala, q is inferred to be of type java.lang.ref.ReferenceQueue[Nothing], but you want it to be a java.lang.ref.ReferenceQueue[File], so you need to make this explicit when you create it:
val q = new ReferenceQueue[File]()
Related
I am not sure how to get past this "No matching Shape found" error, apart from writing lots of boilerplate.
The basic idea illustrated in the Gist is that I have a very basic version of a method (works, but is very specific), then a version that takes the mapper parameter and is more generic (works too, but is specific to one particular type), and then a third version which takes a type parameter and would be very useful, but doesn't compile because of this error.
Basic method:
def updatePD_FirstNames(id: ids.PersonalDetailsId, firstNames: StringLtd30): Future[Int] = {
Better method:
def updatePD_SL(id: ids.PersonalDetailsId, mapper: tables.PersonalDetails => tables.profile.api.Rep[StringLtd30], sl: StringLtd30): Future[Int] = {
Ideal method (but doesn't compile):
def updatePD_X[X](id: ids.PersonalDetailsId, mapper: tables.PersonalDetails => tables.profile.api.Rep[X], sl: X): Future[Int] = {
```
[server] $ compile
[info] Compiling 1 Scala source to ... target\scala-2.12\classes...
[error] ...schema\DbProxy.scala:688: No matching Shape found.
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your * projection,
[error] you use an unsupported type in a Query (e.g. scala List),
[error] or you forgot to import a driver api into scope.
[error] Required level: slick.lifted.FlatShapeLevel
[error] Source type: slick.lifted.Rep[X]
[error] Unpacked type: T
[error] Packed type: G
[error] val q2: Query[tables.profile.api.Rep[X], X, Seq] = q1.map(mapper)
[error] ^
[error] one error found
[error] (server/compile:compileIncremental) Compilation failed
[error] Total time: 4 s, completed 23-Mar-2017 11:15:47
```
Full code at https://gist.github.com/aholland/0845bf29d836d672d006ab58f5f1c73c
The only obvious problem I can see in the code you've posted is that X is unconstrained. It could be any type, includes ones that Slick doesn't know how to process.
What you can do is add a context bound on X. The bound you probably want is BaseTypedType, which is a "typed type" Slick uses to identify types it can work with. It's described from 11:30 in https://www.youtube.com/watch?v=tS6N5AaZTLA
You'd use it like this:
import slick.ast.BaseTypedType
def updatePD[X : BaseTypedType](
id: Long,
selector: PersonTable => Rep[X],
newValue: X
): DBIO[Int] =
people.filter(_.id === id).map(selector).update(newValue)
What that means is that when you use the method...
updatePD(anId, _.name, "Alice")
...the compiler has to prove to itself that whatever X you use, there is an approproate type representation in Slick.
This is also from Richard, but the exchange took place on gitter.
The only trouble with the first answer is that by demanding an implicit of type BaseTypedType[X] the context bound forces client code for optional columns to provide an implicit of type BaseTypedType[Option[X]] even when BaseTypedType[X] is already available.
This is unnecessary. Slick handles optional columns for you and if you provide an implicit for BaseTypedType[X] you are providing enough for it to handle columns of type Option[X].
So the context bound, while it works, is more demanding than necessary and results in having to write implicits in the client-code that involve directly referencing null and replicating logic already built into Slick. Not good.
The answer is to declare the implicit parameter as a named implicit parameter (called shape below) in its own parameter list, i.e. in long-form, not using the context bound short-hand :BaseTypedType. Then you can specify the more complicated but less demanding constraint used below.
So the solution is:
def updatePD[X] (id: Long, selector: PersonTable => Rep[X], newValue: X)
(implicit shape: Shape[_ <: FlatShapeLevel, Rep[X], X, _]): DBIO[Int] = {
people.filter(_.id === id).map(selector).update(newValue)
}
Understanding why shape has the exact type Shape[_ <: FlatShapeLevel, Rep[X], X, _] depends on an intimate understanding of Slick's types and implicit mechanisms. Richard may yet write a blog post on that!
Right now trying to instantiate a new JSONConverter to register Jackson's Scala module.
private def getConverter(implicit m: ClassTag[T]) = {
new JSONConverter[T](classTag[T].runtimeClass, bucketName)
JSONConverter.registerJacksonModule(DefaultScalaModule)
converter
}
The above code sits in a standard Scala trait that looks like trait Writeable[T] { }.
The problem with the above code is that Scala seems to be having a difficult time with Types. Compiler error is:
[error] found : Class[_$1] where type _$1
[error] required: Class[T]
[error] val converter = new JSONConverter[T](classTag[T].runtimeClass, bucketName(clientId))
[error] ^
[error] one error found
Anyone know the source or easy fix of this issue? Thanks!
Update
Although #wingedsubmariner had an answer that allowed this to originally compile, as soon as I went to write more code the issue cascaded further. I'll show an example:
val o = bucketLookup(clientId).fetch(id, classTag[T].runtimeClass).withConverter(converter).withRetrier(DB.retrier).r(DB.N_READ).execute()
At withConverter the compiler throws the same error:
[error] found : com.basho.riak.client.convert.JSONConverter[T]
[error] required: com.basho.riak.client.convert.Converter[_$1] where type _$1
[error] val o = bucketLookup(clientId).fetch(id, classTag[T].runtimeClass).withConverter(converter).withRetrier(DB.retrier).r(DB.N_READ).execute()
I even tried doing the same type casting using converter.asInstanceOf[JSONConverter[T]] but inheritance (JSONConverter<T> extends Converter<T>) seems to cascade the issue. Any ideas here?
runtimeClass is retuning a Class with the wrong type parameter. Try:
new JSONConverter(classTag[T].runtimeClass.asInstanceOf[Class[T]], bucketName(clientId))
How can I use nested type in Scala generic function ? I'd like to implement something like this
implicit def basicDBList2List[List[A]](value : BasicDBList) = value.toList.asInstanceOf[List[A]]
Compiler gives following error:
scala: not found: type A
implicit def basicDBList2List[List[A]](value : BasicDBList) = value.toList.asInstanceOf[List[A]]
^
When you write:
implicit def basicDBList2List[List[A]](value: BasicDBList) = ...
... that doesn't mean what you think it means. You're declaring a new type parameter called List, not referring to the existing List trait in the library! You're also declaring that your newly-defined List type requires some type parameter, which you've called A, but you can't actually reference it.
What you probably meant was:
implicit def basicDBList2List[A](value: BasicDBList): List[A] = ...
... which says that, for any type A, you can convert a BasicDBList to a List[A].
This is sketchy code, though, for two reasons:
What type does your BasicDBList class actually contain? Probably not any possible A. You'll very likely get ClassCastException at runtime.
Why do you want an implicit conversion from BasicDBList to List[A]? That's almost always a bad idea.
I think it is better have it like:
implicit def basicDBList2List[A](value : BasicDBList) = value.toList.asInstanceOf[List[A]]
I use Scala 2.10, Specs2 13.1-SNAPSHOT and the FluentLenium Api provided by Play2 Framework 2.1.
I have this line of code in my IntegrationSpec file, finding a child element (according to FluentLenium spec):
browser.find(".myClass").find("#mySubElement") must haveSize(1)
That line leads to the following compilation error:
error: type mismatch;
found : org.fluentlenium.core.domain.FluentList[_ <: org.fluentlenium.core.domain.FluentWebElement]
required: org.fluentlenium.core.domain.FluentList[?0(in value $anonfun)] where type ?0(in value $anonfun) <: org.fluentlenium.core.domain.FluentWebElement
Note: org.fluentlenium.core.domain.FluentWebElement >: ?0, but Java-defined class FluentList is invariant in type E.
You may wish to investigate a wildcard type such as `_ >: ?0`. (SLS 3.2.10)
Is it a kind of...incompatibilty Scala/Java due to generics?? or a normal behaviour that I didn't figure out?
This line however (omitting any matcher), well compiles:
browser.find(".myClass").find("#mySubElement")
The haveSize matcher require the element being matched to have an org.specs2.data.Sized typeclass in scope. The corresponding typeclass for java collections is:
implicit def javaCollectionIsSized[T <: java.util.Collection[_]]: Sized[T] =
new Sized[T] {
def size(t: T) = t.size()
}
I suspect that type inference here is the issue and you could try to tame it with the following ugly code:
browser.find(".myClass").
find("#mySubElement").
asInstanceOf[FluentList[FluentWebElement]] must haveSize(1)
Or maybe
browser.find(".myClass").
find("#mySubElement").
asInstanceOf[Collection[_]] must haveSize(1)
Or
import scala.collection.convert.JavaConverters._
browser.find(".myClass").
find("#mySubElement").
asScala must haveSize(1)
I'm trying to do something in Scala that I'm not sure is possible. I'd love some feedback from the community.
Say I have a sealed trait for some 'thing', a few concrete extensions of it, and a generic class which works with some implementation of that trait..
sealed trait Thing
class CoolThing extends Thing
class OtherThing extends Thing
class BoxOfThings[T <: Thing]
Now, I can define another class which handles two 'boxes of things' like so..
class PairOfBoxes(boxOne: BoxOfThings[_ <: Thing], boxTwo: BoxOfThings[_ <: Thing])
However, here it's perfectly fine to create a PairOfBoxes with one box of CoolThings and the other of OtherThings. I would like to declare that boxOne and boxTwo contain the same type of Thing.. is that at all possible?
For example:
// Cool things..
val boxOfCoolThings = new BoxOfThings[CoolThing]
val anotherBoxOfCoolThings = new BoxOfThings[CoolThing]
// Other things..
val boxOfOtherThings = new BoxOfThings[OtherThing]
// A pair of cool boxes, no problem:
new PairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThings)
// A pair of different boxes, compiles but I don't want it to:
new PairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
I could do this by making the PairOfBoxes generic itself, like so..
class TypedPairOfBoxes[T <: BoxOfThings[_ <: Thing]](boxOne: T, boxTwo: T)
It works, but it's ugly..
// A pair of cool boxes, no problem:
new TypedPairOfBoxes[BoxOfThings[CoolThing]](boxOfCoolThings, anotherBoxOfCoolThings)
// A pair of different boxes, doesn't compile:
val mixedPair = new TypedPairOfBoxes[BoxOfThings[CoolThing]](boxOfOtherThings, anotherBoxOfCoolThings)
I would like to avoid this is I can. It pushes the problem upstream and forces us to specify the contents of each TypedPairOfBoxes. It would be ideal to simply use an untyped PairOfBoxes which asserts it's parameters are of the same type.
Possible?
Thanks!
You just need to write as:
class TypedPairOfBoxes[T <: Thing](one: BoxOfThings[T], two: BoxOfThings[T])
Then:
scala> new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
<console>:15: error: type mismatch;
found : BoxOfThings[OtherThing]
required: BoxOfThings[Thing]
Note: OtherThing <: Thing, but class BoxOfThings is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
^
<console>:15: error: type mismatch;
found : BoxOfThings[CoolThing]
required: BoxOfThings[Thing]
Note: CoolThing <: Thing, but class BoxOfThings is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThings)
^
scala> new TypedPairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThings)
res3: TypedPairOfBoxes[CoolThing] = TypedPairOfBoxes#2f5e1167
I <3 Scala
Scala can infer the generic types such that I can define an 'ugly' typed class but don't need to specify the specific implementation when I use it.
With this realization, I was able to define a typed class similar to the one in my question above..
class TypedPairOfBoxes[T, BoxOfThings[T <: Thing]](boxOne: BoxOfThings[T], boxTwo: BoxOfThings[T])
.. it looks a bit gnarly, but can be used as simply as this:
// Both boxes contain cool things, no problem:
new TypedPairOfBoxes(boxOfCoolThings, anotherBoxOfCoolThing)
// These boxes contain different things, doesn't compile:
new TypedPairOfBoxes(boxOfOtherThings, anotherBoxOfCoolThing)
Amazing.
Edit:
As #Eastsun demonstrated, the latter part of of the generic definition is unused. So can be written, instead, as:
class TypedPairOfBoxes[T <: Thing](boxOne: BoxOfThings[T], boxTwo: BoxOfThings[T])
This looks very much like Java. But the amazing thing here being that Scala infers the generic types from the parameters.