Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implicit methods behave suboptimally when used non-implicitly #3781

Closed
scabug opened this issue Aug 20, 2010 · 9 comments
Closed

implicit methods behave suboptimally when used non-implicitly #3781

scabug opened this issue Aug 20, 2010 · 9 comments
Assignees

Comments

@scabug
Copy link

scabug commented Aug 20, 2010

scala> def f(implicit x: Int): Int = x + 1
f: (implicit x: Int)Int

scala> List(1, 2, 3) map f
<console>:7: error: could not find implicit value for parameter x: Int
       List(1, 2, 3) map f
                         ^

scala> List(1, 2, 3) map (f _)      
<console>:7: error: could not find implicit value for parameter x: Int
       List(1, 2, 3) map (f _)
                          ^

scala> List(1, 2, 3) map (x => f(x))
res1: List[Int] = List(2, 3, 4)

And the monkey wrenches really go flying if you throw in another one:

scala> implicit def g(implicit x: Int): Int = x + 1
g: (implicit x: Int)Int

scala> List(1, 2, 3) map g                         
<console>:7: error: diverging implicit expansion for type Int
starting with method g in object $$iw
       List(1, 2, 3) map g
                         ^

scala> List(1, 2, 3) map (x => g(x))
res4: List[Int] = List(2, 3, 4)

I suppose we're in unspecified land here, but I think it'd be nice if we could say implicit methods don't move one in multiple directions away from non-implicit ones (by which I mean, make it implicit and now THIS works but THIS doesn't...) because it's rather tedious trying to push all that toothpaste back into the tube.

@scabug
Copy link
Author

scabug commented Aug 20, 2010

Imported From: https://issues.scala-lang.org/browse/SI-3781?orig=1
Reporter: @paulp

@scabug
Copy link
Author

scabug commented Aug 22, 2010

@harrah said:
It is specified by 6.26.2, which indicates the order of method conversions: implicit parameter application first, eta expansion second.

@scabug
Copy link
Author

scabug commented Aug 22, 2010

@paulp said:
Replying to [comment:1 harrah]:

It is specified by 6.26.2, which indicates the order of method conversions: implicit parameter application first, eta expansion second.

Thank you, I looked but didn't find the right spot.

So I guess the question is whether a method with an implicit argument is to be eta-expanded. The spec says "Otherwise..." for eta expansion, which sounds like it means that if a method takes only implicit parameters, it stops before eta expansion. But I don't know why we wouldn't want them to expand from (implicit T)R to T => R. Is there some obvious reason to squelch it?

@scabug
Copy link
Author

scabug commented Aug 23, 2010

@adriaanm said:
I think the problem is that eta-expansion turns method types into function types, which are entirely different (and explicit, as far as implicits go) beasts.

@scabug
Copy link
Author

scabug commented Aug 24, 2010

@lrytz said:
wontfix. duscussion on (f _)

@scabug
Copy link
Author

scabug commented Aug 24, 2010

@odersky said:
The behavior is as specified, and I would not know how to change the spec.
That said there's one sore point: The behavior of f _: You would expect that

   f _ == f(_) == (x => f(x))

But only the second equality holds. The reason lies i the parser. It eta-expands
f(_) immediately, but expands f * to something like (f: ? -> ?). It can't do the eta expansion for f * because it does not know how many parameters f has. So that's how the code paths diverge.

What to do about it? The proper thing to do would be to force eta-expansion
of f _ in the typer. But I have been uncompfortable with f _ anyway for a long time. It feels redundant with all the other possibilities we have for expressing
function values. So how about deprecating f _ altogether?

@scabug
Copy link
Author

scabug commented Aug 25, 2010

@harrah said:
I'm not especially attached to f _ for eta-expansion of methods, but it is nice for converting by-name parameters to Function0.

@scabug
Copy link
Author

scabug commented Aug 26, 2010

@odersky said:
Good point. That one is not covered by the alternative use of (_). You'd have to write
() => f which is a bit less nice. But It's still only a minor inconvenience and writing () => f might atcually help comprehensibility.

@scabug
Copy link
Author

scabug commented Aug 26, 2010

@paulp said:
Replying to [comment:8 odersky]:

Good point. That one is not covered by the alternative use of (_). You'd have to write
() => f which is a bit less nice. But It's still only a minor inconvenience and writing () => f might atcually help comprehensibility.

I would miss f _. I use it a lot, although maybe there are other ways to do things. Is there another way to turn a method into a function without knowing the arity first? Maybe that seems like a trivial thing but I get a lot of mileage in the repl, especially with java's ridiculously long everything.

scala> java.lang.management.ManagementFactory.newPlatformMXBeanProxy _
res0: (javax.management.MBeanServerConnection, java.lang.String, java.lang.Class[Nothing]) => Nothing = <function3>

scala> java.util.Arrays.deepEquals _
res1: (Array[java.lang.Object], Array[java.lang.Object]) => Boolean = <function2>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants