<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<meta name="CocoaVersion" content="1404.46">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Helvetica}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 14.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #0433ff}
p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 15.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; line-height: 15.0px; font: 12.0px Helvetica}
p.p7 {margin: 0.0px 0.0px 0.0px 12.0px; line-height: 14.0px; font: 12.0px Helvetica; color: #011892; min-height: 14.0px}
p.p8 {margin: 0.0px 0.0px 0.0px 24.0px; font: 12.0px Helvetica; color: #008e00}
p.p9 {margin: 0.0px 0.0px 0.0px 24.0px; font: 12.0px Helvetica; color: #008e00; min-height: 14.0px}
p.p10 {margin: 0.0px 0.0px 0.0px 12.0px; font: 12.0px Helvetica; color: #011892}
p.p11 {margin: 0.0px 0.0px 0.0px 12.0px; font: 12.0px Helvetica; color: #011892; min-height: 14.0px}
p.p12 {margin: 0.0px 0.0px 0.0px 36.0px; font: 12.0px Helvetica; color: #941100}
p.p13 {margin: 0.0px 0.0px 0.0px 36.0px; font: 12.0px Helvetica; color: #941100; min-height: 14.0px}
p.p14 {margin: 0.0px 0.0px 0.0px 48.0px; font: 12.0px Helvetica; color: #011892}
p.p15 {margin: 0.0px 0.0px 0.0px 48.0px; font: 12.0px Helvetica; color: #011892; min-height: 14.0px}
p.p16 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #b4261a}
p.p17 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p18 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #000000; min-height: 14.0px}
span.s1 {font: 11.0px Menlo; font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #0433ff}
span.s3 {font-variant-ligatures: no-common-ligatures}
span.s4 {font-variant-ligatures: no-common-ligatures; color: #3495af}
span.s5 {font-variant-ligatures: no-common-ligatures; color: #000000}
</style>
</head>
<body>
<p class="p1">The failing testcase is <span class="s1"><b>TestNSTask.test_pipe_stdout_and_stderr_same_pipe</b></span>. The call to posix_spawn returns an error code 9 (EBADF).<span class="Apple-converted-space"> </span></p>
<p class="p2"><br></p>
<p class="p1">In order to avoid code repetition I've wrapped all posix calls with a throwing status code check;</p>
<p class="p2"><br></p>
<p class="p3"><span class="s2">private</span><span class="s3"> </span><span class="s2">func</span><span class="s3"> posix(</span><span class="s2">_</span><span class="s3"> code: </span><span class="s4">Int32</span><span class="s3">) </span><span class="s2">throws</span><span class="s3"> {</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span></span><span class="s2">switch</span><span class="s3"> code {</span></p>
<p class="p4"><span class="s5"><span class="Apple-converted-space">    </span></span><span class="s3">case</span><span class="s5"> 0: </span><span class="s3">return</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span></span><span class="s2">default</span><span class="s3">: </span><span class="s2">throw</span><span class="s3"> </span><span class="s4">NSError</span><span class="s3">(domain: </span><span class="s4">NSPOSIXErrorDomain</span><span class="s3">, code: </span><span class="s4">Int</span><span class="s3">(code), userInfo: </span><span class="s2">nil</span><span class="s3">)</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span>}</span></p>
<p class="p3"><span class="s3">}</span></p>
<p class="p2"><br></p>
<p class="p1">However this produces the not-so-helpful error dump on OSX:</p>
<p class="p2"><br></p>
<p class="p3"><span class="s3"><b>Test Case 'TestNSTask.test_pipe_stdout_and_stderr_same_pipe' started at 10:20:59.741</b></span></p>
<p class="p3"><span class="s3"><b>fatal error: 'try!' expression unexpectedly raised an error: &lt;NSError: 0x0000600000067c40&gt;: file /Users/buildnode/jenkins/workspace/oss-swift-package-osx/swift/stdlib/public/core/ErrorType.swift, line 53</b></span></p>
<p class="p2"><br></p>
<p class="p5"><br></p>
<p class="p5"><br></p>
<p class="p6">On 2016-05-13 21:07:59 +0000, Tony Parker via swift-corelibs-dev said:</p>
<p class="p5"><br></p>
<p class="p7"><br></p>
<p class="p8">On May 13, 2016, at 1:05 PM, James Lee &lt;james@jelee.co.uk&gt; wrote:</p>
<p class="p9"><br></p>
<p class="p8">Cheers for the clarification. I started assuming there may be a reason when changing the guard let on the launch args to use the InvalidArgumentException.</p>
<p class="p9"><br></p>
<p class="p8">Could this be a position where we may need os checking to cover the regression for the moment. It seems odd that the test would pass in CI when an error is thrown with a try! but fail on OSX</p>
<p class="p10">Task is certainly one of the cases where the underlying stuff that we’re abstracting is significantly different, so I’m not too surprised.</p>
<p class="p11"><br></p>
<p class="p10">We should try to get something in place so we’re not failing on OS X in the short term for sure.</p>
<p class="p11"><br></p>
<p class="p10">- Tony</p>
<p class="p11"><br></p>
<p class="p8">Sent from my iPhone</p>
<p class="p9"><br></p>
<p class="p12">On 13 May 2016, at 20:48, Tony Parker &lt;anthony.parker@apple.com&gt; wrote:</p>
<p class="p13"><br></p>
<p class="p12">Hi James,</p>
<p class="p13"><br></p>
<p class="p14">On May 13, 2016, at 12:25 PM, James Lee via swift-corelibs-dev &lt;swift-corelibs-dev@swift.org&gt; wrote:</p>
<p class="p15"><br></p>
<p class="p14">Following on from a previous discussion with Tests failing on OSX. I have been looking into the failures. It seems that one of the earliest failures is due to an error from a try! within NSTask.launch(). This came in with this commit: https://github.com/apple/swift-corelibs-foundation/commit/4c6f04cfcad3d4b06688558021595d06751fc66a</p>
<p class="p15"><br></p>
<p class="p14">Going by the docs for Foundation - The launch function apparently "Raises an NSInvalidArgumentException if the launch path has not been set or is invalid or if it fails to create a process."</p>
<p class="p15"><br></p>
<p class="p14">https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTask_Class/#//apple_ref/occ/instm/NSTask/launch</p>
<p class="p15"><br></p>
<p class="p14">My question is, should this be built into the Swift Foundation API? The documentation for Swift doesn't state that the launch function throws.</p>
<p class="p15"><br></p>
<p class="p14">With the test that is failing expecting an error, it feels more Swift-y to have any errors throw explicitly, rather than looking at what the lower level fills the data with.</p>
<p class="p15"><br></p>
<p class="p14">But before jumping into doing this, I would rather put it out there and see what the community feels about this?</p>
<p class="p13"><br></p>
<p class="p12">Unfortunately the ‘throws’ syntax in Swift often causes a mixup between two different things, because it flipped the terminology from what all of our documentation and header comments use.</p>
<p class="p13"><br></p>
<p class="p12">1. Cocoa uses exceptions (@throw in ObjC) to indicate programmer errors and they are generally not intended to be recoverable.<span class="Apple-converted-space">  </span>Example: passing nil where not expected, passing an invalid argument, failing to meet a precondition of an API.</p>
<p class="p12">2. Cocoa uses NSError ** to indicate runtime errors that are recoverable or at least presentable to user. Example: out of disk space, name of file already exists.</p>
<p class="p13"><br></p>
<p class="p12">The ‘throws’ syntax in Swift is actually for case #2, not #1. In Swift, #1 is fatalError or preconditionFailure. #2 is ‘throw Error’.</p>
<p class="p2"><br></p>
<p class="p1">While API compatibility should be the fore-most goal here, I feel like there's room for improvement here for the API overlays. While in ObjC one has the ability to recover from NSInvalidArgumentException, on Swift this would trap.</p>
<p class="p2"><br></p>
<p class="p13"><br></p>
<p class="p12">In the case of NSTask, when the documentation says “raises an NSInvalidArgumentException” (#1) then in Swift, that should translate to fatalError or preconditionFailure.</p>
<p class="p2"><br></p>
<p class="p1">As a resort; I propose to change the error wrapper (see https://github.com/apple/swift-corelibs-foundation/pull/362):</p>
<p class="p2"><br></p>
<p class="p3"><span class="s2">private</span><span class="s3"> </span><span class="s2">func</span><span class="s3"> posix(</span><span class="s2">_</span><span class="s3"> code: </span><span class="s4">Int32</span><span class="s3">) {</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span></span><span class="s2">switch</span><span class="s3"> code {</span></p>
<p class="p4"><span class="s5"><span class="Apple-converted-space">    </span></span><span class="s3">case</span><span class="s5"> 0: </span><span class="s3">return</span></p>
<p class="p16"><span class="s5"><span class="Apple-converted-space">    </span></span><span class="s2">case</span><span class="s5"> </span><span class="s4">EBADF</span><span class="s5">: </span><span class="s4">fatalError</span><span class="s5">(</span><span class="s3">"POSIX command failed with error: </span><span class="s5">\</span><span class="s3">(</span><span class="s5">code</span><span class="s3">) -- EBADF"</span><span class="s5">)</span></p>
<p class="p16"><span class="s5"><span class="Apple-converted-space">    </span></span><span class="s2">default</span><span class="s5">: </span><span class="s4">fatalError</span><span class="s5">(</span><span class="s3">"POSIX command failed with error: </span><span class="s5">\</span><span class="s3">(</span><span class="s5">code</span><span class="s3">)"</span><span class="s5">)</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span>}</span></p>
<p class="p3"><span class="s3">}</span></p>
<p class="p2"><br></p>
<p class="p1">Which would produce the following –more helpful– error on OSX:</p>
<p class="p2"><br></p>
<p class="p3"><span class="s3"><b>Test Case 'TestNSTask.test_pipe_stdout_and_stderr_same_pipe' started at 10:13:55.584</b></span></p>
<p class="p3"><span class="s3"><b>fatal error: POSIX command failed with error: 9 -- EBADF: file &lt;somedir&gt;/swift-corelibs-foundation/Foundation/NSTask.swift, line 424</b></span></p>
<p class="p17"><br></p>
<p class="p2"><br></p>
<p class="p13"><br></p>
<p class="p12">Hope this helps,</p>
<p class="p12">- Tony</p>
<p class="p13"><br></p>
<p class="p14">Cheers</p>
<p class="p15"><br></p>
<p class="p14">James</p>
<p class="p14">_______________________________________________</p>
<p class="p14">swift-corelibs-dev mailing list</p>
<p class="p14">swift-corelibs-dev@swift.org</p>
<p class="p14">https://lists.swift.org/mailman/listinfo/swift-corelibs-dev</p>
<p class="p13"><br></p>
<p class="p9"><br></p>
<p class="p11"><br></p>
<p class="p10">_______________________________________________</p>
<p class="p10">swift-corelibs-dev mailing list</p>
<p class="p10">swift-corelibs-dev@swift.org</p>
<p class="p10">https://lists.swift.org/mailman/listinfo/swift-corelibs-dev</p>
<p class="p18"><br></p>
</body>
</html>