Opening this issue, as suggested by Martin, to provide a place to discuss the individual warts brought up in the blog post Warts of the Scala Programming Language and the possibility of mitigating/fixing them in Dotty (and perhaps later in Scala 2.x). These are based on Scala 2.x behavior, which I understand Dotty follows closely, apologies in advance if it has already been fixed
This doesn't work:
@ class Foo(i: Int)
defined class Foo
@ new Foo(1)
res50: Foo = $sess.cmd49$Foo@7230510
@ class Bar(implicit i: Int)
defined class Bar
@ new Bar(1)
cmd52.sc:1: no arguments allowed for nullary constructor Bar: ()(implicit i: Int)$sess.cmd51.Bar
val res52 = new Bar(1)
^
Compilation Failed
But this does:
@ new Bar()(1)
res52: Bar = $sess.cmd51$Bar@467de021
This one straddles the line between "Wart" and "Bug", but definitely should
be fixed so that a class defined with one argument list doesn't magically
sprout two.
I think this will be affected by the explicitly proposal.
This bug hit me pretty hard recently, I was looking to curry the type signature of a function with three types. One is supplied by the user, and the other two derived from function arguments. I used code that looks like
private[Mixer] final class _Mixer[T <: FluidT](implicit ev: ClassTag[T]) {
def apply[A <: FluidT, B <: FluidT](fst: Fluid[A], snd: Fluid[B])(
mxe: MixerT[A, B, T]): Fluid[T] =
Mixer[A, B, T](fst, snd)
}
private lazy val _mixer = new Mixer[Nothing]
def as[T <: FluidT] = _mixer.asInstanceOf[Fluid[T]]
(see http://caryrobbins.com/dev/scala-type-curry/)
Problem is, that the asInstanceOf call doesn't regenerate the ClassTag.
No big deal, I thought, I'll just insert some classtag implicit evidence, and do the new call in as, but now I have to call .apply for it to resolve to the inner method apply, instead of the implicit parameter list of as. I'd much rather the implicits go away at compile time here and allow me to call into the inner method apply.
The only reason I'm doing this hack is so I can have curried type parameter lists.
The only reason I'm doing this hack is so I can have curried type parameter lists.
That's also something we'll hopefully also support directly, if there isn't an issue feel free to create one.
Hi,
I get hit by this one:
trait Encoder[T] {
def apply(o: T): String
}
object Encoder {
implicit val intEncoder: Encoder[Int] = _.toString
}
trait Creatable[Resource: Encoder] {
def create(resource: Resource): Unit = ???
}
case class PodsOperations() extends Creatable[Int]
The last line won't compile.
The workaround:
case class PodsOperations() extends Creatable[Int]()
Thanks
It turns out this is can alternatively be seen as the problem of old-style implicits taking regular arguments. If we move to given parameters and arguments, all test cases work as expected. E.g. the following compiles:
class TC
implied tc for TC
class Foo given TC
object Test {
new Foo
new Foo given tc
new Foo()
new Foo() given tc
Foo()
Foo() given tc
}
Classes without a leading regular parameter list still assume () as first parameter list. I tried for a while to avoid this but in the end this created more problems than it solved. In particular, with creator applications, it's quite reasonable to demand that Foo() works even if class Foo is parameterless. Otherwise we'd either have to go back to new Foo for this case, or make sure everyone creates their classes with at least a () parameter list. Either choice is unpalatable.
But if creator applications take a () it's consistent to expect that corresponding constructors do so as well.
I'm reopening this issue because the syntax has evolved quite a bit since it was closed and the situation is now "wart-y" again in my opinion:
given Int = 1
class Foo(using x: Int)
new Foo // compiles
new Foo() // compiles
new Foo(using 1) // compiles
new Foo()(using 1) // compiles
The fact that there's some sort of optional empty parameter list is fairly weird, but it gets weirder when combined with the fact that we can now have a regular parameter list after a using parameter list:
class Bar(using x: Int)(y: String) // For a more realistic usecase, see https://github.com/lampepfl/dotty-feature-requests/issues/133
new Bar("") // ERROR: too many arguments for constructor Bar: ()(using x: Int)(y: String): Bar
new Bar()("") // compiles
new Bar(using 1)("") // compiles
new Bar()(using 1)("") // compiles
Here in particular, the fact that one cannot write new Bar("") (or Bar("") using creator application syntax) seems like a real wart to me.
Most helpful comment
I'm reopening this issue because the syntax has evolved quite a bit since it was closed and the situation is now "wart-y" again in my opinion:
The fact that there's some sort of optional empty parameter list is fairly weird, but it gets weirder when combined with the fact that we can now have a regular parameter list after a using parameter list:
Here in particular, the fact that one cannot write
new Bar("")(orBar("")using creator application syntax) seems like a real wart to me.