How to make shallow capture sets less burdensome? #12871
Replies: 4 comments 7 replies
-
The capture set info of a class could also be inferred. E.g. if
|
Beta Was this translation helpful? Give feedback.
-
There's another rule for eliding capture sets When converting tests to shallow capture sets I repeatedly stumbled over situations like this: def f[C <: Any retains *] =
val x: () => C = ... That almost never makes sense. () => C only has very uncommon instances, such as def f[C <: Any retains *] =
val x: (() => C) retains C = ... We could do one of two things to improve the situation here
I think (2) will ultimately be more popular, since even with warnings, a type like |
Beta Was this translation helpful? Give feedback.
-
The suggested syntactic shorthands and their escape hatches make sense to me. The basic assumption guiding them (a curried function only performs side effect at its end) seems solid.
|
Beta Was this translation helpful? Give feedback.
-
We have now shallow capture sets in PR #12875 and the rule proposed in #12871 (comment) as PR #12892. I am still unsure about the the precise formulation of this rule. Currently is says: If In try3.scala we have a handler with two arguments of types: A more aggressive rule would be: If Aside: I find ia good way to think about subcapturing (which is in fact modelled like this in the compiler) is to turn things around. If A and B are capture sets then If Subcapturing is always a bit hard to wrap
|
Beta Was this translation helpful? Give feedback.
-
I am currently trying to make the type checker use shallow capture sets. Two reasons:
Int retains cap => Int retains cap
has capture setcap
under the deep interpretation, even though it might well be the identity overInt retains cap
. Similarly,B => A
orA => A
hasA
in its capture set.But if we do that we need some way to reduce the number of necessary
retains
annotations. For instance, assume thatA <: Any retains *
, then it would be very annoying to have to writeList[List[A] retains A] retains A
. We can get around it by defining a type aliastype List1[+A] = List[A] retains A
, but it would be more convenient to roll that information into the classList
itself. Something likeOr, for now, as long as we do not want change the syntax of the language,
Another issue is curried function types. Say we have a function of type
that retains
io
throughout. Right now it'sSuper annoying (in fact that's why we went to prefix syntax for retains sets in the paper to make this less of an eyesore).
One possible way around it is to decree that a curried function type never discards retains sets established to the left. The motivation is that a curried function type often does no computation until all arguments are supplied. So whatever is retained by the outermost function is retained by nested functions. With that convention, the last type could be written
If a curried function does in fact discard a capability before reaching the result part, we can use a type alias to express this:
One could also think of inline syntax for this. Maybe
A => (B => C => C) retains cap
, or is that is too inconspicuous,A => {B => C => C} retains cap
? But at least initially it won't be necessary, type aliases will work fine.By the same reasoning we could then say that tracked arguments in a curried function type are retained by all functions to the right. I.e. assuming the alias
X ==> Y
for(X => Y) retains *
, we could then writeand it would expand to
Aside: In the final version of Scala-CC, we could introduce
->
for pure functions that do not capture anything and defineA => B
asA -> B retains *
. With that convention we might be able to keep most function types as they are now in the new cc interpretation.Beta Was this translation helpful? Give feedback.
All reactions