Minutes
The agenda distributed to the attendees is here.
Proceedings
Implicit conversions
https://dotty.epfl.ch/docs/reference/contextual/conversions.html
Mostly an uncontroversial change.
Someone: Do we want it as an abstract class, not a trait? Someone: Yes, because we actively want to discourage it being used as a mixin.
Miles: There are lots of function types, could it be a refinement of Function1? Someone: No, because it’s not structural.
Seth: But it still needs a contributors.scala-lang.org thread for discussion outside by itself, apart from the other implicits changes
Auto-tupling
Implemented but not merged: https://github.com/scala/scala3/pull/4311
The problem is when using infix (e.g. an operator method) there’s confusion between a 1-argument tuple2 method and a 2-argument method, of which there are a few in the standard library.
Someone asks: should we drop auto-tuple completely? (unanswered, I believe)
One example is += on Map, which was deprecated in 2.13.
We could deprecate the definition of such methods in 2.14.
Adriaan: why, outside of overloads, can’t auto-tupling kick in for 1-argument tuple2 methods? Decision: let’s try that
Exports
https://dotty.epfl.ch/docs/reference/other-new-features/export.html
The motivation is the same as package objects, and is by-and-large replaced by top-level definitions.
What’s left over is: how do we compose namespaces? Export is the answer there.
(It’s also one of the longest standing feature requests of Scala.)
Seb: is wildcard exporting a good idea? Maybe just name them (without full definitions).
Iulian: Does export fix the package object inheritance problem? Yes, because export can be top-level.
Seth: What’s the impact on Scaladoc? Shared concerns with what the UX should be, maybe just forward references instead of copying the Scaladoc.
Miles: Does this fix Daniel Spiewak’s Monad/Traverse issue? The issue is you want to implement the intersection by exporting monad instance methods and traverse instance methods but sometimes you want to be selective on exporting (“every method that isn’t (something something)”) for now you just name them
Martin(?): Export is entirely implemented in namer, it’s a simple implementation, no types.
Josh: What about incremental compilation impact? Answer: We’ll treat it like a variant of inheritance.
Seth: Can this wait for 3.1 or later?
- Martin argument 1: deprecate package object replacement
- Martin argument 2: simpler structure, Scala 3 books should promote this instead of package objects
Seb: back to no-wildcard / named exports only: we can loosen it later to allow for wildcards
Miles/Seth: can we make the export relative to the type? “Export everything in monadInstance from Traverse”?
- Martin: it’s meant to mirror import
- Seb: but we have import implied for types in the talks…
- Martin: it’s not the same thing
- Seb: but it is, kind of…
- (someone): just ascribe the type “val monadInstance: Functor” and export from that
Adriaan: (using the Printer/Scanner example) method in scanner won’t call method in printer
- Martin: yeah it’s not inheritance
- Adriaan: right, we should make that clear
Seb: Javascript supports wildcard exports
Adriaan: we need to give good error messages in export conflicts
Adriaan: Also let’s not forget the big Scaladoc impact, can’t copy because of the type parameter and other different names
- Martin: we should be able to use Scaladoc’s variable redefining system
- Adriaan: Scaladoc is very important to users, so let’s not forget this issue
Polymorphic function types
Merged but not documented: https://github.com/scala/scala3/pull/4672
Presented by Guillaume.
First type lambda syntax was type A = [T] => List[T]
But we need term-level syntax and =>
is taken by Function1
So switched type lambda to type A = [T] =>> List[T]
So the identity function can be def id: [T] => T => T
Miles(?): and now we have lots of function type (dependent functions, implicit functions, …) Miles: we should definitely lose the FunctionN types, if possible Guillaume: should we eta-expand to polymorphic code? does it break existing code?
- Martin: yeah it does Miles: (summarising) it’s lovely, we should have it (it’s currently entirely experimental) Martin: let’s discuss if can we do it later
- Miles: I need it for typeclass derivation, so no
- Martin: … Right, that clears that up
Seb: there’s confusion in arrows between type parameters and term parameters
- (lots of chat)
- Adriaan: we’ll need to decide the syntax later
- Adriaan: maybe instead of
[T] =>> List[T]
useList[__]
No-one is expressly against including it, but details will need to be finalised later.
@infix and @alpha
Presented by Sébastien.
The goal is to ensure all operators always have a name, for documentation purposes, IDE hover display, googleable.
Also @alpha defines the JVM name of the method. But it’s a design decision to only have 1 way to call the method.
Nicolas: why not the other way round, have an @op
annotation with the infix operator name?
Seb(?): Because you can’t call the alpha numeric name (e.g. .append
)
Seth: Also having two methods (+=
and append
) interferes with overriding: you want one to alias the other,
but you want to be able to override to refine the result type of both methods.
Seb: And then there’s @infix, to be prescriptive about methods that should only be used infix Seb: it’s a controversial issue Seb: the plan is for now you can choose, then you’ll get a warning, then it will error (forcing you to infix)
Seth: the hardcore infix fans is small
Iulian: I don’t like the forcing from @infix either
Martin: There are too many choices with infix and non-infix usage
Adriaan: should this be in 2.14?
- No definitive answer, there’s no reason not to, outside of the already full roadmap plans
Also mentioned are the non-operator methods that are really designed for infix usage: eq
, is
(?),
Range’s to
and be
.
Martin: this is already implemented, and forced with -strict
Creator Applications
Presented by Martin.
Iulian: can you do both? new Foo(x, y)
and Foo(x, y)
- Martin: yes
- Iulian: but that’s inconsistent with the previous discussion about infix/non-infix
- Martin: people will converge to not writing “new” (because it’s shorter)
- Iulian: so kill new
- Martin: you need new for edge-cases
- Seth: .new instead of prefix new?
- Martin: also you need new for anonymous classes
- Martin: it’s important in chisel (spelling? It’s some framework)
Martin: people define classes as case classes for it, so let’s give it to classes
Josh: dart has this with builders and constructors, and it works out nicely Josh: but dart has it so builders can’t call builders and it’s confusing so let’s keep new
Adriaan: we should limit use of “new”, lint thing or other compiler help Seth: e.g. under -strict it warns if using unnecessary new (for some definition unnecessary) Adriaan: figure out where new is absolutely needed and restrict to that Adriaan: continue Scala 3’s mantra of being more opinionated
Nullability
If we get nullability over the summer, then we’ll try to land it in Scala 3
Inline
https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html
Presented by Nicolas
inline
is guaranteed inline (unlike final
)
Miles shared (unclear) concerns about limitations with literal types (42.type)
Miles: could we have a “fuel” (sp?) integer? That is, an integer that goes down to 0.
- (many): no, it’s hard to prove these things in the compiler (and other implementation details)
Martin: Or could we just disallow recursion?
- Nicolas: yeah, we could, and tell users to use staging for that (Olivier approves :D)
Martin: Hmm, we might not need inline on parameters
- Nicolas: I agree, just can just use staging instead
Staging
https://dotty.epfl.ch/docs/reference/metaprogramming/macros.html
Presented by Olivier
Miles: the example is too basic, no recursion: can we do typeclass derivation with this? (need recursion)
Adriaan: how staging works must be clear to the SIP committee and to users, even if it targets advanced users Adriaan has concerns about sneaking whitebox macro style problems back into the compiler Adriaan/Seb: inline is simpler
- Olivier: I disagree, you can’t understand a large inline method, because it’s entangled with the optimizer
- Martin: with staging you can println half-way into staging
- Martin: the ideal is that inline desugars to staging
- Nicolas: except staging requires separate compilation (because we have no interpreter), inline doesn’t
- (Miles: or we can make an interpreter for a subset of the language)
- Nicolas also has some ingenious half-way between inline and staging, that he mentioned (too) quickly
More general meta-programming talks
Nicolas/Olivier present 3 “tiers” of meta-programming: inline, staging, dotty reflect
At the end it becomes clear that these aren’t desugarings from one to another (e.g. staging doesn’t desugar to dotty reflect, it’s its own thing, idem for inline to staging).
But even at the most powerful, dotty reflect, you cannot typecheck (or untypecheck), you only have typed trees.
No precise hanging questions, follow-up work or decisions, except:
Miles: how long to finish everything? Nicholas: hopefully by the end of the summer
Typeclass Derivation
https://dotty.epfl.ch/docs/reference/contextual/derivation.html
Presented by Miles.
For typeclasses that are monoidal (e.g. Monoid, Eq/Eqv, Show) just pass the summoned TC instances to the erased infrastructure.
There is a “derived” magic method name on TC companions that matches the “derives” keyword that you can put at the end of your case class.
Seth: no handling of higher-kinded types?
- Miles: no need at the compiler/scala.deriving level, just a small kernel, and a veneer in Shapeless 3
- Miles: AnyKind is not enough to do the necessary kind-polymorphism
Martin: But we said we weren’t adding anything to the standard library in 3.0
- (Someone): We can still add it to the 2.14 and 3.0 standard library
Erased Terms
https://dotty.epfl.ch/docs/reference/experimental/erased-defs.html
Olivier: Are they necessary?
- Yes’s and No’s
- Seb: in Scala.js I could use them
- Seth: should we ask the community?
- Miles: no, because you’ll always find someone that says yes
Decision: Find use cases and test performance
Seth: Defer to 3.1+?
(Someone): Yes, it doesn’t need to be in 3.0
(Someone): Maybe it’s superseded by @compileTimeOnly, that’s already in 2.13?
(A few): Should we delete the code or put it under a flag?
Guillaume: If we don’t delete it it’ll be in TASTY forever
Decision: delete the code, strive to make @compileTimeOnly its replacement
Runtime reflection
Drop it, and push the problem to the community to experiment solutions.
Enum
Update: if an enum extends java.lang.Enum, it’s a Java enum! Without extending it has a subset of java.lang.Enum’s API.
-strict vs -relaxed vs -Xsource
You use -Xsource V
and -migration
to help get to version V
Martin: I’d like a way to do it file-by-file
- (Many): having different files use different versions of Scala sounds very confusing