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
FandGbe function types, and letF'andG'be the corresponding function types with any isolation specifier removed (including but not limited to@isolated(any). If eitherForGspecifies@isolated(any)then a value of typeFcan be converted to typeGif a value of typeF'could be converted to typeG'and the following conditions apply:
- <snip>
- <snip>
- If only
Fspecifies@isolated(any), thenGmust be anasyncfunction type.Gmay 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
Gmay 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!