Do you categories cover scala.collection.JavaConverters?
Do you categories cover scala.collection.JavaConverters ?
Yes: they are extension methods, so will need no implicit support in the future.
@Matveev:
Third party serialization packages are typical examples of orphan instances. They require import implied.
It is very good news, is there any description of it.
IIUC
Ok, It is important to know.
Although It is a pitty that such popular library like anormsql can be considered as rare case.
Why cannot it be simplified as extension methods?
Again, can someone please explain the motivation behind the import implied
semantics. Even if I agree that import
should not import implied instances, why doesnât import implied
just import all instances including the implied ones? I see no viable use case for just a import implied A._
statement if it imports just implied instances in A
(and even if we found such a use-case, we can always just created object implicits
with the relevant implied instances).
Additionally, what will happen to the implicit conversion inside Predef
? Will the Predef
object be imported by default to include the implicits?
On a related note, was a syntax introducing a separate import selector instead of a whole separate form of import clause considered and rejected?
I mean something like
import some.path.{_, implied _}
instead of
import some.path._
import implied some.path._
I personally do not read the import section.
For me, the main idea will be to demonstrate library users that it is not good(rare case).
Someone can make checkbox which automatically insert implied keyword.
I am personally think that library user should not be punished. Such complication should be done only for library authors. But after all I agree that import implied
is evil, so It does not matter how more\less it will be with implied keyword.
I only hope that someday there will be more abilities to avoid such cases(for example sql, orm).
This could actually be an interesting alternative, since it allows a refinement (which is based on a proposal by @liufengyun). We can also allow something like this:
import some.path.{implied for Ordering[_], _}
The semantics would be that the import classifier implied for T
would bring into scope all implied instances of some.path
that return values of type T
. The short hand form implied
could stand for implied for Any
. Whatâs nice about it is that it does not just discourage misuse but also encourages virtue, where being virtuous means narrowing down your imports to specific members.
We already have wildcard imports and named imports. Named imports are âvirtuousâ whereas wildcard imports are considered âsloppyâ, so we encourage to use named imports. But for implicits, named imports donât work. In Scala 3, implied instances can be anonymous, in which case we canât use a named import for them. Even in Scala 2 implicits often have intentionally obscure names in order not to risk name conflicts, which makes it very hard to remember those names for an import. So most people just use a wildcard import instead.
With this new feature, we could specify imported implicits by the types they implement, which is precisely what we care about.
While combine the imports is more succinct, make them separate might be more readable.
import a.path._
import b.path._
import a.b._ for Ordering[_], String
import b.c._ for List[_], File
Can we use it for extension methods too? import a.b._ for T
also import extension methods for the type T
. Otherwise, it will be difficult to find where do they come from, just as implicit classes.
If this is a new form of import selector then the ability to use it grouped together with others or separately comes naturally, doesnât it?
It is useful to prevent name clashing.
Why do not you consider the means to automate imports.
Actually imports are boring and most duplicated code at least in my practice.
If you care about readability it is important to consider when it is needed. I think it will be really important only when errors occur. In such cases the good error messages is much more important and can solve most troubles.
Why is it impossible to really help to get rid of such wasteful work as doing same import blocks again and again âŚ
In the current implementation, I can import implied
something that isnât implied
, and doing so has no effect. Is this working-as-designed, or a bug?
scala> object O { def x = 3 }
// defined object O
scala> import implied O.x
scala> x
1 |x
|^
|Not found: x
scala> the[Int]
1 |the[Int]
| ^
|no implicit argument of type Int was found for parameter x of method the in object DottyPredef
I had expected instead that either:
- the compiler would refuse the import
- the compiler would accept the import, and add
O.x
to implicit scope
For neither to happen was surprising to me.
And then conversely, if I do a regular import of an implied thing:
scala> object O { implied x for Int = 3 }
// defined object O
scala> import O.x
scala> x
1 |x
|^
|Not found: x
Again this seem strange; I would expect either a compile error, or for the identifier to be brought into normal scope.
Good point. These should be both be errors.
The proposal and its implementation have been extended with a new construct, which allows to specify implied instances by type rather than by name. Hereâs the new text:
Importing By Type
Since implied instances can be anonymous it is not always practical to import them by their name, and wildcard imports are typically used instead. By-type imports provide a more specific alternative to wildcard imports, which makes it clearer what is imported. Example:
import implied A.{for TC}
This imports any implied instance in A
that has a type which conforms tp TC
. There can be several bounding types following a for
and bounding types can contain wildcards. For instance, assuming the object
object Instances {
implied intOrd for Ordering[Int]
implied [T: Ordering] listOrd for Ordering[List[T]]
implied ec for ExecutionContext = ...
implied im for Monoid[Int]
}
the import
import implied Instances.{for Ordering[_], ExecutionContext}
would import the intOrd
, listOrd
, and ec
instances but leave out the im
instance, since it fits none of the specified bounds.
By-type imports can be mixed with by-name imports. If both are present in an import clause, by-type imports come last. For instance, the import clause
import implied Instances.{im, for Ordering[_]}
would import im
, intOrd
, and listOrd
but leave out ec
. By-type imports cannot be mixed with a wildcard import in the same import clause.
Is that requirement intended to emphasize underlying order of evaluation semantics? I see no obvious syntactic reason other than that.
I think itâs to avoid the confusion around the comma: is it separating a list of types, or does it introduce another import. Consider swapping the order: import implied Instances.{for Ordering[_], im}
â should im
be parsed as a type (i.e. without ambiguity, you meant for Ordering[_], for im
), or is it a term name?
That has less ambiguity, but itâs still kinda ambiguous because in language, ,
has lower precedence than spaces. If it were to be âintuitivelyâ clear (i.e. follow natural language rules), it would need to be something like
import implied Foo.{evA, evB}
import implied Foo.{for C, D}
import implied Foo.{evE, evF; and for G, H}
Even that doesnât read all that well, though, because C
and D
presumably arenât in Foo
. And it looks like they are because of the braces. If you wanted a natural language version it would be
import implied from Foo for C and D
which suggests that you have to actually write it like that:
import implied Foo for { C, D }
which doesnât generalize well to importing instances on the same line.
Itâs because a for
clause is the analogue of a wildcard import, which also comes last. This is particularly important in conjunction with removals. I.e.
import p.{x => _, _}
means you import everything except x
. Likewise,
import implied p.{x => _, for B}
means you import all instances of B
except x
.
This could simplify the imports for libraries like cats.
Currently you need to do something like this to get the instances for Int
and List
:
import implied cats.instances.int._
import implied cats.instances.list._
It looks like, youâd be able to do this instead:
import implied cats.instances.all.{for Int, List[_]}
I assume it would be possible to adjust the hierarchy to take further advantage of this, but even with the current hierarchy itâd be possible to simplify things.
The for
clause details the type of the value being imported, rather than the type it is parameterised over, so you would import these instead:
import delegate cats.instances.all.{for Show[_], Traverse[List]}
That seems like a bug, as itâll bring in a bunch of stuff into scope that will likely not be used.
Assuming this object:
object implicits {
delegate for Show[Int] = ???
delegate for Show[String] = ???
delegate for Show[Foo] = ???
delegate for Monoid[Int] = ???
delegate for Eq[Int] = ???
}
If you ask, âWhat are the delegate instances for Int
?â, the intuitive response would be Show[Int]
, Monoid[Int]
, and Eq[Int]
.
On the other hand, if you ask, âWhat are the delegate instances of Show
?â, the intuitive response would be Show[Int]
, Show[String]
, and Show[Foo]
.
Itâs also more useful to get all the type class instances defined for a type, rather than all the instances of a particular type class.
The best of both worlds, would be something like this:
// To import Show[Int], Monoid[Int], and Eq[Int]:
import delegate implicits.{for Int}
// To import Show[Int], Show[String], and Show[Foo]
import delegate implicits.{of Show[_]}