Why does URL.checkResourceIsReachable() return a Bool?


(Charles Srstka) #1

-[NSURL checkResourceIsReachableAndReturnError:] has taken on several forms in Swift during its development, sometimes returning a Boolean and an error by reference, sometimes returning Void and using Swift’s do/try/catch system. In Swift 3, though, it appears to do both, which is weird:

func checkResourceIsReachable() throws -> Bool

All the documentation has to say about this is:

"This method is currently applicable only to URLs for file system resources. For other URL types, false is returned.”

It does not, however, say whether non-file URLs are the only thing that can cause a return of ‘false’, so I don’t know whether I should be checking the return value when checking a file URL or not. This results in having to check both the return value *and* the catch block each time, which is fairly awkward. I’m also not clear on why checking reachability on a non-file URL can’t just return an error like it did in the past.

What’s the rationale behind this?

Charles


(Félix Cloutier) #2

One line above the text that you quoted, you can read:

If this method returns false, the object pointer referenced by error is populated with additional information.

The rationale is probably that this method was awkward to begin with. It's unclear to me why it was decided to return a `NSError` by reference and a bool that is seemingly equivalent to `error != nil`.

Félix

···

Le 7 août 2016 à 10:41:32, Charles Srstka via swift-evolution <swift-evolution@swift.org> a écrit :

-[NSURL checkResourceIsReachableAndReturnError:] has taken on several forms in Swift during its development, sometimes returning a Boolean and an error by reference, sometimes returning Void and using Swift’s do/try/catch system. In Swift 3, though, it appears to do both, which is weird:

func checkResourceIsReachable() throws -> Bool

All the documentation has to say about this is:

"This method is currently applicable only to URLs for file system resources. For other URL types, false is returned.”

It does not, however, say whether non-file URLs are the only thing that can cause a return of ‘false’, so I don’t know whether I should be checking the return value when checking a file URL or not. This results in having to check both the return value *and* the catch block each time, which is fairly awkward. I’m also not clear on why checking reachability on a non-file URL can’t just return an error like it did in the past.

What’s the rationale behind this?

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charles Srstka) #3

One line above the text that you quoted, you can read:

If this method returns false, the object pointer referenced by error is populated with additional information.

That’s only in the documentation for the original NSURL method (which still returns an error by reference). This is the entirety of the description in the documentation for the new one on URL:

"This method synchronously checks if the resource’s backing store is reachable. Checking reachability is appropriate when making decisions that do not require other immediate operations on the resource, e.g. periodic maintenance of UI state that depends on the existence of a specific document. When performing operations such as opening a file or copying resource properties, it is more efficient to simply try the operation and handle failures. This method is currently applicable only to URLs for file system resources. For other URL types, false is returned.”

The rationale is probably that this method was awkward to begin with. It's unclear to me why it was decided to return a `NSError` by reference and a bool that is seemingly equivalent to `error != nil`.

It’s not like that anymore. On the new URL value type, it both returns a bool *and* is marked ‘throws’. So you have to check *both* whether it returned false *and* whether it threw an error.

Charles

···

On Aug 7, 2016, at 1:59 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:


(Lily Ballard) #4

The documentation is wrong (for Swift).

For file URLs, this method returns true/false without throwing an error
(at least, if the file doesn't exist there's no error; I don't know if
there are conditions that would cause an error to be returned).

For non-file URLs this method throws an error.

The bit about "For other URL types, false is returned" is written for
Obj-C, where you can completely disregard the error. You can't disregard
the error in Swift, so it doesn't apply (though you can use try? and
treat a nil value the same as false)

-Kevin

···

On Sun, Aug 7, 2016, at 10:41 AM, Charles Srstka via swift-evolution wrote:

-[NSURL checkResourceIsReachableAndReturnError:] has taken on several
forms in Swift during its development, sometimes returning a Boolean
and an error by reference, sometimes returning Void and using Swift’s
do/try/catch system. In Swift 3, though, it appears to do both, which
is weird:

func checkResourceIsReachable() throws -> Bool

All the documentation has to say about this is:

"This method is currently applicable only to URLs for file system
resources. For other URL types, false is returned.”

It does not, however, say whether non-file URLs are the only thing
that can cause a return of ‘false’, so I don’t know whether I should
be checking the return value when checking a file URL or not. This
results in having to check both the return value *and* the catch block
each time, which is fairly awkward. I’m also not clear on why checking
reachability on a non-file URL can’t just return an error like it did
in the past.

What’s the rationale behind this?

Charles

_________________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #5

Hi Charles,

At least for now, discussion of the design of core libraries belongs on
swift-corelibs-dev, rather than swift-evolution. That's where you'll
reach the people that can usefully respond.

HTH,

···

on Sun Aug 07 2016, Charles Srstka <swift-evolution@swift.org> wrote:

-[NSURL checkResourceIsReachableAndReturnError:] has taken on several
forms in Swift during its development, sometimes returning a Boolean
and an error by reference, sometimes returning Void and using Swift’s
do/try/catch system. In Swift 3, though, it appears to do both, which
is weird:

func checkResourceIsReachable() throws -> Bool

All the documentation has to say about this is:

"This method is currently applicable only to URLs for file system resources. For other URL types, false is returned.”

It does not, however, say whether non-file URLs are the only thing
that can cause a return of ‘false’, so I don’t know whether I should
be checking the return value when checking a file URL or not. This
results in having to check both the return value *and* the catch block
each time, which is fairly awkward. I’m also not clear on why checking
reachability on a non-file URL can’t just return an error like it did
in the past.

What’s the rationale behind this?

--
-Dave


(Félix Cloutier) #6

I read it from the Mac Developer Library's documentation, which has all of that for the Swift version too (link <https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/#//apple_ref/occ/instm/NSURL/checkResourceIsReachableAndReturnError:>).

I was commenting on the awkwardness of the Objective-C interface. Given that the error parameter is only populated when the return value is `false`, in the transposed Swift world, you shouldn't need to check the return value.

Félix

···

Le 7 août 2016 à 12:14:38, Charles Srstka <cocoadev@charlessoft.com> a écrit :

On Aug 7, 2016, at 1:59 PM, Félix Cloutier <felixcca@yahoo.ca <mailto:felixcca@yahoo.ca>> wrote:

One line above the text that you quoted, you can read:

If this method returns false, the object pointer referenced by error is populated with additional information.

That’s only in the documentation for the original NSURL method (which still returns an error by reference). This is the entirety of the description in the documentation for the new one on URL:

"This method synchronously checks if the resource’s backing store is reachable. Checking reachability is appropriate when making decisions that do not require other immediate operations on the resource, e.g. periodic maintenance of UI state that depends on the existence of a specific document. When performing operations such as opening a file or copying resource properties, it is more efficient to simply try the operation and handle failures. This method is currently applicable only to URLs for file system resources. For other URL types, false is returned.”

The rationale is probably that this method was awkward to begin with. It's unclear to me why it was decided to return a `NSError` by reference and a bool that is seemingly equivalent to `error != nil`.

It’s not like that anymore. On the new URL value type, it both returns a bool *and* is marked ‘throws’. So you have to check *both* whether it returned false *and* whether it threw an error.

Charles


(Jacob Bandes-Storch) #7

If you were to design this API for Swift in the first place, you might want
to do something entirely different:

extension URL {
    enum Reachability {
        case reachable
        case notReachable(ErrorProtocol)
    }
    func reachability() -> Reachability
}

···

On Sun, Aug 7, 2016 at 12:20 PM, Félix Cloutier <swift-evolution@swift.org> wrote:

I read it from the Mac Developer Library's documentation, which has all of
that for the Swift version too (link
<https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/#//apple_ref/occ/instm/NSURL/checkResourceIsReachableAndReturnError:>
).

I was commenting on the awkwardness of the Objective-C interface. Given
that the error parameter is only populated when the return value is
`false`, in the transposed Swift world, you shouldn't need to check the
return value.

Félix

Le 7 août 2016 à 12:14:38, Charles Srstka <cocoadev@charlessoft.com> a
écrit :

On Aug 7, 2016, at 1:59 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

One line above the text that you quoted, you can read:

If this method returns false, the object pointer referenced by error is
populated with additional information.

That’s only in the documentation for the original NSURL method (which
still returns an error by reference). This is the entirety of the
description in the documentation for the new one on URL:

"This method synchronously checks if the resource’s backing store is
reachable. Checking reachability is appropriate when making decisions that
do not require other immediate operations on the resource, e.g. periodic
maintenance of UI state that depends on the existence of a specific
document. When performing operations such as opening a file or copying
resource properties, it is more efficient to simply try the operation and
handle failures. This method is currently applicable only to URLs for file
system resources. For other URL types, false is returned.”

The rationale is probably that this method was awkward to begin with. It's
unclear to me why it was decided to return a `NSError` by reference and a
bool that is seemingly equivalent to `error != nil`.

It’s not like that anymore. On the new URL value type, it both returns a
bool *and* is marked ‘throws’. So you have to check *both* whether it
returned false *and* whether it threw an error.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charles Srstka) #8

Again, that is the documentation for NSURL, not the new URL value type. Check the top of the file: “NSURL Class Reference”.

Charles

···

On Aug 7, 2016, at 2:20 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I read it from the Mac Developer Library's documentation, which has all of that for the Swift version too (link <https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/#//apple_ref/occ/instm/NSURL/checkResourceIsReachableAndReturnError:>).


(Charles Srstka) #9

That is excellent.

Charles

···

On Aug 7, 2016, at 2:33 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

extension URL {
    enum Reachability {
        case reachable
        case notReachable(ErrorProtocol)
    }
    func reachability() -> Reachability
}


(Charles Srstka) #10

In my testing, this does not appear to be correct; it actually seems to throw an error in both cases. For a file URL pointing to a file that doesn’t exist, it throws NSFileReadNoSuchFileError, and for an HTTP URL, it throws NSFileNoSuchFileError. This further causes me to question the purpose of having the method return a boolean.

Here’s the code:

import Foundation

let fileURL = URL(fileURLWithPath: "/asdfasdfasdf")
let httpURL = URL(string: "http://asdfasdfasdf.com/asdfasdfasdf")!

do {
    if try fileURL.checkResourceIsReachable() {
        print("file URL is reachable")
    } else {
        print("file URL returned false")
    }
} catch {
    print("file URL threw error: \(error)")
}

do {
    if try httpURL.checkResourceIsReachable() {
        print("http URL is reachable")
    } else {
        print("http URL returned false")
    }
} catch {
    print("http URL threw error: \(error)")
}

And the output:

file URL threw error: Error Domain=NSCocoaErrorDomain Code=260 "The file “asdfasdfasdf” couldn’t be opened because there is no such file." UserInfo={NSURL=file:///asdfasdfasdf, NSFilePath=/asdfasdfasdf, NSUnderlyingError=0x100903eb0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
http URL threw error: Error Domain=NSCocoaErrorDomain Code=4 "The file doesn’t exist."
Program ended with exit code: 0

Charles

···

On Aug 8, 2016, at 4:32 PM, Kevin Ballard <kevin@sb.org> wrote:

The documentation is wrong (for Swift).

For file URLs, this method returns true/false without throwing an error (at least, if the file doesn't exist there's no error; I don't know if there are conditions that would cause an error to be returned).

For non-file URLs this method throws an error.

The bit about "For other URL types, false is returned" is written for Obj-C, where you can completely disregard the error. You can't disregard the error in Swift, so it doesn't apply (though you can use try? and treat a nil value the same as false)


(Lily Ballard) #11

Well that's curious. I tested in the REPL for URL(fileURLWithPath:
"/foo/bar") and it simply returned false, but running the script does
throw an error. And doubly-weird, if I go back to the REPL and prefix
the call with `try?` the value becomes nil instead of false. So that's
pretty confusing.

It definitely seems like this method should behave differently than it
does today. My suggestion would be to replace it with something like

func checkResourceIsReachable() -> (Bool, Error?)

This best approximates the Obj-C behavior where you can just use the
return value if you don't care about the reason why it's not reachable,
and you can inspect the error if you do care.

-Kevin Ballard

···

On Mon, Aug 8, 2016, at 03:13 PM, Charles Srstka wrote:

On Aug 8, 2016, at 4:32 PM, Kevin Ballard <kevin@sb.org> wrote:

The documentation is wrong (for Swift).

For file URLs, this method returns true/false without throwing an
error (at least, if the file doesn't exist there's no error; I don't
know if there are conditions that would cause an error to be
returned).

For non-file URLs this method throws an error.

The bit about "For other URL types, false is returned" is written for
Obj-C, where you can completely disregard the error. You can't
disregard the error in Swift, so it doesn't apply (though you can use
try? and treat a nil value the same as false)

In my testing, this does not appear to be correct; it actually seems
to throw an error in both cases. For a file URL pointing to a file
that doesn’t exist, it throws NSFileReadNoSuchFileError, and for an
HTTP URL, it throws NSFileNoSuchFileError. This further causes me to
question the purpose of having the method return a boolean.

Here’s the code:

import Foundation

let fileURL = URL(fileURLWithPath: "/asdfasdfasdf")
let httpURL = URL(string: "http://asdfasdfasdf.com/asdfasdfasdf")!

do {
if try fileURL.checkResourceIsReachable() {
print("file URL is reachable")
    } else {
print("file URL returned false")
    }
} catch {
print("file URL threw error: \(error)")
}

do {
if try httpURL.checkResourceIsReachable() {
print("http URL is reachable")
    } else {
print("http URL returned false")
    }
} catch {
print("http URL threw error: \(error)")
}

And the output:

*file URL threw error: Error Domain=NSCocoaErrorDomain Code=260 "The
file “asdfasdfasdf” couldn’t be opened because there is no such file."
UserInfo={NSURL=file:///asdfasdfasdf, NSFilePath=/asdfasdfasdf,
NSUnderlyingError=0x100903eb0 {Error Domain=NSPOSIXErrorDomain Code=2
"No such file or directory"}}*
*http URL threw error: Error Domain=NSCocoaErrorDomain Code=4 "The
file doesn’t exist."*
*Program ended with exit code: 0*
**
Charles