object foo extends Foo { val x = 3 }
// is eq to
lazy val foo = new Foo { val x = 3 }
//------------------------------------
object foo extends Foo { val x = 3 }
foo //this line produces warning ...
// is eq to
val foo = new Foo { val x = 3 }
Scala 2.x can’t infer the correct type of this expression, and many other expressions where one branch is a subclass of AnyVal and the other is the java wrapper. Not sure how easy this would be to fix, since it has to do with implicit conversions.
This came up for real when I had to interact with Java I was doing something like this
public class User {
private Boolean isEnabled;
//getters setters, etc...
}
And in scala I was doing something like
val maybeNullPerson = Option(getUser())
val thatPersonEnabled = maybeNullPerson.map(_.isEnabled).getOrElse(false)
if(thatPersonEnabled) {
//...
Since the inferred type was Any I had to do this
val thatPersonEnabled = maybeNullPerson.map(_.isEnabled).getOrElse[java.lang.Boolean](false)
Yeah, the current behavior might be the best, but the other option would be to automatically infer java.lang.Boolean, since that’s the wrapper type for scala.Boolean.
Why not scala.Boolean in this case? This value is used in if in your example. So, it’s unclear why complier should prefer Java’s one.
Why you think compiler should apply implicit conversion inside if and at other usages of thatPersonEnabled as boolean (inferring java.lang.Boolean for thatPersonEnabled) instead of applying implicit conversion at _.isEnabled call (thus inferring scala.Boolean for thatPersonEnabled).
This is a backwards compatibility problem for all of our users, and it seems onerous to make a code-rewriter and require everyone to use it.
More generally, this pattern is useful and important for Chisel’s goals as a hardware DSL. From our experience, structural typing is a very familiar paradigm for Verilog/VHDL users- we try to add more safety while still giving a familiar look and feel.
I think we might be able to accommodate your usecase with only minimal changes on your side. In Dotty, structural types need to be converted to Selectable to access the structural members (see Proposal for programmatic structural types for the details), so maybe we could just tweak type inference to make new Foo { val x = 3 } infer Foo { val x: Int } if the expected type is a subtype of Structural, which would be the case if you write def func[T <: Structural](in: T): T.
We control the abstract class that people extend when using this pattern, so if we can just mixin Structural with our abstract class, that would be awesome.
@scottcarey it’s not performance sensitive and does use reflection.
@smarter thanks for the link to Selectable- as Jack says, we can control the base type so adding Structural to the mix is doable. From my initial read-through of the proposal, I think it will cover most of our use-cases. We’ll review what’s out in the wild to make sure the limitations in the proposal aren’t a bigger deal than I think they are, but I think they’re unlikely to pop up very often. Thanks!
Contravariance prevents proper type derivation in Scala 2.13.0; in Dotty it compiles fine. Could this type derivation improvement be back ported?
// if using Scala 2.13.0 a compile error results in marked line below
// ("found Step[B with A]; required Step[A]")
// if using Dotty it compiles fine
// a Step requires some environment
type Step[-E]
// providing a p allows to transform a step that requires an environment with P into a step that does no more require a P
def provide[E, P](p: P): Step[E with P] => Step[E] = ???
trait A
trait B
val step: Step[A with B] = ???
val b: B = ???
// the compile error occurs here
val s: Step[A] = provide(b)(step)