I have a challenge with the type system: I have a class method that returns a kafka producer: ```cla...
h
I have a challenge with the type system: I have a class method that returns a kafka producer:
Copy code
class ResourceProducer(
  private val resourceAProducer: Producer<String, ResourceA>,
  private val resourceBProducer: Producer<String, ResourceB>
) {
  fun getCorrectKafkaProducer(resource: Resource): Producer<String, SpecificRecord> {
     return when(someSealedClass) {
        ValueA -> resourceAProducer <-- does not compile
        ValueB -> resourceBProducer <-- does not compile
    }
  }
^-- Compiler error msg: Type mismatch: Required: Producer<String, SpecificRecord>, Found: Producer<String, ResourceA/B>
  
  fun getSpecificRecord(resource: Resource): SpecificRecord {
     return when(someSealedClass) {
        ValueA -> ResourceA <-- this compiles
        ValueB -> ResourceB <-- this compiles
    }
  }

}
Some extra information:
Producer
is a Java generic interface
public interface Producer<K, V> extends Closeable {... Future<RecordMetadata send(ProducerRecord<K, V record) ...}
.
SpecificRecord
is a Java interface
public interface SpecificRecord extends IndexedRecord {}
.
ResourceA
and
ResourceB
are auto-generated classed based on schema files, and they implement `SpecificRecord`:
public class ResourceA extends SpecificRecordBase implements SpecificRecord
public class ResourceB extends SpecificRecordBase implements SpecificRecord
SpecificRecordBase
is an abstract class.
s
Can you do something like this to add
out
variance at the use site?
Copy code
fun getCorrectKafkaProducer(resource: Resource): Producer<String, out SpecificRecord>
Bit of a guess, I haven’t tried to see if it works
h
I actually tried that, which makes the
getCorrectKafkaProducer
compile. The issue, however, is that then I cannot use the
Future<RecordMetadata send(ProducerRecord<K, V record)
method anymore (the compiler expects
Nothing
as the
record
type argument at that point
s
Ah, I was assuming
V
was an output type for the producer (because of the class name) but it looks like it’s actually an input type
In that case I think your problem is more fundamental. A
Producer<String, ResourceB>
can’t be used as a
Producer<String, SpecificRecord>
because that would imply that its
send
method could accept any
ProducerRecord<String, SpecificRecord>
, when it actually only accepts
ProducerRecord<String, ResourceB>
.
Caveat: I’m not familiar with this API so I could be misunderstanding how it works
h
I guess your reasoning makes sense. Thank you for helping me understand!