scala - Strange type mismatch when using member access instead of extractor -


given tuple elements of type a , type parametrised in a:

trait writer[-a] { def write(a: a): unit } case class write[a](value: a, writer: writer[a]) 

and use site:

trait cache { def store[a](value: a, writer: writer[a]): unit } 

why following work expected, using tuple's extractor:

def test1(set: set[write[_]], cache: cache): unit =   set.foreach {     case write(value, writer) => cache.store(value, writer)   } 

but following fails:

def test2(set: set[write[_]], cache: cache ): unit =   set.foreach { write =>     cache.store(write.value, write.writer)   } 

with error message

 found   : writer[_$1] type _$1  required: writer[any]              cache.store(write.value, write.writer)                                         ^ 

can fix second form (test2) compile properly?

edit

departing ideas owen tried out if can make work without pattern matching @ (which wanted in first place). here 2 more strange cases, 1 working, other not:

// not work def test3(set: set[write[_]], cache: cache): unit = {   def process[a](write: write[a]): unit =     cache.store(write.value, write.writer)    set.foreach(process) }  // _does work_ def test4(set: set[write[_]], cache: cache): unit = {   def process[a](write: write[a]): unit =     cache.store(write.value, write.writer)    set.foreach(w => process(w)) } 

still pretty obscure me...

running -xprint:typer illuminating here. problem test2 there existential type, appears in 2 separate places: both write.value , write.writer have existential type, but, crucially, compiler has no way of knowing have same existentially quantified type variable. though access them same object, compiler forgets came same place.

when test1 typed, see:

def test1(set: set[write[_]], cache: cache) =     set.foreach(((x0$1: write[_]) => x0$1 match {       case (value: _$1, writer: writer[_$1])write[_$1]((value @ _), (writer @ _)) =>           cache.store[_$1](value, writer)     })); 

the type variable _$1 matched along values. matching type variable _$1 binds in scope of case, it's not existential anymore, , scala can tell value , writer have same type parameter.

the solution test2 not use existentials:

def test2[a]( set: set[ write[ ]], cache: cache ) {    set.foreach { write =>       cache.store( write.value, write.writer )    } } 

or bind type variable match:

def test2( set: set[ write[ _ ]], cache: cache ) {    set.foreach { case write: write[a] =>       cache.store( write.value, write.writer )    } } 

edit

let me endeavor answer new questions brought up.

the reason test3 not work, when write:

set.foreach( process )

process, polymorphic, has made monomorphic, 2 reasons (that know of):

  1. functions in scala cannot polymorphic; methods can be. process defined method; when used first-class function, function.

  2. the way compiler type inference taking polymorphic values , unifying them make them less polymorphic. passing actual polymorphic value method argument require higher-rank types.

the reason test4 does work function literal:

set.foreach( w => process( w )) 

is not polymorphic function! takes argument exestentially qualified type; not polymorphic type. calls method (not function) process, , matches existential type variable process's type parameter. pretty wild, eh?

you write:

set.foreach( process(_) ) 

which, creating anonymous function, means same thing.

another route may or may not find appropriate discard existential types , use type members:

trait writable {     type     val value:     val writer: writer[a] }  case class write[t]( value: t, writer: writer[ t ]) extends writable {     type = t }  def test2( set: set[writable], cache: cache ) {     set.foreach { write =>         cache.store( write.value, write.writer )     } } 

here scala able see write.value , write.writer have same type parameter because have same path dependent type.


Comments

Popular posts from this blog

jasper reports - Fixed header in Excel using JasperReports -

media player - Android: mediaplayer went away with unhandled events -

python - ('The SQL contains 0 parameter markers, but 50 parameters were supplied', 'HY000') or TypeError: 'tuple' object is not callable -