Sign up ×

Suppose I have two classes, Input and Output, which are designed to be connected to each other. Output produces values of some type, and Input consumes them.

class Input[T] {
  var output: Option[Output[_ <: T]] = None
class Output[T] {
  var input: Option[Input[_ >: T]] = None

It's okay if an Input and Output pair don't operate on the same kind of value as long as the Input type parameter is a supertype of the Output type parameter. Note that the type parameter in both classes is invariant; in the real versions it is used in both co- and contravariant positions.

I have a connect method elsewhere which sets up a link between an Input/Output pair:

def connect[T](output: Output[T], input: Input[_ >: T]) = {
  output.input = Some(input)
  input.output = Some(output)

If I call this method as below, I get a type error:

val out = new Output[String]
val in = new Input[AnyRef]
connect(out, in)

The error is:

test.scala:17: error: type mismatch;
 found   : Output[String]
 required: Output[AnyRef]
  connect(out, in)

I can resolve this by writing out the type parameter (in this case, I would write connect[String], but I think the compiler should be able to figure this out for me. How can I change the connect method so that the type parameter is inferred automatically?

Edit: For now, I've made connect a method of Output so it gets the type parameter automatically. This also has the added benefit that I can use the infix notation out connect in, but the design feels a little awkward.

I am still interested in why the compiler exhibits this behavior. I feel like it should be able to infer the type parameter. Is this actually working as specified?

share|improve this question
did you mean "don't operate on the same kind of value" –  Rich Seller Jul 26 '09 at 19:17
have you tried asking the question to Scala mailing list? –  GClaramunt Jul 31 '09 at 18:30

3 Answers 3

You will sometimes get better results if you use multiple parameter lists:

def connect[T](output: Output[T])(input: Input[_ >: T]) = {
  output.input = Some(input)
  input.output = Some(output)


...and indeed in this case, it works.

share|improve this answer
Can you expand on why this is? "sometimes get better results" doesn't sound very deterministic! –  oxbow_lakes Jul 27 '09 at 12:03
Sadly, the type inferencer isn't spec'ed, and sometimes isn't deterministic either. –  Jorge Ortiz Jul 28 '09 at 3:17

I may be totally wrong, but I think the problem is when you tie together the input and the output: the input has an output restricted to a subtype of T, but the output has an input restricted to a supertype of T, the only type that can satisfy both conditions is T.

Input[T] -> Output[ _ <: T ]
Output[Q] -> Input[ _ >: Q ]

When you create the input with the output (replacing Q with _ <: T )you get:

Input[T]->Input[ _ >: [_ <: T] ]

The same as

Input[T]->Input[ _ <: T <: _ ]

Hence the type mismatch

share|improve this answer
In my example, String and AnyRef satisfy my constraints. The Output produces Strings and requires an Input that consumes some supertype of String. The Input consumes AnyRefs and requires an Output that produces some subtype of AnyRef. Since String is a subtype of AnyRef, the constraints are satisfied. –  Jay Conrod Jul 27 '09 at 18:26
The problem is that there is exactly one appropriate type parameter for connect, and that is the type parameter of the Output. When I specify this explicitly, it works fine. If I don't, it tries to use the type parameter of the Input, and I get a type error on the Output argument. –  Jay Conrod Jul 27 '09 at 18:28
Sorry, I misread the Input[_ >: T] in the signature of connect[T]( –  GClaramunt Jul 28 '09 at 16:30

Actually scala type inferene can't handle "recursion" for now. So if type of argument can be infered only in collocation with other argument scala fail to inference. But if you use differnt argument list scala f(a)(b)(c,d)will infer types list by list, so it usally works better.

PS It is oversimplified, but can get you some clue.

share|improve this answer

Your Answer


