inspired by the discussion surfaced here, i wanted to highlight some of the specific language regarding @isolated(any)
function conversions from the relevant evolution document. focusing on the third bullet point from the 'Conversions' section, it states:
Let
F
andG
be function types, and letF'
andG'
be the corresponding function types with any isolation specifier removed (including but not limited to@isolated(any)
. If eitherF
orG
specifies@isolated(any)
then a value of typeF
can be converted to typeG
if a value of typeF'
could be converted to typeG'
and the following conditions apply:
- <snip>
- <snip>
- If only
F
specifies@isolated(any)
, thenG
must be anasync
function type.G
may have any isolation specifier, but it will be ignored and the function will run with the isolation of the original value. The arguments and result must be sendable across an isolation boundary. It is unspecified whether the task will dynamically suspend when calling or returning from the resulting value.
the requirement that G
be an async
function type makes sense – in order to preserve the original function's isolation, async entry when it is called must be possible. however, i do not follow the subsequent statements regarding conversions to an arbitrary isolation being allowable. my reading of the text implies something like this would be permissible:
let f: @isolated(any) @Sendable () async -> Void = {}
let g: @MainActor @Sendable () async -> Void = f
however, this conversion currently does not work and produces an error. the statement
G
may have any isolation specifier, but it will be ignored and the function will run with the isolation of the original value.
seems confusing – why would ignoring the isolation be okay? is the idea that an intermediary function value could automatically 'box' the original function to do whatever 'isolation hopping' is needed? overall i'm a bit confused about what that paragraph is trying to convey exactly. cc @hborla & @John_McCall – any insights you may have would be appreciated!