score:2
this is because as soon as the type member check
escapes to the outside,
it can immediately appear both in co- and contravariant positions in functions and
methods:
class bad[+a] {
type check[b]
}
class b
class a extends b
val bad: bad[a] = ???
import bad._
def hypotheticalmethodsomewhereoutside1(c: check[b]) = ???
def hypotheticalmethodsomewhereoutside2(i: int): check[b] = ???
the crucial difference to the [b >: a]
type argument in the method check
def check[b >: a]: good[b] = this
is that the single method check
is under your control, you can guarantee that
it does not use a
in a not-covariant position.
in contrast to that, the type member check
can appear in infinitely many other methods
in both co- and contravariant positions, and those methods are not under your control,
so you cannot prohibit the usage of check
in positions in which a
appears not-covariant,
e.g. you cannot prevent hypotheticalmethodsomewhereoutsiden
from the example above to
be defined by someone else.
note that the presence of the method check
is not necessary for your bad
example to fail:
// error: covariant type a occurs in invariant position in type >: a of type b
class bad[+a] {
type check[b >: a] = bad[b]
// def check[b >: a] : check[b] = this
}
however, if you hide the member type check
from everyone
(really everyone, including even other instances of same class, that is,
with the extremely reclusive private[this]
access modifier):
class bad[+a] {
private[this] type check[b >: a] = bad[b]
}
it compiles just nicely.
the private[this]
solves the problem, because with this modifier, only the methods
inside the class have to be inspected, no hypothetical methods somewhere outside
have to be taken into consideration:
class ok[+a] {
private[this] type check[b >: a] = ok[b]
def ok[b >: a](c: check[b]): unit = ???
def alsook[b >: a]: check[b] = ???
}
note that the above can be written just as
class good[+a] {
type check[+b] = good[b]
def ok[b >: a](c: check[b]): unit = ???
def alsook[b >: a]: check[b] = ???
}
which makes sense only if the type constructor good
has way more arguments than check
.
Source: stackoverflow.com
Related Query
- Why do methods and types impose different constraints on variance?
- Why do val and def implement abstract methods at different times?
- Why do proper types Any and Nothing fit type constructor shape F[_] when they are different kinds?
- Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?
- Why does the runtime reflective universe and the macro universe create two different trees for scala.None?
- Why do mutable and immutable ListMaps have different orders in Scala?
- Why are Buffer and List objects equal (even they are from different classes)?
- Why are aggregate and fold two different APIs in Spark?
- why both transform and map methods in scala?
- Why is logback loading configurations in a different order and ignoring system properties (SBT)?
- Why does overloading polymorphic methods with different upper bounds not compile in Scala
- Scala method types and methods as parameters
- Why compound types with different order of components are equivalent in Scala?
- Why making a difference between methods and functions in Scala?
- Why with scala, using the same regular expression, using 2 different matching methods lead to 2 different results?
- Why does this two checks for null and empty returns different results?
- Scala: why mutable Map and immutable Map have different result on same custom class instance as key?
- Why are methods -- and - deprecated for List?
- Why does this snippet with pattern matching and higher kinded types no longer compile in Scala 2.12?
- Chaining path-dependent types and instantiating them when they having different parameter lists in Scala
- Hybrid Functional/Object Oriented languages like F#/Scala: Use types with methods or methods and types
- Why do development and production modes lead to different web pages?
- scala type class with higher kinded types and variance
- Why there is a different error message on using += and a=x+y on a val variable?
- Why do .map.flatten and flatMap on a Scala Map return different results?
- Why does Scala's Traversable have two copyToArray methods with slightly different types?
- F-bounded types and methods with type parameters at argument and return sites
- Why does '0xcafebabe' stand for a different number in Scala and Python?
- why is specified equivalence between wildcard and existential types not observed in REPL
- Why are `def aPlusOne = a + 1` and `val aPlusOne = () => a + 1` different in Scala?
More Query from same tag
- How to define local method on top of a monad transformer stack in Scala cats
- Simple unit testing with monoids
- Use list of integers as argument for fill function
- How to use import statement with singleton objects
- Scala SBT - sbt-native-packager, how to specify custom stage directory
- Catch Scala macro expansion errors
- Using Scala & IntelliJ, show unicode arrows but don't change source-code
- How do you override fields in Scala?
- Performance issue when extracting a subset from an immutable Map
- Folders In SiteMap Using Liftweb
- Eclipse Scala IDE - class file needed by X is missing
- How to filter out elements in each row of a List[StringType] column in a spark Dataframe?
- Function return type error with future.onComplete
- How to handle this type of JSON request in akka http POST endpoint?
- Play! Framework/Anorm: Converting data to JSON and storing into DB
- value not found in akka Producer-Consumer with actor
- How to handle Cassandra "duration" datatype in Spark?
- Parallelization/Cluster Options For Code Execution
- When will Akka bring better performance?
- How does prepend preserve immutability of a List but append does not?
- Gradle build failed with Kotlin, Scala and Java
- select with aggrgation spark and scala
- value keys is not a member of play.api.libs.json.JsValue
- How to convert spark dataframe array to tuple
- Remove item in list if adjacent
- Re-use "await" parameters in Scala Specs2
- Spark Streaming Data to S3
- SBT run single test class in submodule
- Convert tuple to case class with default values
- Is it possible to pass dynamic values in default replacement of ZipAll in Scala?