Scala 3 specific stdlib improvements

Some parts of stdlib could be greatly ehanced by using Scala 3 specific features. One example is ChainingSyntax. Just consider:

  extension [A](self: A):
    inline def tap[U](inline f: A => U): A =
      f(self)
      self
    inline def pipe[B](inline f: A => B): B = f(self)

Using inline here is not only more efficient, it also makes debugging more reliable (no lambdas), exception callstacks shorter and tidier and it e.g. makes return statemens from inside possible, as they are no longer non-local.

I am not sure what are binary compatibility concerns in cases like this and what strategy could be used to implement Scala 3 improvements to some carefully seleected parts of stdlib.

4 Likes

The current strategy is shipping some other code such as in scala.runtime.stdLibPatches.Predef

e.g. assert, implicitly and locally methods are overridden here

Then we intercept any patched definitions when we initialise the compiler and point them to the patched version

Interesting, thanks. I can see assert there, but not locally or implicitly, only summon.

Who and how chooses what will be added there? Is pipe / tap a good candidate?

How many functions can be added before the maintenance burden becomes too heavy? Will Scala 3 improvements in stdlib have to wait until Scala 2.13 dies, which may be practically never?

SIP 51 mentions the issue without solving it.

That document is no longer new, so probably their thinking has evolved since then.

It would be great to get @inline tap under scala 2 and inline under scala 3.

https://docs.scala-lang.org/sips/drop-stdlib-forwards-bin-compat.html

1 Like

Oh that is interesting, I think before 3.0.0 this was the case, but we did some “cleanup” which probably decided it was not worth patching those methods - but at least assert exists in the 2.13 Predef also

@som-snytt In Cross-build by som-snytt · Pull Request #240 · scala/scala-collection-contrib · GitHub you mentioned:

Use of tap is also a test of cross-compilation. Scala 3 ought already to intercept that API to make it inline

Is this documented somewhere? When and how was it implemented?

there is no interception of pipe and tap in scala 3

My comment was prescriptive, not descriptive. Or, if you like, moral imperative.

1 Like

I have seen several mentions on GitHub most of the stdlib will be compiled by Scala 3 compiler to allow improving it as needed, starting with 3.8 release, and its distribution will be changed a bit. I think this is great news. I guess it will be done carefully to avoid annoyance as much as possible, but still maybe this is quite a substantial change, which might deserve an announcement? Maybe next Scala Highlights could cover this?

In Scala 3.8, it will use the stdlib in source, other than the one from Scala 2.13, but I still don’t know which features were added, may be CC checked?

In 3.8 standard library will be annotated with capture checking (from what I heard in scaladays), but I’m not aware of any other features.

1 Like

I’m not sure if it’s possible, but maybe we can use the @targetName annotation to make these kinds of changes while not breaking backward compatibility? I. e. rename the old pipe implementation to something else (legacyPipe or whatever) but annotate it with @targetName so it’s still called pipe in the binary, then add the new macro-based implementation under the name pipe. this would retain binary compatibility while providing the benefits of the macro based implementation to callers compiled against a newer version of the standard library.

Note that other ecosystems already do something similar, e. g. glibc’s symbol versioning feature.

1 Like