Writing a generic function that Writer can accept, as well as an OutputStream

I wrote a few functions that look like this:

def myWrite(os: OutputStream) = {} def myWrite(w: Writer) = {} 

Now both are very similar, and I thought I'd try to write one parameterized version of the function.

I started with a type with two methods that are common in Java OutputStream and Writer:

 type Writable[T] = { def close() : Unit def write(cbuf: Array[T], off: Int, len: Int): Unit } 

One of the problems is that OutputStream writes Byte and writes Writer Char , so I parameterized the type with T

Then I write my function:

 def myWrite[T, A[T] <: Writable[T]](out: A[T]) = {} 

and try using it:

 val w = new java.io.StringWriter() myWrite(w) 

Result:

 <console>:9: error: type mismatch; found : java.io.StringWriter required: ?A[ ?T ] Note that implicit conversions are not applicable because they are ambiguous: both method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] and method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] are possible conversion functions from java.io.StringWriter to ?A[ ?T ] myWrite(w) 

I tried several other combinations of types and parameters until nothing came of it.

My question is, is there any way to achieve this at all, and if so, how.

(Note that to implement myWrite, it is necessary that the type T known inside, which parameterizes the write () method, because it needs to create a buffer, as in the new ArrayT array.)

UPDATE: the β€œright” solution does not work because the error is in the compiler: https://lampsvn.epfl.ch/trac/scala/ticket/2672

+4
source share
2 answers

First of all, you do not need to parameterize A in myWrite . Your target classes are not shared! Secondly, you do not need to explicitly allow subclasses - just inherit to do the trick for you.

 def myWrite[T](out: Writable[T]) = {} 

Now the method can infer type T If for some reason you do not need true type A , this will work for you:

 myWrite(new StringWriter) 

However, you ran into a problem:

 def myWrite[T](out: Writable[T]) = new Array[T](0) // Doesn't work! 

The problem is that this is common code. He does not know what T is - it can be anything! Therefore, you need to tell the compiler to pass information that identifies T :

 def myWrite[T : ClassManifest](out: Writable[T]) = new Array[T](0) 

(Edit: Simplify the answer so that it really works.)


(Edit: this doesn't really work at all - see comments.)

+1
source

It works:

 myWrite(w.asInstanceOf[Writable[Char]]) 

... so you think this will work:

 implicit def wrToWr(w:java.io.Writer): Writable[Char] = w.asInstanceOf[Writable[Char]] 

... but it is not. I have no idea why not:

 scala> myWrite(w) <console>:17: error: type mismatch; found : java.io.StringWriter required: Nothing myWrite(w) ^ 

Where does nothing come?

0
source

Source: https://habr.com/ru/post/1335692/


All Articles