Updated Proposal: Revisiting Implicits

Overall, this looks like a solid and comprehensive set of improvements to the language, elevating language past features like implicits from the level of mechanics to the level of intent, and simplifying teaching use case-driven contextual features (notably: type classes and extension methods). :clap:

My only very minor concerns revolve around reducing the number of ways to do things, and simplifying the new language features as much as possible.

Some random ideas here:

Remove Named Givens

Currently, there are two ways to define a given:

given Ord[Int]

and

given intOrd: Ord[Int]

This bifurcation makes the feature more complex and forces users to choose between two different styles; indeed, it also leaks the mechanical, implementation detail that givens are implemented by synthesizing named values (or methods).

The named given is not needed, because it can be reconstructed separately from other orthogonal language features:

given Ord[Int] { ... }

val intOrd = summon[Ord[Int]]

This factoring avoids the conflation of creation of a given with the naming and storing of a reference to that given, and also takes a more opinionated stance that the canonical way to define given instances is without names, which, thanks to summon and extension methods, are often useless and / or boilerplate.

Remove Given Extensions

As others have pointed out, there are many ways to define extension methods. The syntax for defining extension methods is straightforward and an obvious generalization of the syntax for def methods

However, given instances for extension methods introduce quite a different syntax for doing the same thing:

given stringOps: extension (xs: Seq[String]) { ... }

This new keyword and new language feature is unnecessary, because we can express the same extensions in two other ways: by defining method extensions using the new syntax, or by using given instances on AnyRef (or, indeed, by using implicit conversions!):

given AnyRef { ... }

The only additional cost for either technique is repeating the “this” parameter for every extension; but sometimes this is desirable, because for polymorphic data types, some extension methods are specialized (e.g. .flatten defined only on Future[Future[A]]); in general extension methods on polymorphic data types will not have a uniform target type.

Remove Implicit Conversions

This suggestion will be so flamed I won’t spend too time much on it, but the idea is that explicit toX or asX conversion methods can be added as extension methods, so implicit conversions are not actually fundamental or necessary in any way; and in my experience, the explicitness of extension method conversions helps tremendously with readability and tooling (e.g. toJavaCollection instead of an automatic conversion).

Removing implicit conversions would also reduce the number of ways to do extension methods.

Other Random Notes

  • I’d prefer the name Equal instead of Eql
  • Big :+1: on given imports
4 Likes