Another way to work around the TParallel.Join problem is to create a different implementation of the same pattern. As with the Async/Await pattern, I've created a version that supports the Join/Await pattern.
As with the TParallel version, Join accepts multiple TProc parameters. It, however, doesn't return an ITask interface but IJoin. This interface is similar to the IAsync interface used for the Async/Await pattern. It implements two versions of the Await method. One is the same as in the IAsync version, while the other can be used to catch exceptions raised in tasks:
type IJoin = interface ['{ED4B4531-B233-4A02-A09A-13EE488FCCA3}'] procedure Await(const awaitProc: TProc); overload; procedure Await(const awaitProc: TProc<Exception>); ...