Currently, when the root function is exited, WxeFunction.Abort() is invoked. This will recursively abort all WxeSteps that are still part of the WxeFunction, including the sub function, if it is still executing. However, all sub functions that have been completed by that time, have already been removed and WxeFunction.Abort() was never called for them.
This alone is not a problem, the WxeFunction was completed instead of aborted. The inconsistency is created with the WxeSteps of the root function that have also already completed their execution at the time the root function is aborted. This means, WxeSteps or WxeFunctions that are a direct part of the root function will always be aborted while sub functions called from within a WxePageStep are not.
A consistent approach needs to be determined that works for all WxeFunctions. Possibly, Abort should be changed to IDisposable.Dispose().
Note that we have to decide how to handle the returning function if we use Disposable sematics, see below.
Note that historically, the WxeStep did have Disposable sematics, but this was changed in August 2005, when we introduced serialization:
The likely reasoning was that Disposable was implemented with the full Disposable-pattern, including Finalizer. Since the finalizer would have also triggered after serialization and we didn't know that implementing the Finalizer was actually an (not yet discovered) anti-pattern, the 'correct' approach was to simply change the sematics from Disposable to Abort.
Another reason could be the sematics of WxePageStep.ReturningFunction. If we dispose a root function (called via Execute External) before returning to the calling page, the WxePageStep.ReturningFunction would contain a disposed instance. At the same time, we cannot not dispose the root function before returning to the page since it is not guaranteed that the page is still available to consume the returning function.