Error using Specs2 with FluentLenium Api - scala

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)

Related

How to use PhantomReference in Scala

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]()

Applying type constructors to generated type parameters with Scala macros

I am trying to materialize an instance of the (simplified) trait
trait TC[F[_]] {
def apply[A](fa: F[A]): F[A]
}
using Scala macros. The signature of the macro therefore is
def materialize[F[_]](c: Context)(
implicit fT: c.WeakTypeTag[F[_]]): c.Expr[TC[F]]
Type constructor F[_] now needs to be applied to the type parameter A for two reasons:
To write the signature of apply above for a particular F (like Foo[A])
To inspect the members of the type Foo[A] in order to specify an interesting body of apply
Is there any way to create the type corresponding to the method type parameter A that can than be used in appliedType? It appears difficult for me, since the method apply and its type parameter A are also just being generated as trees.
I tried to take WeakTypeTag[TC[F]] as additional argument to the macro call and received the paramter type by
val paramT = wfg.tpe.member("apply": TermName).tpe.typeParams.head.tpe
but then using paramT in q"... def apply[$paramT] ..." does result in
java.lang.IllegalArgumentException: can't splice "A" as type parameter
so this appears also to be no solution.
I solved the problem by changing the definition of the above trait to
trait TC[F[_]] {
type ApplyF[A] = F[A]
def apply[A](fa: ApplyF[A]): ApplyF[A]
}
and typechecking the tree for a dummy value:
typecheck(q"""new TC[Foo] {
def apply[A](fa: ApplyF[A]): ApplyF[A] = ???
}""").tpe
The typechecked result then could be destructed and transformed (by means of tree transformers) to fill in the ???. This did not solve the problem completely, yielding the type error:
found : A(in method apply)(in method apply)(in method apply)...
required: A(in method apply)(in method apply)(in method apply)...
While calling untypecheck before returning the tree did not help - inspection of the resulting tree however showed that the expected result is valid (type correct) Scala code. Thus, the last step that made the macro finally fly was to call
parse(showCode(result))
It feels completely unnecessary, but it seems that this was the only way to get rid of conflicting type information.

How to make scalaz.Tagged work with class class primitive attributes?

Consider the following example:
import scalaz._
object TaggedExample {
sealed trait Test
def Test[A](a: A): A ## Test = Tag[A, Test](a)
}
case class TaggedAttribute(l: Long ## TaggedExample.Test)
It will fail to compile with next reason:
scalac: type mismatch;
found : Double
required: AnyRef
Note: an implicit exists from scala.Double => java.lang.Double, but
methods inherited from Object are rendered ambiguous. This is to avoid
a blanket implicit which would convert any scala.Double to any AnyRef.
You may wish to use a type ascription: `x: java.lang.Double`.
To my understanding, it is happens due to some details in case class compiler code generation (because simple def test(l: Long ## TaggedExample.Test) = l compiles just fine).
If we change case class definition to
case class TaggedAttribute(l: java.lang.Long ## TaggedExample.Test)
compilation will succeed.
The question is: Is there a way to avoid this scalac error without changing type of l to java.lang.Long (which, in turn, will allow l to be null etc.)?
Update
Found this Tagged type : type mismatch question and answer to it right after posting, but still: may be there is a way to avoid use of java.lang.* box types.
Know bug: Compiler error when using tagged types and case classes
Workaround: use box types.

Manifest and abstract type resolution

I am hitting a compiler problem when the compiler needs to solve a manifest for a class with an abstract type parameter. The following snippet show the issue
trait MyStuff
trait SecurityMutatorFactory[X]{
def apply(x1:X,x2:X)
}
object Example{
trait LEdge[N]
{
type L1
}
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}
val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]
}
As a result, the compiler throws the following type error:
type mismatch;
found : scala.reflect.Manifest[LEdge[MyStuff]]
required: Manifest[MyEdge[MyStuff]]
Note: LEdge[MyStuff] >: MyEdge[MyStuff], but trait Manifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: MyEdge[MyStuff]`. (SLS 3.2.10)
val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]
What is happening at compiler level? ^
As others have suggested the problem comes from
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] }
Declarations of the form type F[X] = ... introduce type synonyms, ie new names for existing types. They do not construct new traits or classes. However, LEdge[X] { type L1 = SecurityMutatorFactory[X] } is constructing a new anonymous class. So your example is approximatelly equivalent to
trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }
(which is what you most probably want) but the original definition in the example is defining a synonym for an anonymous class instead of defining a new class MyEdge[X]. So in the example the new class is not actually called MyEdge. When constructing the implicit manifest, the compiler replaces the type synonym with the underlying type, but fails to construct a manifest for that because that type is anonymous.
Replacing the MyEdge declaration with either a normal extension definition:
trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }
or with an ordinary type synonym:
type MyEdge[X] = LEdge[X]
both compile successfully.
EDIT
Here is the specific reason why generating implicit manifests for anonymous classes fails.
In the language specification type expessions of the form BaseType { ... } are called refined types.
According to the language specification, the manifest for a refined type is just the manifest of its base class. This however fails to typecheck, because you asked for a Manifest[LEdge[MyStuff]{ type L1 = SecurityMutatorFactory[X] }], but the algorithm is returning Manifest[LEdge[MyStuff]]. This means that you can only construct implicit manifests for types with refined types only in contravariant positions. For example using:
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] } => AnyRef
in your example allows it to compile, though it is clearly not what you are after.
The full algorithm for constructing implicit manifests is given at the end of section 7.5 of the language specification. This question is covered by clause 6:
6) If T is a refined type T'{R}, a manifest is generated for T'. (That is, refinements are never reflected in manifests).
Well, I'm not so familiar with that kind of pattern:
type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}
but I tend to consider types defined with the type keyword as aliases (concepts) rather than a guarantee about the implementation (EDIT more precisely, I believe that type provides guarantees in terms of prototyping/specifying but that no AST/code is generated until there's an actual need to replace the alias with the traits/classes it's based upon). So even if the compiler claims, in its error message:
LEdge[MyStuff] >: MyEdge[MyStuff]
I'm not sure that, at the bytecode level, it implements MyEdge accordingly, with interfaces/methods/etc. Thus, it might not recognize the wanted relationship between LEdge and MyEdge, eventually:
found : scala.reflect.Manifest[LEdge[MyStuff]]
required: Manifest[MyEdge[MyStuff]]
(and, is the absence of package scala.reflect. a hint? (1))
About your code, how do you use a? Anyway, if the following is your intent, with:
trait MyEdge[X] extends LEdge[X] {
type L1 = SecurityMutatorFactory[X]
}
instead, it does compile (scala 2.10)... (EDIT I just noticed now that dmitry already told that) ...what that does during runtime, I don't know!
As an item of note, Manifest is deprecated after scala 2.9; so you may prefer to use TypeTag[T] as described in the scaladoc.
EDIT:
(1) I suspect that the following happens:
- at the syntactic analysis phase, the compiler registers literally what you specified, that is, the implicitly method shall return a Manifest[MyEdge[MyStuff]].
- by the code generation phase, the aliases are "reconciled" to their nearest classes or traits; in the case of implicitly the result's type Manifest[MyEdge[MyStuff]] becomes trait scala.reflect.Manifest[LEdge[MyStuff]]]
- due to some limitations of type inference involved in Manifest and type "aliasing" within type parameters, however, somehow the specified requirement Manifest[MyEdge[MyStuff]] remains under its raw shape
- (this is pure conjecture, because I've not read the Scala compiler source code for this answer) the compiler would have the proper AST/code on the one hand, but a method prototype/spec that is still under its raw/literal shape on the other hand; that doesn't fit in so it emits an error.
Hoping that helps...

ScalaTest - writing custom matchers

I am running into a problem while writing a custom matcher for NodeSeq:
private def matchXML(expected: NodeSeq) = new Matcher[NodeSeq] {
def apply(left: NodeSeq): MatchResult = MatchResult(left xml_== expected,
"XML structure was not the same (watch spaces in tag texts)",
"XML messages were equal")
}
This compiles, but the following piece of code:
val expected : NodeSeq = ...
val xml : NodeSeq = ...
xml should matchXML(expected)
causes:
error: overloaded method value should with alternatives:
(beWord: XMLStripDecoratorTests.this.BeWord)XMLStripDecoratorTests.this.ResultOfBeWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(notWord: XMLStripDecoratorTests.this.NotWord)XMLStripDecoratorTests.this.ResultOfNotWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(haveWord: XMLStripDecoratorTests.this.HaveWord)XMLStripDecoratorTests.this.ResultOfHaveWordForSeq[scala.xml.Node] <and>
(rightMatcher: org.scalatest.matchers.Matcher[scala.collection.GenSeq[scala.xml.Node]])Unit
cannot be applied to (org.scalatest.matchers.Matcher[scala.xml.NodeSeq])
xml should (matchXML(expected))
Any ideas what this means?
Why this fails to typecheck:
The type checker works in the following way.
xml.should(matchXML(expected))
Because the method should is not part of a NodeSeq, the compiler tries to find an implicit conversion for xml to a ShouldMatcher.
The book "Programming in Scala" specifies that such implicit conversion should be the most specific:
"Up through Scala 2.7, that was the end of the story. Whenever
multiple implicit conversions applied, the compiler refused to choose
between them. ... Scala 2.8 loosens this rule. If one of the available
conversions is strictly more specific than the others, then the
compiler will choose the more specific one. ... one implicit conversion
is more specific than another if one of the following applies: The
argument type of the former is a subtype of the latter’s. .."
Because NodeSeq extends Seq[Node], the following function
convertToSeqShouldWrapper[T](o : scala.GenSeq[T]) : SeqShouldWrapper[T]
is therefore the most specific one among all others.
The program is rewritten as:
`convertToSeqShouldWrapper(xml).should(matchXML(expected))`
where convertToSeqShouldWrapper(xml) is a SeqShouldWrapper[T] where T = GenSeq[Node].
The method should from SeqShouldWrapper accepts a Matcher[T] which is a function of type T => MatchResult. Therefore, it accepts a Matcher[GenSeq[Node]].
Because T is appearing to the left of the arrow, matchers are not covariant in T, but contravariant. A NodeSeq is a GenSeq[Node], so a Matcher[GenSeq[Node]] is a Matcher[NodeSeq], not the opposite.This explains the above error, where the method should cannot accept a Matcher[NodeSeq] and requires a Matcher[GenSeq[Node]].
2 Solutions
Replace All instances of NodeSeq to GenSeq[Node] so that the type matches everywhere.
Alternatively, wrap xml explicitely with the conversion function.
convertToAnyShouldWrapper(xml).should(matchXML(expected))
This looks to me like your matchXML method is not in scope.