I would hope that it would only be used in a local scope. Certainly, such implicits should not be imported. So I don’t think it’s a dealbreaker.
At least in IntelliJ, from the list I can preview the implementation or jump to it. So again, if used sparingly I think it’s okay.
I think we have to separate
implicit vals and
implicit defs. For
defs that’s certainly valid. However my response would also depend on what you mean by overloaded.
If you mean as far as people’s intuition and increasing the learning curve, I think it’s consistent enough with other places
_ is used that the meaning should be obvious. (It would help if we stop telling people
_ is highly overloaded. While true in terms of the spec, and important to understand in more non-obvious places like type parameters, I think a better way to teach it is that
_ is a wildcard and Scala accepts wildcards in a lot of contexts, whenever it makes sense.)
If you mean in the sense of increasing the footprint of the language grammar or increasing the complexity of the compiler codebase, so for
implicit def I agree. For
implicit val, maybe it’s naive of me to say this, but it would seem this could be implemented by lifting some restrictions and simplifying the grammar and code. The way I see it, we’re basically saying (1)
_ is a pattern not an identifier [should be a simple grammar change that doesn’t affect its size], and (2) an implicit val with a pattern not an identifier, while not assigning to the expression a user-addressable name, it nevertheless exists within the local scope [perhaps because the compiler will assign it a generated name with a
private[this] or local-only scope]. Again, while an assumption from ignorance, it seems like it’s just a slight tweak of the rules in a way that makes things more regular.
These two suggestions are entirely orthogonal, though. Well, except that #2 is more intuitive the way things are now, that
_ is actually an identifier in the sense that you can’t do two
Wait, I just did some testing. The current behavior is a bit contradictory.
implicit val _ : Int = 10; implicitly[Int] works. This seems to imply that either
_ is an identifier, or that #2 is implemented already.
implicit def _ : Int = 10 does not compile:
identifier expected but '_' found. Why should it work for def but not val? The answer would seem to be that val supports patterns while def does not. So
_ is interpreted as a pattern!
val _ = 1; val _ = 2 does not compile:
_ is already defined as value _ So
_ is interpreted as an identifier! (For example, using a tuple2 pattern and annotating
Any does compile.)
So while the two proposals are orthogonal, #2 is necessary if we want to implement #1 while preserving the behavior of (A). And if we don’t implement #1 – if we say that
_ can be an identifier – then in order to remove the above contradiction, we either implement #2 and allow (B) or disallow (A).
In short, the consistent options are:
- (A) and © compile and work – implement #1 and #2. (B) doesn’t compile because
defs can’t use patterns.
- (A) and (B) compile and work – we don’t implement #1 or #2, instead we say
_ is a valid identifier
- Only © compiles and works – we implement #1 so there’s no redefinition, but without #2 (A) won’t work since
10 is not stored in the scope.
If we would implement #2, it’s not clear what to do for other pattern types. For example a constructor pattern that uses an extractor that returns some “unrelated” value.
All of this doesn’t help for the
implicit def case. I’m not sure how important that is. If something needs to be a def, it probably is being reused enough that leaving off the name has no justification. (Usually scala allows shorter forms of things in order to support prototyping, scripting, etc., or syntactic sugar for patterns it encourages.) Besides the generalization – allowing
defs to be patterns – has some problems.
def (filter, filterNot) ... = partition ... doesn’t seem very efficient ;).