Skip to content
This repository was archived by the owner on Jun 5, 2023. It is now read-only.
This repository was archived by the owner on Jun 5, 2023. It is now read-only.

Should we bring back rewrite methods? #56

@odersky

Description

@odersky

At the SIP meeting several people felt that rewrite methods were a rather natural way to express typelevel programming without having to breakout to the meta level. We also identified two areas where we don't currently have a solution and rewrite methods look like they could fit the bill:

  • Typelevel stuff where synthesized terms are dependent on implicit search. Without a mechanism like implicit matches, we are forced to stay in logic programming mode forever. I can see a specific use case in typeclass derivation.

  • String interpolators in patterns. We need a way here to derive an expected type for an embedded pattern from the contents of a string. This needs a form of whiteboxity. Rewrite methods could do it in principle, whether at acceptable complexity remains to be seen.

We removed rewrite methods in #5109, #5138 since the specification and implementation problems seemed too hard. In particular:

  • it was very tricky to produce untyped trees with typed splices,
  • we had to pickle untyped as well as typed trees,
  • the scheme to package implicits to come with untyped trees was quite complex,
  • using rewritten terms to implicitly define types was a performance bottleneck once
    the defined types got large (i.e. 500+ elements).
  • the fact that inlined code could fail in typer was unsettling
  • the last point also implicitly moves the type checker into the APIs of libraries. Subtle
    changes in the typechecker might break inlined code that worked with an earlier version.

But maybe we can change the spec and implementation scheme to address these issues?
Here's an idea for morphed rewrite methods, which I suggest should continue to carry the inline modifier instead of rewrite, as was the case formerly.

  • Inline their bodies as typed trees, as is the case for regular inline methods now
  • The right hand side of an inline method may be one of three special match expressions: inline match, type match, implicit match.
  • An inline match is evaluated at inlining time, just like we used to handle rewrite matches. The language of patterns available in an inline match might be restricted to make such evaluation predictable. Inline matches must rewrite to an alternative. The rewritten alternative is subject to some substitutions or wrappings that map pattern-bound variables to parts of the scrutinee. This can affect terms as well as types.
  • The type of an inlined expression is the type of the rewritten body.
  • Implicit matches and type matches are as described before, except that they again work with typed trees.
  • We keep match types to define computed types; no need to rely on term inlining to do this.

So, in essence, this is like the previous rewrite methods, except that instead of re-typing trees from scratch at the inlined position, we take the typed body and specialize it. Specialization is by picking an alternative in a match, by substituting parts of the scrutinee for pattern-bound variables, and by substituting actual for formal parameters.

This new version of inline methods is different from the currently implemented one in that the type of an inlined expression is in general a subtype of the inline method's return type. We can accommodate both versions by adopting a syntax element from match types.

inline def f(...): T = ...     // type of inlined expression is always T
inline def g(...) <: U = ...   // type of inlined expression is a subtype of U

Before embarking on fleshing this out, which - even accounting for previous work - will be a large effort, it would be good to discuss whether we need this, and to look at all the possible reasons why we should not do this. So, if you can contribute to the discussion, please do!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions