Does Scala allow for the arbitrary instantiation of generic objects? new B {}? - scala

I was wondering if something like this would be possible to implement in Scala:
def f[B <: AnyRef]()(implicit ct: ClassTag[B]): B = {
new B {
override def equals(o: Any) = ...
override def hashcode(o: Any) = ...
}
}
My intuition is that even with the ClassTag it should not be possible to instantiate an arbitrary B, as we don't know if it even has a no-args parameter.
But the actual error I'm getting is:
class type required but B found
My current use case is: I want to be able to redefine the equals/hashcode of arbitrary objects that are given to me (I can't really get away from that as I'll have then to deliver the objects to some faulty framework that will use those objects' equals / hashcodes, so I have no control over that).
The obvious way to do that would be through inheritance. Is there some way of doing this?

It's definitely impossible in the general case.
Supposed I passed a final type for B, such as String. There would be no way to subclass that. So, you can't do it for arbitrary B.
Depending on how this other framework works, you might be able to pass it an AnyRef instead. Otherwise, you might be able to pull something off with macros, but more information is needed to determine this.

Brian answers the question in the title (you can also consider that B can have abstract methods you wouldn't know to define). But
I want to be able to redefine the equals/hashcode of arbitrary objects that are given to me
suggests a different signature:
def f[B <: AnyRef](x: B): B = ...
and this one is doable. With limitations, of course. If B is an interface, you can use dynamic proxies from Java standard library,
and for classes you need a library like CGLIB. Approximately (untested):
def f[B <: AnyRef](x: B): B = {
val enhancer = new Enhancer()
enhancer.setSuperclass(x.getClass)
val interceptor: MethodInterceptor = (obj, method, args, proxy) =>
method.getName match {
case "equals" => // your equals impl
case "hashCode" => // your hashCode impl
case _ => proxy.invokeSuper(obj, args)
}
enhancer.setCallback(interceptor)
enhancer.create() as B
}

Related

Implementing functor map for class-tagged arguments only

I have the following data structure:
class MyDaSt[A]{
def map[B: ClassTag](f: A => B) = //...
}
I'd like to implement a Functor instance for to be able to use ad-hoc polymorphism. The obvious attempt would be as follows:
implicit val mydastFunctor: Functor[MyDaSt] = new Functor[MyDaSt] {
override def map[A, B](fa: MyDaSt[A])(f: A => B): MyDaSt[B] = fa.map(f) //compile error
}
It obviously does not compile because we did not provide an implicit ClassTag[B]. But would it be possible to use map only with functions f: A => B such that there is ClassTag[B]. Otherwise compile error. I mean something like that:
def someFun[A, B, C[_]: Functor](cc: C[A], f: A => B) = cc.map(f)
val f: Int => Int = //...
val v: MyDaSt[Int] = //...
someFunc(v, f) //fine, ClassTag[Int] exists and in scope
I cannot change its implementation in anyway, but I can create wrappers (which does not look helpful through) or inheritance. I'm free to use shapeless of any version.
I currently think that shapeless is a way to go in such case...
I'll expand on what comments touched:
Functor
cats.Functor describes an endofunctor in a category of Scala types - that is, you should be able to map with a function A => B where A and B must support any Scala types.
What you have is a mathematical functor, but in a different, smaller category of types that have a ClassTag. These general functors are somewhat uncommon - I think for stdlib types, only SortedSet can be a functor on a category of ordered things - so it's fairly unexplored territory in Scala FP right now, only rumored somewhat in Scalaz 8.
Cats does not have any tools for abstracting over such things, so you won't get any utility methods and ecosystem support. You can use that answer linked by #DmytroMitin if you want to roll your own
Coyoneda
Coyoneda can make an endofunctor on Scala types from any type constructor F[_]. The idea is simple:
have some initial value F[Initial]
have a function Initial => A
to map with A => B, you don't touch initial value, but simply compose the functions to get Initial => B
You can lift any F[A] into cats.free.Coyoneda[F, A]. The question is how to get F[A] out.
If F is a cats.Functor, then it is totally natural that you can use it's native map, and, in fact, there will not be any difference in result with using Coyoneda and using F directly, due to functor law (x.map(f).map(g) <-> x.map(f andThen g)).
In your case, it's not. But you can tear cats.free.Coyoneda apart and delegate to your own map:
def coy[A](fa: MyDaSt[A]): Coyoneda[MyDaSt, A] = Coyoneda.lift(fa)
def unCoy[A: ClassTag](fa: Coyoneda[MyDaSt, A]): MyDaSt[A] =
fa.fi.map(fa.k) // fi is initial value, k is the composed function
Which will let you use functions expecting cats.Functor:
def generic[F[_]: Functor, A: Show](fa: F[A]): F[String] = fa.map(_.show)
unCoy(generic(coy(v))) // ok, though cumbersome and needs -Ypartial-unification on scala prior to 2.13
(runnable example on scastie)
An obvious limitation is that you need to have a ClassTag[A] in any spot you want to call unCo - even if you did not need it to create an instance of MyDaSt[A] in the first place.
The less obvious one is that you don't automatically have that guarantee about having no behavioral differences. Whether it's okay or not depends on what your map does - e.g. if it's just allocating some Arrays, it shouldn't cause issues.

An abstract signature for "without" some type

I want a method of a type to return the type it is mixed into. E.g., something in the spirit of the following:
trait A {
def withoutA: this.type without A
}
So in case of type A with B with C, the method withoutA would have a signature B with C, in case of A with D - just D.
Is this achievable and how if it is?
Here's an example of how it could be used:
trait Limit {
def limit(a: Int): this.type without Limit
}
trait Offset {
def offset(a: Int): this.type without Offset
}
val sqlBuilder = new Limit with Offset { ... }
sqlBuilder.limit(2).offset(4) // valid code
sqlBuilder.offset(4).limit(2) // valid code
sqlBuilder.limit(2).limit(4) // invalid code
A stab in the dark here, but the type Negation as defined by shapeless might work here.
type ¬[A] = A => Nothing
trait A {
def withoutA: this.type with ¬[A]
}
Without access to a REPL right now, I haven't had the chance to test this though. I'd also be interested to know the use-case.
UPDATE:
If what you really want is a builder that progressively reduces the operations available as you use them, then phantom types and the type-safe builder pattern come to the rescue:
http://james-iry.blogspot.co.uk/2010/10/phantom-types-in-haskell-and-scala.html
http://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html
You might want to update the title of the question as well, so it's easier for others to find :)

How to test type conformance of higher-kinded types in Scala

I am trying to test whether two "containers" use the same higher-kinded type. Look at the following code:
import scala.reflect.runtime.universe._
class Funct[A[_],B]
class Foo[A : TypeTag](x: A) {
def test[B[_]](implicit wt: WeakTypeTag[B[_]]) =
println(typeOf[A] <:< weakTypeOf[Funct[B,_]])
def print[B[_]](implicit wt: WeakTypeTag[B[_]]) = {
println(typeOf[A])
println(weakTypeOf[B[_]])
}
}
val x = new Foo(new Funct[Option,Int])
x.test[Option]
x.print[Option]
The output is:
false
Test.Funct[Option,Int]
scala.Option[_]
However, I expect the conformance test to succeed. What am I doing wrong? How can I test for higher-kinded types?
Clarification
In my case, the values I am testing (the x: A in the example) come in a List[c.Expr[Any]] in a Macro. So any solution relying on static resolution (as the one I have given), will not solve my problem.
It's the mixup between underscores used in type parameter definitions and elsewhere. The underscore in TypeTag[B[_]] means an existential type, hence you get a tag not for B, but for an existential wrapper over it, which is pretty much useless without manual postprocessing.
Consequently typeOf[Funct[B, _]] that needs a tag for raw B can't make use of the tag for the wrapper and gets upset. By getting upset I mean it refuses to splice the tag in scope and fails with a compilation error. If you use weakTypeOf instead, then that one will succeed, but it will generate stubs for everything it couldn't splice, making the result useless for subtyping checks.
Looks like in this case we really hit the limits of Scala in the sense that there's no way for us to refer to raw B in WeakTypeTag[B], because we don't have kind polymorphism in Scala. Hopefully something like DOT will save us from this inconvenience, but in the meanwhile you can use this workaround (it's not pretty, but I haven't been able to come up with a simpler approach).
import scala.reflect.runtime.universe._
object Test extends App {
class Foo[B[_], T]
// NOTE: ideally we'd be able to write this, but since it's not valid Scala
// we have to work around by using an existential type
// def test[B[_]](implicit tt: WeakTypeTag[B]) = weakTypeOf[Foo[B, _]]
def test[B[_]](implicit tt: WeakTypeTag[B[_]]) = {
val ExistentialType(_, TypeRef(pre, sym, _)) = tt.tpe
// attempt #1: just compose the type manually
// but what do we put there instead of question marks?!
// appliedType(typeOf[Foo], List(TypeRef(pre, sym, Nil), ???))
// attempt #2: reify a template and then manually replace the stubs
val template = typeOf[Foo[Hack, _]]
val result = template.substituteSymbols(List(typeOf[Hack[_]].typeSymbol), List(sym))
println(result)
}
test[Option]
}
// has to be top-level, otherwise the substituion magic won't work
class Hack[T]
An astute reader will notice that I used WeakTypeTag in the signature of foo, even though I should be able to use TypeTag. After all, we call foo on an Option which is a well-behaved type, in the sense that it doesn't involve unresolved type parameters or local classes that pose problems for TypeTags. Unfortunately, it's not that simple because of https://issues.scala-lang.org/browse/SI-7686, so we're forced to use a weak tag even though we shouldn't need to.
The following is an answer that works for the example I have given (and might help others), but does not apply to my (non-simplified) case.
Stealing from #pedrofurla's hint, and using type-classes:
trait ConfTest[A,B] {
def conform: Boolean
}
trait LowPrioConfTest {
implicit def ctF[A,B] = new ConfTest[A,B] { val conform = false }
}
object ConfTest extends LowPrioConfTest {
implicit def ctT[A,B](implicit ev: A <:< B) =
new ConfTest[A,B] { val conform = true }
}
And add this to Foo:
def imp[B[_]](implicit ct: ConfTest[A,Funct[B,_]]) =
println(ct.conform)
Now:
x.imp[Option] // --> true
x.imp[List] // --> false

Scala: Building a complex hierarchy of traits and classes

I have posted several questions on SO recently dealing with Scala traits, representation types, member types, manifests, and implicit evidence. Behind these questions is my project to build modeling software for biological protein networks. Despite the immensely helpful answers, which have gotten me closer than I ever could get on my own, I have still not arrived at an solution for my project. A couple of answers have suggested that my design is flawed, which is why the solutions to the Foo-framed questions don't work in practice. Here I am posting a more complicated (but still greatly simplified) version of my problem. My hope is that the problem and solution will be broadly useful for people trying to build complex hierarchies of traits and classes in Scala.
The highest-level class in my project is the biological reaction rule. A rule describes how one or two reactants are transformed by a reaction. Each reactant is a graph that has nodes called monomers and edges that connect between named sites on the monomers. Each site also has a state that it can be in. Edit: The concept of the edges have been removed from the example code because they complicate the example without contributing much to the question. A rule might say something like this: there is one reactant made of monomer A bound to monomer B through sites a1 and b1, respectively; the bond is broken by the rule leaving sites a1 and b1 unbound; simultaneously on monomer A, the state of site a1 is changed from U to P. I would write this as:
A(a1~U-1).B(b1-1) -> A(a1~P) + B(b1)
(Parsing strings like this in Scala was so easy, it made my head spin.) The -1 indicates that bond #1 is between those sites--the number is just a arbitrary label.
Here is what I have so far along with the reasoning for why I added each component. It compiles, but only with gratuitous use of asInstanceOf. How do I get rid of the asInstanceOfs so that the types match?
I represent rules with a basic class:
case class Rule(
reactants: Seq[ReactantGraph], // The starting monomers and edges
producedMonomers: Seq[ProducedMonomer] // Only new monomers go here
) {
// Example method that shows different monomers being combined and down-cast
def combineIntoOneGraph: Graph = {
val all_monomers = reactants.flatMap(_.monomers) ++ producedMonomers
GraphClass(all_monomers)
}
}
The class for graphs GraphClass has type parameters because so that I can put constraints on what kinds of monomers and edges are allowed in a particular graph; for example, there cannot be any ProducedMonomers in the Reactant of a Rule. I would also like to be able to collect all the Monomers of a particular type, say ReactantMonomers. I use type aliases to manage the constraints.
case class GraphClass[
+MonomerType <: Monomer
](
monomers: Seq[MonomerType]
) {
// Methods that demonstrate the need for a manifest on MonomerClass
def justTheProductMonomers: Seq[ProductMonomer] = {
monomers.collect{
case x if isProductMonomer(x) => x.asInstanceOf[ProductMonomer]
}
}
def isProductMonomer(monomer: Monomer): Boolean = (
monomer.manifest <:< manifest[ProductStateSite]
)
}
// The most generic Graph
type Graph = GraphClass[Monomer]
// Anything allowed in a reactant
type ReactantGraph = GraphClass[ReactantMonomer]
// Anything allowed in a product, which I sometimes extract from a Rule
type ProductGraph = GraphClass[ProductMonomer]
The class for monomers MonomerClass has type parameters, as well, so that I can put constraints on the sites; for example, a ConsumedMonomer cannot have a StaticStateSite. Furthermore, I need to collect all the monomers of a particular type to, say, collect all the monomers in a rule that are in the product, so I add a Manifest to each type parameter.
case class MonomerClass[
+StateSiteType <: StateSite : Manifest
](
stateSites: Seq[StateSiteType]
) {
type MyType = MonomerClass[StateSiteType]
def manifest = implicitly[Manifest[_ <: StateSiteType]]
// Method that demonstrates the need for implicit evidence
// This is where it gets bad
def replaceSiteWithIntersection[A >: StateSiteType <: ReactantStateSite](
thisSite: A, // This is a member of this.stateSites
monomer: ReactantMonomer
)(
// Only the sites on ReactantMonomers have the Observed property
implicit evidence: MyType <:< ReactantMonomer
): MyType = {
val new_this = evidence(this) // implicit evidence usually needs some help
monomer.stateSites.find(_.name == thisSite.name) match {
case Some(otherSite) =>
val newSites = stateSites map {
case `thisSite` => (
thisSite.asInstanceOf[StateSiteType with ReactantStateSite]
.createIntersection(otherSite).asInstanceOf[StateSiteType]
)
case other => other
}
copy(stateSites = newSites)
case None => this
}
}
}
type Monomer = MonomerClass[StateSite]
type ReactantMonomer = MonomerClass[ReactantStateSite]
type ProductMonomer = MonomerClass[ProductStateSite]
type ConsumedMonomer = MonomerClass[ConsumedStateSite]
type ProducedMonomer = MonomerClass[ProducedStateSite]
type StaticMonomer = MonomerClass[StaticStateSite]
My current implementation for StateSite does not have type parameters; it is a standard hierarchy of traits, terminating in classes that have a name and some Strings that represent the appropriate state. (Be nice about using strings to hold object states; they are actually name classes in my real code.) One important purpose of these traits is provide functionality that all the subclasses need. Well, isn't that the purpose of all traits. My traits are special in that many of the methods make small changes to a property of the object that is common to all subclasses of the trait and then return a copy. It would be preferable if the return type matched the underlying type of the object. The lame way to do this is to make all the trait methods abstract, and copy the desired methods into all the subclasses. I am unsure of the proper Scala way to do this. Some sources suggest a member type MyType that stores the underlying type (shown here). Other sources suggest a representation type parameter.
trait StateSite {
type MyType <: StateSite
def name: String
}
trait ReactantStateSite extends StateSite {
type MyType <: ReactantStateSite
def observed: Seq[String]
def stateCopy(observed: Seq[String]): MyType
def createIntersection(otherSite: ReactantStateSite): MyType = {
val newStates = observed.intersect(otherSite.observed)
stateCopy(newStates)
}
}
trait ProductStateSite extends StateSite
trait ConservedStateSite extends ReactantStateSite with ProductStateSite
case class ConsumedStateSite(name: String, consumed: Seq[String])
extends ReactantStateSite {
type MyType = ConsumedStateSite
def observed = consumed
def stateCopy(observed: Seq[String]) = copy(consumed = observed)
}
case class ProducedStateSite(name: String, Produced: String)
extends ProductStateSite
case class ChangedStateSite(
name: String,
consumed: Seq[String],
Produced: String
)
extends ConservedStateSite {
type MyType = ChangedStateSite
def observed = consumed
def stateCopy(observed: Seq[String]) = copy(consumed = observed)
}
case class StaticStateSite(name: String, static: Seq[String])
extends ConservedStateSite {
type MyType = StaticStateSite
def observed = static
def stateCopy(observed: Seq[String]) = copy(static = observed)
}
My biggest problems are with methods framed like MonomerClass.replaceSiteWithIntersection. A lot of methods do some complicated search for particular members of the class, then pass those members to other functions where complicated changes are made to them and return a copy, which then replaces the original in a copy of the higher-level object. How should I parameterize methods (or the classes) so that the calls are type safe? Right now I can get the code to compile only with lots of asInstanceOfs everywhere. Scala is particularly unhappy with passing instances of a type or member parameter around because of two main reasons that I can see: (1) the covariant type parameter ends up as input to any method that takes them as input, and (2) it is difficult to convince Scala that a method that returns a copy indeed returns an object with exactly the same type as was put in.
I have undoubtedly left some things that will not be clear to everyone. If there are any details I need to add, or excess details I need to delete, I will try to be quick to clear things up.
Edit
#0__ replaced the replaceSiteWithIntersection with a method that compiled without asInstanceOf. Unfortunately, I can't find a way to call the method without a type error. His code is essentially the first method in this new class for MonomerClass; I added the second method that calls it.
case class MonomerClass[+StateSiteType <: StateSite/* : Manifest*/](
stateSites: Seq[StateSiteType]) {
type MyType = MonomerClass[StateSiteType]
//def manifest = implicitly[Manifest[_ <: StateSiteType]]
def replaceSiteWithIntersection[A <: ReactantStateSite { type MyType = A }]
(thisSite: A, otherMonomer: ReactantMonomer)
(implicit ev: this.type <:< MonomerClass[A])
: MonomerClass[A] = {
val new_this = ev(this)
otherMonomer.stateSites.find(_.name == thisSite.name) match {
case Some(otherSite) =>
val newSites = new_this.stateSites map {
case `thisSite` => thisSite.createIntersection(otherSite)
case other => other
}
copy(stateSites = newSites)
case None => new_this // This throws an exception in the real program
}
}
// Example method that calls the previous method
def replaceSomeSiteOnThisOtherMonomer(otherMonomer: ReactantMonomer)
(implicit ev: MyType <:< ReactantMonomer): MyType = {
// Find a state that is a current member of this.stateSites
// Obviously, a more sophisticated means of selection is actually used
val thisSite = ev(this).stateSites(0)
// I can't get this to compile even with asInstanceOf
replaceSiteWithIntersection(thisSite, otherMonomer)
}
}
I have reduced your problem to traits, and I am starting to understand why you are getting into troubles with casts and abstract types.
What you are actually missing is ad-hoc polymorphism, which you obtain through the following:
- Writing a method with generic signature relying on an implicit of the same generic to delegate the work to
- Making the implicit available only for specific value of that generic parameter, which will turn into a "implicit not found" compile time error when you try to do something illegal.
Let's now look to the problem in order. The first is that the signature of your method is wrong for two reasons:
When replacing a site you want to create a new monomer of the new generic type, much as you do when you add to a collection an object which is a superclass of the existing generic type: you get a new collection whose type parameter is the superclass. You should yield this new Monomer as a result.
You are not sure that the operation will yield a result (in case you can't really replace a state). In such a case the right type it's Option[T]
def replaceSiteWithIntersection[A >: StateSiteType <: ReactantStateSite]
(thisSite: A, monomer: ReactantMonomer): Option[MonomerClass[A]]
If we now look digger in the type errors, we can see that the real type error comes from this method:
thisSite.createIntersection
The reason is simple: it's signature is not coherent with the rest of your types, because it accepts a ReactantSite but you want to call it passing as parameter one of your stateSites (which is of type Seq[StateSiteType] ) but you have no guarantee that
StateSiteType<:<ReactantSite
Now let's see how evidences can help you:
trait Intersector[T] {
def apply(observed: Seq[String]): T
}
trait StateSite {
def name: String
}
trait ReactantStateSite extends StateSite {
def observed: Seq[String]
def createIntersection[A](otherSite: ReactantStateSite)(implicit intersector: Intersector[A]): A = {
val newStates = observed.intersect(otherSite.observed)
intersector(newStates)
}
}
import Monomers._
trait MonomerClass[+StateSiteType <: StateSite] {
val stateSites: Seq[StateSiteType]
def replaceSiteWithIntersection[A >: StateSiteType <: ReactantStateSite](thisSite: A, otherMonomer: ReactantMonomer)(implicit intersector:Intersector[A], ev: StateSiteType <:< ReactantStateSite): Option[MonomerClass[A]] = {
def replaceOrKeep(condition: (StateSiteType) => Boolean)(f: (StateSiteType) => A)(implicit ev: StateSiteType<:<A): Seq[A] = {
stateSites.map {
site => if (condition(site)) f(site) else site
}
}
val reactantSiteToIntersect:Option[ReactantStateSite] = otherMonomer.stateSites.find(_.name == thisSite.name)
reactantSiteToIntersect.map {
siteToReplace =>
val newSites = replaceOrKeep {_ == thisSite } { item => thisSite.createIntersection( ev(item) ) }
MonomerClass(newSites)
}
}
}
object MonomerClass {
def apply[A <: StateSite](sites:Seq[A]):MonomerClass[A] = new MonomerClass[A] {
val stateSites = sites
}
}
object Monomers{
type Monomer = MonomerClass[StateSite]
type ReactantMonomer = MonomerClass[ReactantStateSite]
type ProductMonomer = MonomerClass[ProductStateSite]
type ProducedMonomer = MonomerClass[ProducedStateSite]
}
Please note that this pattern can be used with no special imports if you use in a clever way implicit resolving rules (for example you put your insector in the companion object of Intersector trait, so that it will be automatically resolved).
While this pattern works perfectly, there is a limitation connected to the fact that your solution works only for a specific StateSiteType. Scala collections solve a similar problem adding another implicit, which is call CanBuildFrom. In our case we will call it CanReact
You will have to make your MonomerClass invariant, which might be a problem though (why do you need covariance, however?)
trait CanReact[A, B] {
implicit val intersector: Intersector[B]
def react(a: A, b: B): B
def reactFunction(b:B) : A=>B = react(_:A,b)
}
object CanReact {
implicit def CanReactWithReactantSite[A<:ReactantStateSite](implicit inters: Intersector[A]): CanReact[ReactantStateSite,A] = {
new CanReact[ReactantStateSite,A] {
val intersector = inters
def react(a: ReactantStateSite, b: A) = a.createIntersection(b)
}
}
}
trait MonomerClass[StateSiteType <: StateSite] {
val stateSites: Seq[StateSiteType]
def replaceSiteWithIntersection[A >: StateSiteType <: ReactantStateSite](thisSite: A, otherMonomer: ReactantMonomer)(implicit canReact:CanReact[StateSiteType,A]): Option[MonomerClass[A]] = {
def replaceOrKeep(condition: (StateSiteType) => Boolean)(f: (StateSiteType) => A)(implicit ev: StateSiteType<:<A): Seq[A] = {
stateSites.map {
site => if (condition(site)) f(site) else site
}
}
val reactantSiteToIntersect:Option[ReactantStateSite] = otherMonomer.stateSites.find(_.name == thisSite.name)
reactantSiteToIntersect.map {
siteToReplace =>
val newSites = replaceOrKeep {_ == thisSite } { canReact.reactFunction(thisSite)}
MonomerClass(newSites)
}
}
}
With such an implementation, whenever you want to make the possibility to replace a site with another site of a different type, all you need is to make available new implicit instances of CanReact with different types.
I will conclude with a (I hope) clear explanation of why you should not need covariance.
Let's say you have a Consumer[T] and a Producer[T].
You need covariance when you want to provide to the Consumer[T1] a Producer[T2] where T2<:<T1 . But if you need to use the value produced by T2 inside T1, you can
class ConsumerOfStuff[T <: CanBeContained] {
def doWith(stuff: Stuff[T]) = stuff.t.writeSomething
}
trait CanBeContained {
def writeSomething: Unit
}
class A extends CanBeContained {
def writeSomething = println("hello")
}
class B extends A {
override def writeSomething = println("goodbye")
}
class Stuff[T <: CanBeContained](val t: T)
object VarianceTest {
val stuff1 = new Stuff(new A)
val stuff2 = new Stuff(new B)
val consumerOfStuff = new ConsumerOfStuff[A]
consumerOfStuff.doWith(stuff2)
}
This stuff clearly not compiles:
error: type mismatch; found : Stuff[B] required: Stuff[A] Note: B <:
A, but class Stuff is invariant in type T. You may wish to define T as
+T instead. (SLS 4.5) consumerOfStuff.doWith(stuff2).
But again, this come from a misinterpretation of usage of variance, as How are co- and contra-variance used in designing business applications? Kris Nuttycombe answer explain. If we refactor like the following
class ConsumerOfStuff[T <: CanBeContained] {
def doWith[A<:T](stuff: Stuff[A]) = stuff.t.writeSomething
}
You could see everything compiling fine.
Not an answer, but what I can observe from looking over the question:
I see MonomerClass but not Monomer
My guts say you should avoid manifests when possible, as you have seen they can make things complicated. I don't think you will need them. For example the justTheProductMonomers method in GraphClass – since you have complete control over your class hierarchy, why not add test methods for anything involving runtime checks to Monomer directly? E.g.
trait Monomer {
def productOption: Option[ProductMonomer]
}
then you'll have
def justTheProductMonomers : Seq[ProductMonomer] = monomers.flatMap( _.productOption )
and so forth.
The problem here is that it seems you can have a generic monomer satisfying the product predicate, while you somehow want sub-type ProductMonomer.
The general advise I would give is first to define your matrix of tests that you need to process the rules, and then put those tests as methods into the particular traits, unless you have a flat hierarchy for which you can do pattern matching, which is easier since the disambiguation will appear concentrated at your use site, and not spread across all implementing types.
Also don't try to overdue it with compile-time type constraints. Often it's perfectly fine to have some constraints checked at runtime. That way at least you can construct a fully working system, and then you can try to spot the points where you can convert a runtime check into a compile time check, and decide whether the effort is worth it or not. It is appealing to solve things on the type level in Scala, because of its sophistication, but it also requires the most skills to do it right.
There are multiple problems. First, the whole method is weird: On the one hand you passing in a monomer argument, and if the argument thisState is found, the method has nothing to do with the receiver—then why is this a method in MonomerClass at all and not a "free floating" function—, on the other hand you fall back to returning this if thisSite is not found. Since you originally had also implicit evidence: MyType <:< ReactantMonomer, my guess is the whole monomer argument is obsolete, and you actually wanted to operate on new_this.
A bit of cleanup, forgetting the manifests for the moment, you could have
case class MonomerClass[+StateSiteType <: StateSite, +EdgeSiteType <: EdgeSite](
stateSites: Seq[StateSiteType], edgeSites: Seq[EdgeSiteType]) {
def replaceSiteWithIntersection[A <: ReactantStateSite { type MyType = A }]
(thisSite: A)(implicit ev: this.type <:< MonomerClass[A, ReactantEdgeSite])
: MonomerClass[A, ReactantEdgeSite] = {
val monomer = ev(this)
monomer.stateSites.find(_.name == thisSite.name) match {
case Some(otherSite) =>
val newSites = monomer.stateSites map {
case `thisSite` => thisSite.createIntersection(otherSite)
case other => other
}
monomer.copy(stateSites = newSites)
case None => monomer
}
}
}
This was an interesting problem, it took me some iterations to get rid of the (wrong!) casting. Now it is actually quite readable: This method is restricted to the evidence that StateSiteType is actually a subtype A of ReactantStateSite. Therefore, the type parameter A <: ReactantStateSite { type MyType = A }—the last bit is interesting, and this was a new find for myself: You can specify the type member here to make sure that your return type from createIntersection is actually A.
There is still something odd with your method, because if I'm not mistaken, you will end up calling x.createIntersection(x) (intersecting thisSite with itself, which is a no-op).
One thing that is flawed about replaceSiteWithIntersection is that according to the method signature the type of thisSite (A) is a super-type of StateSiteType and a sub-type of ReactantStateSite.
But then you eventually cast it to StateSiteType with ReactantStateSite. That doesn't make sense to me.
Where do you get the assurance from that A suddenly is a StateSiteType?

What does "abstract over" mean?

Often in the Scala literature, I encounter the phrase "abstract over", but I don't understand the intent. For example, Martin Odersky writes
You can pass methods (or "functions") as parameters, or you can abstract over them. You can specify types as parameters, or you can abstract over them.
As another example, in the "Deprecating the Observer Pattern" paper,
A consequence from our event streams being first-class values is that we can abstract over them.
I have read that first order generics "abstract over types", while monads "abstract over type constructors". And we also see phrases like this in the Cake Pattern paper. To quote one of many such examples:
Abstract type members provide flexible way to abstract over concrete types of components.
Even relevant stack overflow questions use this terminology. "can't existentially abstract over parameterized type..."
So... what does "abstract over" actually mean?
In algebra, as in everyday concept formation, abstractions are formed by grouping things by some essential characteristics and omitting their specific other characteristics. The abstraction is unified under a single symbol or word denoting the similarities. We say that we abstract over the differences, but this really means we're integrating by the similarities.
For example, consider a program that takes the sum of the numbers 1, 2, and 3:
val sumOfOneTwoThree = 1 + 2 + 3
This program is not very interesting, since it's not very abstract. We can abstract over the numbers we're summing, by integrating all lists of numbers under a single symbol ns:
def sumOf(ns: List[Int]) = ns.foldLeft(0)(_ + _)
And we don't particularly care that it's a List either. List is a specific type constructor (takes a type and returns a type), but we can abstract over the type constructor by specifying which essential characteristic we want (that it can be folded):
trait Foldable[F[_]] {
def foldl[A, B](as: F[A], z: B, f: (B, A) => B): B
}
def sumOf[F[_]](ns: F[Int])(implicit ff: Foldable[F]) =
ff.foldl(ns, 0, (x: Int, y: Int) => x + y)
And we can have implicit Foldable instances for List and any other thing we can fold.
implicit val listFoldable = new Foldable[List] {
def foldl[A, B](as: List[A], z: B, f: (B, A) => B) = as.foldLeft(z)(f)
}
implicit val setFoldable = new Foldable[Set] {
def foldl[A, B](as: Set[A], z: B, f: (B, A) => B) = as.foldLeft(z)(f)
}
val sumOfOneTwoThree = sumOf(List(1,2,3))
What's more, we can abstract over both the operation and the type of the operands:
trait Monoid[M] {
def zero: M
def add(m1: M, m2: M): M
}
trait Foldable[F[_]] {
def foldl[A, B](as: F[A], z: B, f: (B, A) => B): B
def foldMap[A, B](as: F[A], f: A => B)(implicit m: Monoid[B]): B =
foldl(as, m.zero, (b: B, a: A) => m.add(b, f(a)))
}
def mapReduce[F[_], A, B](as: F[A], f: A => B)
(implicit ff: Foldable[F], m: Monoid[B]) =
ff.foldMap(as, f)
Now we have something quite general. The method mapReduce will fold any F[A] given that we can prove that F is foldable and that A is a monoid or can be mapped into one. For example:
case class Sum(value: Int)
case class Product(value: Int)
implicit val sumMonoid = new Monoid[Sum] {
def zero = Sum(0)
def add(a: Sum, b: Sum) = Sum(a.value + b.value)
}
implicit val productMonoid = new Monoid[Product] {
def zero = Product(1)
def add(a: Product, b: Product) = Product(a.value * b.value)
}
val sumOf123 = mapReduce(List(1,2,3), Sum)
val productOf456 = mapReduce(Set(4,5,6), Product)
We have abstracted over monoids and foldables.
To a first approximation, being able to "abstract over" something means that instead of using that something directly, you can make a parameter of it, or otherwise use it "anonymously".
Scala allows you to abstract over types, by allowing classes, methods, and values to have type parameters, and values to have abstract (or anonymous) types.
Scala allows you to abstract over actions, by allowing methods to have function parameters.
Scala allows you to abstract over features, by allowing types to be defined structurally.
Scala allows you to abstract over type parameters, by allowing higher-order type parameters.
Scala allows you to abstract over data access patterns, by allowing you to create extractors.
Scala allows you to abstract over "things that can be used as something else", by allowing implicit conversions as parameters. Haskell does similarly with type classes.
Scala doesn't (yet) allow you to abstract over classes. You can't pass a class to something, and then use that class to create new objects. Other languages do allow abstraction over classes.
("Monads abstract over type constructors" is only true in a very restrictive way. Don't get hung up on it until you have your "Aha! I understand monads!!" moment.)
The ability to abstract over some aspect of computation is basically what allows code reuse, and enables the creation of libraries of functionality. Scala allows many more sorts of things to be abstracted over than more mainstream languages, and libraries in Scala can be correspondingly more powerful.
An abstraction is a sort of generalization.
http://en.wikipedia.org/wiki/Abstraction
Not only in Scala but many languages there is a need to have such mechanisms to reduce complexity(or at least create a hierarchy that partitions information into easier to understand pieces).
A class is an abstraction over a simple data type. It is sort of like a basic type but actually generalizes them. So a class is more than a simple data type but has many things in common with it.
When he says "abstracting over" he means the process by which you generalize. So if you are abstracting over methods as parameters you are generalizing the process of doing that. e.g., instead of passing methods to functions you might create some type of generalized way to handle it(such as not passing methods at all but building up a special system to deal with it).
In this case he specifically means the process of abstracting a problem and creating a oop like solution to the problem. C has very little ability to abstract(you can do it but it gets messy real quick and the language doesn't directly support it). If you wrote it in C++ you could use oop concepts to reduce the complexity of the problem(well, it's the same complexity but the conceptualization is generally easier(at least once you learn to think in terms of abstractions)).
e.g., If I needed a special data type that was like an int but, lets say restricted I could abstract over it by creating a new type that could be used like an int but had those properties I needed. The process I would use to do such a thing would be called an "abstracting".
Here is my narrow show and tell interpretation. It's self-explanatory and runs in the REPL.
class Parameterized[T] { // type as a parameter
def call(func: (Int) => Int) = func(1) // function as a parameter
def use(l: Long) { println(l) } // value as a parameter
}
val p = new Parameterized[String] // pass type String as a parameter
p.call((i:Int) => i + 1) // pass function increment as a parameter
p.use(1L) // pass value 1L as a parameter
abstract class Abstracted {
type T // abstract over a type
def call(i: Int): Int // abstract over a function
val l: Long // abstract over value
def use() { println(l) }
}
class Concrete extends Abstracted {
type T = String // specialize type as String
def call(i:Int): Int = i + 1 // specialize function as increment function
val l = 1L // specialize value as 1L
}
val a: Abstracted = new Concrete
a.call(1)
a.use()
The other answers give already a good idea of what kinds of abstractions exist. Lets go over the quotes one by one, and provide an example:
You can pass methods (or "functions")
as parameters, or you can abstract
over them. You can specify types as
parameters, or you can abstract over
them.
Pass function as a parameter: List(1,-2,3).map(math.abs(x)) Clearly abs is passed as parameter here. map itself abstracts over a function that does a certain specialiced thing with each list element. val list = List[String]() specifies a type paramter (String). You could write a collection type which uses abstract type members instead: val buffer = Buffer{ type Elem=String }. One difference is that you have to write def f(lis:List[String])... but def f(buffer:Buffer)..., so the element type is kind of "hidden" in the second method.
A consequence from our event streams
being first-class values is that we
can abstract over them.
In Swing an event just "happens" out of the blue, and you have to deal with it here and now. Event streams allow you to do all the plumbing an wiring in a more declarative way. E.g. when you want to change the responsible listener in Swing, you have to unregister the old and to register the new one, and to know all the gory details (e.g. threading issues). With event streams, the source of the events becomes a thing you can simply pass around, making it not very different from a byte or char stream, hence a more "abstract" concept.
Abstract type members provide flexible
way to abstract over concrete types of
components.
The Buffer class above is already an example for this.
Answers above provide an excellent explanation, but to summarize it in a single sentence, I would say:
Abstracting over something is the very same as neglecting it where irrelevant.