Skip to content

Narrow implicit scope #446

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

Closed
adriaanm opened this issue Nov 21, 2017 · 13 comments
Closed

Narrow implicit scope #446

adriaanm opened this issue Nov 21, 2017 · 13 comments

Comments

@adriaanm
Copy link
Contributor

Don't include all parts of type of implicit value. Implicits are plenty magical in how they propagate, let's make it tractable to reason about where they come from, while supporting common use cases of companion objects supplying e.g. serializers for the type they accompany.

@adriaanm adriaanm added this to the 2.14 milestone Nov 21, 2017
@smarter
Copy link
Member

smarter commented Nov 21, 2017

Could you sketch out the rules for the implicit scope you have in mind? If I understand what you're proposing correctly, this seems overly restrictive. The implicit scope of the type Foo[Bla] should include both Foo and Bla, otherwise it's either impossible to define a new typeclass that has instances for existing data structures, or impossible to define a new data structure that has an instance of an existing typeclass.

@ShaneDelmore
Copy link

I agree with the sentiment to make it tractable to reason about where implicit values come from, but am not yet sure that reducing implicit scope is the best way to accomplish it. If this ticket were titled “Make implicit scope easier to reason about” would the solution still be to narrow implicit scope? What about making it easier to visualize implicit scope, through printing of an implicit scope graph maybe? Or the ability to interact with the scope at debug time and find objects available and their source?

@nafg
Copy link

nafg commented Nov 22, 2017

Can someone name a specific search location that is unnecessary?

@adriaanm
Copy link
Contributor Author

For example, the various subpackages that prefix any type that's part of the type of the implicit we're looking for? See the recursive computation of the parts of a type specified by http://www.scala-lang.org/files/archive/spec/2.12/07-implicits.html#implicit-parameters

That's a lot of parts! :-)

For the record, I don't have a concrete proposal, or I would be SIPping it ;-)

@milessabin
Copy link

Prefixes definitely seem like a candidate for pruning. I think most people are unaware that they form part of the implicit scope, and I think there are very few examples in the wild of this being directly exploited (cue someone finding an example of me doing this in shapeless ;-).

@szeiger
Copy link

szeiger commented Nov 28, 2017

Prefixes are probably safe to remove. I can't think of any case where it would be considerably more difficult to achieve the same result without them. Usually the required changes should be limited to moving code around. There is a possibility of having a corner case where you want the same implicits to be available in multiple scopes (so they are currently scoped in a prefix) but you cannot duplicate them because that would lead to ambiguities when the scopes overlap. This could possibly be solved by treating implicits from multiple paths as identical in certain cases (e.g. simple aliasing of objects).

A more restrictive alternative would be to only consider type variables which have an explicit annotation that makes them part of an implicit scope. For Foo[Bar]] to add Bar to the implicit scope Foo would have to be defined as something like class Foo[T @implicitScope].

@adriaanm
Copy link
Contributor Author

adriaanm commented Dec 1, 2017

Maybe we should widen the ticket beyond narrowing implicit scope to simplifying implicit search.

See also scala/scala3#3421

@odersky
Copy link

odersky commented Dec 6, 2017

I agree that package objects in prefixes would be a good candidate for removal. For other prefixes there might be surprises, though. E.g.

trait ADT
object ADT {
   class Left extends ADT
   class Right extends ADT
   implicit def leftIsSerializable: Serializable[Left]
}

Seems reasonable, but the implicit leftIsSerializable would no longer be in the implicit scope of Left.

@retronym
Copy link
Member

retronym commented Dec 6, 2017

Seems reasonable, but the implicit leftIsSerializable would no longer be in the implicit scope of Left.

In that particular example, it would still be in scope based on the rule that includes companion implicits of all base types of Left.

@odersky
Copy link

odersky commented Dec 13, 2017

In that particular example, it would still be in scope based on the rule that includes companion implicits of all base types of Left.

Ah yes, you are right. In that case, maybe we could experiment with dropping the prefix rule and find out how much breaks?

@fommil
Copy link

fommil commented Feb 2, 2018

We put implicits on package objects in the ensime api, to save boilerplate, but it shouldn't be too hard to refactor it into an import. It's probably a code smell anyway, because it breaks typeclass coherence.

@SethTisue
Copy link
Member

out of scope for Scala 2

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Jan 23, 2023
@som-snytt
Copy link

or a good candidate for -Xsource;3. But as noted, probably few usages IRL.

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

No branches or pull requests