Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the order of implicit parameters matter in Scala?

Tags:

scala

implicit

Given some method

def f[A,B](p: A)(implicit a: X[A,B], b: Y[B])

Does the order of a before b within the implicit parameter list matter for type inference?

I thought only the placement of parameters within different parameter lists matters, e.g. type information flows only through parameter lists from left to right.

I'm asking because I noticed that changing the order of implicit parameters within the singly implicit list made a program of mine compile.

Real example

The following code is using:

  • shapeless 2.1.0
  • Scala 2.11.5

Here is a simple sbt build file to help along with compiling the examples:

scalaVersion := "2.11.5"

libraryDependencies += "com.chuusai" %% "shapeless" % "2.1.0"

scalaSource in Compile := baseDirectory.value

Onto the example. This code compiles:

import shapeless._
import shapeless.ops.hlist.Comapped

class Foo {
  trait NN
  trait Node[X] extends NN
  object Computation {
    def foo[LN <: HList, N <: HList, TupN <: Product, FunDT]
    (dependencies: TupN)
    (computation: FunDT)
    (implicit tupToHlist: Generic.Aux[TupN, LN], unwrap: Comapped.Aux[LN, Node, N]) = ???
//    (implicit unwrap: Comapped.Aux[LN, Node, N], tupToHlist: Generic.Aux[TupN, LN]) = ???

    val ni: Node[Int] = ???
    val ns: Node[String] = ???
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
  }
}

and this code fails

import shapeless._
import shapeless.ops.hlist.Comapped

class Foo {
  trait NN
  trait Node[X] extends NN
  object Computation {
    def foo[LN <: HList, N <: HList, TupN <: Product, FunDT]
    (dependencies: TupN)
    (computation: FunDT)
//    (implicit tupToHlist: Generic.Aux[TupN, LN], unwrap: Comapped.Aux[LN, Node, N]) = ???
    (implicit unwrap: Comapped.Aux[LN, Node, N], tupToHlist: Generic.Aux[TupN, LN]) = ???

    val ni: Node[Int] = ???
    val ns: Node[String] = ???
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
  }
}

with the following compile error

Error:(22, 25) ambiguous implicit values:
 both method hnilComapped in object Comapped of type [F[_]]=> shapeless.ops.hlist.Comapped.Aux[shapeless.HNil,F,shapeless.HNil]
 and method hlistComapped in object Comapped of type [H, T <: shapeless.HList, F[_]](implicit mt: shapeless.ops.hlist.Comapped[T,F])shapeless.ops.hlist.Comapped.Aux[shapeless.::[F[H],T],F,shapeless.::[H,mt.Out]]
 match expected type shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N]
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^
Error:(22, 25) could not find implicit value for parameter unwrap: shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N]
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^
Error:(22, 25) not enough arguments for method foo: (implicit unwrap: shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N], implicit tupToHlist: shapeless.Generic.Aux[(Foo.this.Node[Int], Foo.this.Node[String]),LN])Nothing.
Unspecified value parameters unwrap, tupToHlist.
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^
like image 453
ziggystar Avatar asked Oct 20 '22 15:10

ziggystar


2 Answers

  1. Normally it should not matter. If you look at the language spec it makes no mention about resolution being dependent on parameter order.

  2. I looked at the source code of shapeless, and I could not come up with any reason why this error would present itself.

  3. And doing a quick search through the bug repo of the language I found a similar issue that was apparently resolved. But it does not state if the fix involved treating the symptom (making context bounds not break compilation) or the cause (restrictions on implicit parameter ordering.)

Therefore I would argue that this is a compiler bug, and it is tightly related to the issue linked in point 3.

Also, I would suggest you submit a bug report if you can find a second opinion that resulted from a more rigorous analysis than my own :)

Hope this puts your mind at rest. Cheers!

like image 127
Loránd Szakács Avatar answered Oct 22 '22 23:10

Loránd Szakács


According to my reading of the comments of the issue mentioned by Lorand Szakacs, I come to the conclusion that the order of implicit parameters matters in the current version 2.11 of the Scala compiler.

This is because the developers participating in the discussion appear to assume that the order matters; they do not state it explicitly.

I'm not aware of the language spec mentioning anything about this topic.

like image 32
ziggystar Avatar answered Oct 22 '22 23:10

ziggystar