Why this structural type bound does not work as expected?
-
24-10-2019 - |
Question
I'm trying to write a simple helper method that receives something that can be closed and some function which receives the former and ensures the "closeable" is closed after executing the function.
For example, I want to use it like this:
closing(new FileOutputStream("/asda"))(_.write("asas"))
My impl is
object Helpers {
def closing[T <: { def close }](closeable: T)(action: T => Unit): Unit =
try action apply closeable finally closeable close
}
But when trying to compile this simple test:
object Test {
import Helpers._
closing(new FileOutputStream("/asda"))(_.write("asas"))
}
The compiler complains with:
inferred type arguments [java.io.FileOutputStream] do not conform to method closing's type parameter bounds [T <: AnyRef{def close: Unit}]
Any ideas why?
Solution
You need to write
def closing[T <: { def close() }]
there is a difference in Scala between methods with empty parentheses and methods without parentheses at all.
OTHER TIPS
Type bounds are tricky. In particular, Scala keeps track of the number of parameter lists in addition to the parameters themselves. Try these out!
class A { def f = 5 }
class B { def f() = 5 }
class C { def f()() = 5 }
def useA[X <: { def f: Int }](x: X) = x.f
def useB[X <: { def f(): Int }](x: X) = x.f
def useC[X <: { def f()(): Int}](x: X) = x.f
useA(new A) // This works, but what other combinations do?
In your case, you want
def closing[T <: { def close() }] ...
P.S. If you really plan on using this a lot, you probably ought also play with
class D extends B { override def f = 6 }
class E extends A { override def f() = 6 }
and see which use
you need to use in each case.