[swift-evolution] Pitch: Much better-performing, Swift-native Progress replacement

Tony Parker anthony.parker at apple.com
Wed Feb 22 12:52:41 CST 2017


It seems like the main complaints about NSProgress revolve around KVO, which there is no question about not being right for Swift in many ways. I’m aware of that. I think the right answer there is instead to improve KVO in Swift, not to replace all KVO in the SDK on a case-by-case basis with ad-hoc observation mechanisms. I acknowledge that improving KVO is not a small task.

Responding to some of the other notes in your description:


* KVO

NSProgress does not use KVO to update its parent progress objects. You can actually see this in the swift-corelibs-foundation version of NSProgress. It does post notifications for its properties this way though.

* Implicit tree composition

I agree that implicit tree composition is not a great idea except in very controlled circumstances. That’s why I introduced the explicit API.

* Explicit tree composition

It looks like you’ve used this incorrectly. The reason the ProgressReporting protocol exists is for types to expose a progress that the caller can then compose into their own progress tree. There is no requirement to use it, but it establishes the pattern.

// disclaimer: typed in Mail
class X {
    var progress: Progress {
        let p = Progress.discreteProgress(totalUnitCount: 10)
        // start with some progress
        p.completedUnitCount = 5
    }
}

var x = X()
var p = Progress.discreteProgress(totalUnitCount: 2)
var childA = Progress(totalUnitCount: 4, parent: p, pendingUnitCount: 1) // childA is 50% of p
p.addChild(x.progress, pendingUnitCount: 1) // x.progress is 50% of p

p.fractionCompleted // 0.25

* Updating progress in a tight loop

No matter how efficient you make updating the properties (and, again, I acknowledge that KVO support adds a cost here), the fact that progress forms trees and the trees are designed to be arbitrarily large, means that you should always consider the cost of updating too frequently. Reducing the cost per update is still a noble goal. As is reducing autoreleases.

* Updating completedUnitCount atomically

The best practice here is to keep the progress object thread local. I think that updating one progress from multiple threads could be a code smell. Perhaps then you are doing several parts of the work and you should instead form a tree. This also leads in a direction where completed unit count is either 100% handed out to children or 100% controlled by your work-update-progress loop. Mixing the two leads to easy confusion about who is responsible for which portion. If you follow this rule, you never have to get the completed unit count, which means the race you describe does not exist.


> On Feb 21, 2017, at 2:25 PM, Charles Srstka via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> On Feb 21, 2017, at 3:52 PM, Rod Brown <rodney.brown6 at icloud.com <mailto:rodney.brown6 at icloud.com>> wrote:
>> 
>> It still holds the fundamental oddities of NSProgress that I find weird. Like "current progress" always strikes me as very odd concept.
> 
> The “current progress” bit is there mainly for source compatibility. I’d expect it would not be the norm for new code.
> 
>> I'd be interested to see what Tony Parker and the Core Team think!
> 
> So would I.
> 
> Charles
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170222/75e8a32e/attachment.html>


More information about the swift-evolution mailing list