0

I have this program:

object B{
  def apply[T](c:T)={}
}

object C{
  type T
  def apply(c:T)={}
}

object A extends App{
  val d=B{println(1);2}
  val e=C{println(1);2}
}

the line

val e = C{println(1);2}

told me error:Type mismatch,expected C.T,actual:2

so why can't I write

type T

def apply(c:T)

it seems the same as

apply[T](c:T)

and what's the type of T when I write

val d=B{println(1);2}

I can write many lines here!

because T means generic,so it can be Int,String,user defined class Apple,Orange...

and what's type of

println(1);2

is there a type "lines of codes"?

Thanks!

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
wang kai
  • 1,673
  • 3
  • 12
  • 21
  • In `def apply[T](c: T)` the **T** means _"whatever the type of `c` is on each call"_. Whereas, on the second example the **T** is already set _(in your specific example probably the compiler infers either **Any** or **Nothing** since you did not specified it)_. – Luis Miguel Mejía Suárez Dec 03 '19 at 01:06
  • 1
    The type of a block is the type of the last expression on the block. Thus `{ println(...); 2 }` has type **Int**. – Luis Miguel Mejía Suárez Dec 03 '19 at 01:09
  • 1
    @LuisMiguelMejíaSuárez Actually I don't think that `T` will be inferred `Any` or `Nothing`, I guess it will remain abstract. The error is "found: `Int(2)`; required: `C.T`" and not "found: `Int(2)`; required: `Nothing`" or "found: `Int(2)`; required: `Any`" https://stackoverflow.com/questions/11274533/use-of-abstract-type-in-a-concrete-class https://stackoverflow.com/questions/2115678/concrete-classes-with-abstract-type-members – Dmytro Mitin Dec 03 '19 at 12:24

1 Answers1

3

The type of a block is the type of the last expression on the block. So

{ println(...); 2 } 

has type Int.

Difference between B and C is difference in type inference between type members and type parameters (1, 2).

object B{
  def apply[T](c:T)={}
}

object C{
  type T
  def apply(c:T)={}
}

class C1[T]{
  def apply(c:T)={}
}

val d: Unit = B{println(1);2}
// val e: Unit = C{println(1);2} // doesn't compile
val e1: Unit = (new C1){println(1);2}

  // scalacOptions ++= Seq("-Xprint:typer", "-Xprint-types")
// val d: Unit = A.this{A.type}.B.apply{[T](c: T)Unit}[Int]{(c: Int)Unit}({
//   scala.Predef.println{(x: Any)Unit}(1{Int(1)}){Unit};
//   2{Int(2)}
// }{2}){Unit};
// val e: Unit = A.this{A.type}.C.apply{(c: A.C.T)Unit}({
//   println{<null>}(1{Int(1)}){<null>};
//   2{Int(2)}
// }{<null>}){<error>};
// val e1: Unit = new A.C1[Int]{A.C1[Int]}{()A.C1[Int]}(){A.C1[Int]}.apply{(c: Int)Unit}({
//   scala.Predef.println{(x: Any)Unit}(1{Int(1)}){Unit};
//   2{Int(2)}
// }{2}){Unit};

In C type T remains abstract

Use of abstract type in a concrete class?

Concrete classes with abstract type members

There is thesis about type inference in Scala:

Plociniczak, Hubert ; Odersky, Martin. Decrypting Local Type Inference https://infoscience.epfl.ch/record/214757

If you want e to compile you can specify T

val e: Unit = C.asInstanceOf[C.type{type T = Int}]{println(1);2}
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Uhm, interesting. Since objects are final I didn't believe it could remain abstract _(and I was at the cellphone at that time, so no way to check)_. A few tests confirm that it, somehow, satisfy `Nothing <:< C.T <:< Any`, but doesn't `C.T =:= Any` nor `C.T =:= Nothing`. – Luis Miguel Mejía Suárez Dec 03 '19 at 13:26
  • 1
    @LuisMiguelMejíaSuárez Yeah, abstract type members are allowed in concrete classes since 2.7 https://github.com/scala/bug/issues/1753#issuecomment-292364630 and in objects since 2.11 https://github.com/scala/scala/pull/4024 – Dmytro Mitin Dec 03 '19 at 13:51
  • 1
    @LuisMiguelMejíaSuárez It's more reliable to investigate inferred types with `scalacOptions ++= Seq("-Xprint:typer", "-Xprint-types")`. – Dmytro Mitin Dec 03 '19 at 13:57