Why is the Scala compiler giving me an error when passing a Kotlin sealed class into a constructor? - scala

I have a sealed class, written in Kotlin:
sealed class Schema {
class RecordSchema(val fields: List<Field>): Schema()
class ArraySchema(val elementSchema: Schema): Schema()
...
}
And another class that takes RecordSchema as a parameter:
class Enrichment(config: Config, val schema: RecordSchema) { ... }
In Scala I have a class that, among other things, get an instance of the RecordSchema and then create an instance of the Enrichment.
object Job {
def main(args: Array[String]): Unit = {
/// some initializing of resources... and then...
val recordSchema = schemas.getSchema(id) // type is Schema.RecordSchema
val enrichment = Enrichment(config, recordSchema) // this is where scalac errors out
}
}
The scala compiler ends up printing this error message:
Error:(52, 62) type mismatch;
found : com.companyname.enricher.schemas.com.companyname.enricher.schemas.com.companyname.enricher.schemas.
required: com.companyname.enricher.schemas.(some other)com.companyname.enricher.schemas.com.companyname.enricher.schemas.
val enrichment = new Enrichment(config, recordSchema)
If I cast recordSchema using asInstanceOf I get another, not so useful, error:
Error:(52, 62) type mismatch;
found : com.companyname.enricher.schemas.Schema.RecordSchema
required: com.companyname.enricher.schemas.com.companyname.enricher.schemas.
val enrichment = new Enrichment(config, recordSchema.asInstanceOf[RecordSchema])
Overall, I have no idea why this is happening. If I make the constructor take the parent class as a parameter rather than nested class, it compiles just fine (which is my workaround for now). If I do the same type of thing, except having written the sourcecode in Java rather than Kotlin, this error does not happen. I am using Java 1.8, Kotlin 1.0.4, Scala 2.11.8.
UPDATE:
demonstrated bug here:
https://github.com/mjburghoffer/scala-kotlin-innerclass-bug/tree/master

Looks like Kotlin generates different number of classes for this case. I compiled Java and Kotlin sources and found that Java has additional file ParentSealedJava$1.class. Bytecode of Parent and Sealed classes in Java and Kotlin pretty the same (i inspect bytecode using javap -c), so i think Scala compiler relies somehow on this missing file in Kotlin.

Related

`illegal inheritance` implementing cake pattern with Slick

I'm implementing a web service using Slick (3.3) for the DB layer. I am trying to make the Slick implementation as generic as possible, hoping to achieve DB-agnosticism as well as generic table, table query, and DAO classes that abstract over the services models as much as possible. I'm trying to do this combining several techniques:
A model hierarchy extending from a common base trait
A table hierarchy, extracting common columns for model traits (inspired by http://gavinschulz.com/posts/2016-01-30-common-model-fields-with-slick-3-part-i.html)
DB-agnosticism, relying on the JdbcProfile trait rather than any DB-specific profile implementation ( as described here: https://stackoverflow.com/a/31128239/4234254 and in the slick multi-db docs)
Cake pattern for dependency injection
I'm having trouble layering some of the schema elements, however, and not being a Scala type expert, I've been unable to figure out the solution on my own. I've created a reproduction of the issue, trying to minimalize it as much as possible, and using a mock slick library. The full code can be found here: https://github.com/anqit/slick_cake_minimal_error_repro/blob/master/src/main/scala/com/anqit/repro/Repro.scala but I'll go through it below.
My "slick" library and model classes:
abstract class Table[E]
type TableQuery[W <: Table[_]] = List[W] // not actually a list, but need a concrete type constructor to demonstrate the issue
object TableQuery {
def apply[W <: Table[_]]: TableQuery[W] = List[W]()
}
trait BaseEntity
case class SubEntityA() extends BaseEntity
case class SubEntityB() extends BaseEntity
Combining technique 2 in the list above with the cake pattern, I'm creating traits that wrap schema elements for each model. The base schema includes columns common to entity tables (e.g. id), and entity tables inherit from that:
trait BaseSchema[E <: BaseEntity] {
// provides common functionality
abstract class BaseTableImpl[E] extends Table[E]
def wrapper: TableQuery[_ <: BaseTableImpl[E]]
}
// functionality specific to SubEntityA
trait SchemaA extends BaseSchema[SubEntityA] {
class TableA extends BaseTableImpl[SubEntityA]
// this definition compiles fine without a type annotation
val queryA = TableQuery[TableA]
def wrapper = queryA
}
// functionality specific to SubEntityB that depends on SchemaA
trait SchemaB extends BaseSchema[SubEntityB] { self: SchemaA =>
class TableB extends BaseTableImpl[SubEntityB] {
// uses SchemaA's queryA to make a FK
}
/*
attempting to define wrapper here without a type annotation results in the following compilation error (unlike defining wrapper for SchemaA above):
def wrapper = Wrapper[WrappedB]
type mismatch;
[error] found : Repro.this.Wrapper[SubB.this.WrappedB]
[error] (which expands to) List[SubB.this.WrappedB]
[error] required: Repro.this.Wrapper[_ <: SubB.this.BaseWrapMeImpl[_1]]
[error] (which expands to) List[_ <: SubB.this.BaseWrapMeImpl[_1]]
[error] def wrapper = Wrapper[WrappedB]
[error] ^
it does, however, compile if defined with an explicit type annotation as below
*/
val queryB = TableQuery[TableB]
def wrapper: TableQuery[TableB] = queryB
}
This is where I get my first error, a type mismatch, that I have currently worked around using an explicit type annotation, but I suspect it is related to the main error, stay tuned.
A base DAO, that will provide common query methods:
trait BaseDao[E <: BaseEntity] { self: BaseSchema[E] => }
And finally, putting all the cake layers together:
// now, the actual injection of the traits
class DaoA extends SchemaA
with BaseDao[SubEntityA]
// so far so good...
class DaoB extends SchemaA
with SchemaB
with BaseDao[SubEntityB] // blargh! failure! :
/*
illegal inheritance;
[error] self-type Repro.this.DaoB does not conform to Repro.this.BaseDao[Repro.this.SubEntityB]'s selftype Repro.this.BaseDao[Repro.this.SubEntityB] with Repro.this.BaseSchema[Repro.this.SubEntityB]
[error] with BaseDao[SubEntityB]
[error] ^
*/
The first error (the type mismatch in SchemaB), I'm completely at a loss. One of the few tricks in my bag is to add explicit type annotations when I run in to type-related errors in Scala, which is the only reason I tried that, and got it to compile. I would love an explanation as to why that is happening, and I suspect fixing my code such that I can write that without the type would probably help me with the second error. Which brings me to... the second error. To me, it looks like I've included all of the necessary traits to satisfy the self-type tree, but I guess not. My guess is that SchemaB, while extending BaseSchema[SubEntityB], is somehow not being recognized as a BaseSchema[SubEntityB]? Have I not set up my hierarchy properly? Or maybe I need to use bounds instead of strict type references?

Why Scala Enumeration does not work in Apache Zeppelin but it works in maven

Enumeration works as expected when I use it in a maven project(with the same Scala version).
object t {
object DashStyle extends Enumeration {
val Solid,ShortDash = Value
}
def f(style: DashStyle.Value) = println(style)
def main(args: Array[String]) = f(DashStyle.Solid)
}
But when it runs in Apache Zeppelin(Zeppelin 0.6, Spark 1.6, Scala 2.10, Java 1.8)
object DashStyle extends Enumeration {
val Solid,ShortDash = Value
}
def f(style: DashStyle.Value) = println(style)
f(DashStyle.Solid)
It reports the following error even it says found and required type is exactly the same
<console>:130: error: type mismatch;
found : DashStyle.Value
required: DashStyle.Value
f(DashStyle.Solid)
Why and how should I use it?
I figured out the trick to solve this issue.
In Apache Zeppelin (or Scala REPL). In order to use Enumeration or sealed&object, it should be wrapped in object but not directly define on the root scope.
The reason why it works in maven is that I already put it into an object.
Define enumeration in an object in a Zeppelin paragraph
object t {
object DashStyle extends Enumeration {
val Solid,ShortDash = Value
}
def f(style: DashStyle.Value) = println(style)
}
Then use it in a Zeppelin paragraph
import t._
f(DashStyle.Solid)

Ensure that a scala parent class has a formatter associated with it

I have a simple type hierarchy like the following:
sealed abstract class Config
object Config {
case class Valid(name: String, traits: List[String]) extends Config
case class Invalid(error: String) extends Config
}
implicit val validFormat = jsonFormatFor(Config.Valid)
implicit val invalidFormat = jsonFormatFor(Config.Invalid)
I also have client code that does the following:
newHttpServer().addHandler("/config", extractConfig)
The extractConfig method performs some computations and returns either a Config.Valid or a Config.Invalid, which the server will automatically convert to json by using the implicit json format objects. My problem is that there is a compiler error because extractConfig returns a Config:
type mismatch; found : Config
required: spray.httpx.marshalling.ToResponseMarshallable
If I change the return type of extractConfig to Config.Valid then the server code compiles because jsonFormatFor(...) supplies the necessary automatic type conversion to make the respose a ToResponseMarshaller (though I admit I don't fully understand this automatic conversion as well, being somewhat new to scala). Is there a simple way to solve this by declaring that any subclass of Config must be a ToResponseMarshaller, given that ToResponseMarshaller is a trait that seems to be supplied via implicit conversions?
If you only have Config.Valid and Config.Invalid it should be sufficient that extractConfig returns an Either[Config.Valid, Config.Invalid]. Then your formats above should work.
Another possibility is to write your own jsonwriter (see this thread from the mailing list).

Type error when mocking Slick Query using ScalaMock: what does "some other" mean?

I have used Java for several years, however I'm new to Scala and am still trying to figure out its type system. I'm using Scala 2.10.2, Slick 1.0.1, and ScalaMock 2.10-3.0-M4 in Eclipse Scala IDE 3.0.1
I'm trying to mock out Slick in updateNameById using ScalaMock.
def updateNameById(id: Int, input: String, users: RichTable[Object]) = {
users.where(_.id === id).map{ e => e.test }.update(input)
}
abstract class RichTable[T](name: String = "blank")
extends slick.driver.MySQLDriver.simple.Table[T](name) {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def test = column[String]("test")
}
(I'm actually passing in users: RichTable[User] where User has a complex inheritance hierarchy, but I've temporarily removed the uses of User to simplify the example)
users.where returns a scala.slick.lifted.Query, so I try to mock this out as follows
class ModelTest extends FlatSpec with MockFactory {
def test = {
val mockUsers = mock[RichTable[Object]]
// mockQuery definition
val mockQuery = mock[scala.slick.lifted.Query[RichTable[Object],
scala.slick.lifted.NothingContainer#TableNothing]]
(mockUsers.where _).expects(*).returns(mockQuery)
Main.updateNameById(1, "asdf", mockUsers)
}
}
The mockQuery definition gives me these cryptic type errors
type mismatch;
found : scala.slick.lifted.Query[O(in method union),
scala.slick.lifted.NothingContainer#TableNothing]
required: scala.slick.lifted.Query[(some other)O(in method union),
scala.slick.lifted.NothingContainer#TableNothing]
type mismatch;
found : scala.slick.lifted.Query[O(in method unionAll),
scala.slick.lifted.NothingContainer#TableNothing]
required: scala.slick.lifted.Query[(some other)O(in method unionAll),
scala.slick.lifted.NothingContainer#TableNothing]
I have no idea what "O(in method union[all])" vs. "(some other)O(in method union[All])" means, and Google hasn't been any help (it doesn't help matters that "some other" is an extremely generic phrase - googling "scala some other type error" produces pretty much the same results as "scala type error"). Does anybody know what this means and/or how to fix the type error?

private field in object doesn't compile

I tried to run one example from Programming in Scala but compiler gives me error:
Description Resource Path Location Type
illegal start of statement (no modifiers allowed here) ChecksumAcc.sc /HelloWorld/src line 3 Scala Problem
basically complains about private
import scala.collection.mutable.Map
object ChecksumAcc {
private val cache = Map[String, Int]()
}
I'm using Eclipse for Scala worksheet. Same after updating. I believe it uses 2.9.3 scala compiler. Why doesn't it compile?
Not sure what your actual question is, but the Scala worksheet has some special rules (as indicated by the very clear error message...). One thing you can do if you have to use the worksheet, is to put all your code inside a Worksheet object like this:
object Worksheet {
import scala.collection.mutable.Map
object ChecksumAcc {
private val cache = Map[String, Int]()
}
}
Or alternatively, use Eclipse's "New Scala object..." and use that instead of the worksheet.
To avoid the error message you are seeing, when you are working in a Eclipse Scala work sheet
wrap the Class definition and Companion class (Singleton object) in the same object
object worksheet {
class CheckSumAccumulator {
...
}
object CheckSumAccumulator {
...
}
CheckSumAccumulator.calculate("foobar")
}