Skip to content

Instantly share code, notes, and snippets.

@samdmarshall
Last active January 25, 2017 16:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samdmarshall/a7a657c8d1a1634d1e734bb17a11b31a to your computer and use it in GitHub Desktop.
Save samdmarshall/a7a657c8d1a1634d1e734bb17a11b31a to your computer and use it in GitHub Desktop.
// Intention: query a dictionary for a key-value pair, take the value as a path that needs to be expanded (tilde -> abspath)
// and then make it available to use.
let path_value = arguments["path"] ?? "" // the `?? ""` makes this a `String` and not an `Any`
var path = NSString.init(string:"\(keychain_path_value)") // this will accept an `Any` or a `String` as the type to
// subsitute when creating the `NSString` type object
if !path.isEqual(to:"") { // "if the string has contents, then expand the path"
path = path.expandingTildeInPath as NSString // cast `as NSString` is necessary because it returns a `String`
}
//
// So without the `?? ""` on line 1, if there is no value in the `argument` dictionary for the key `"path"`, that will return
// an `Any` object which will case the `NSString` object that is created on line 2 to return as `nil`, not as a valid
// `NSString` object. I don't like that the introduction of a single bridge call into Objective-C here makes all following
// statements that use that variable contain more risk due to the possibility of the optional value.
//
// Additionally, with this specific code, you can satisfy the swift (3.0.2) compiler with and without the `?? ""` in line 1
// because of the typing of the code. Which means I could remove it, this could still be seen as "valid" without raising
// any warnings and be fundamentally poorly written code for handling the intention properly. Furthermore, the default value
// assignment can be removed without making any indication about the type system and implication of the changes as such.
//
@nheagy
Copy link

nheagy commented Jan 25, 2017

The problem on line 4 is an intentional design of the language: if something has no value, the programmer has to be explicit about what value they want instead.

String has free bridging to NSString, so I'd expect that using String on line 5 instead would avoid the cast on line 9, and still work. I can't be 100% sure because I always use the Xcode version :P

@JEEBAN123
Copy link

this is a wrong program

@jonah-williams
Copy link

Good morning! I know I'm missing some of the context in which you want to use this path but I'm tempted to get it like this:

import Foundation

func getPath(_ arguments: [String: Any]) -> String? {
    guard let path_value = (arguments["path"] as? String) else { //Using a conditional cast when subscripting into the arguments dictionary lets us avoid the nil-coalescing operator and I think eliminates some of the `Any` type ambiguity when reading the code.
        return nil //Using a `guard` (or `if let`) here lets us avoid having to consider `nil` (or `isEqual(to:"")` checks later.
    }
    let path = NSString(string: path_value).expandingTildeInPath //It is a shame that Swift 3's removal of automatic bridging means we have to be explicit about use of `NSString` here but I guess it also makes our dependence on something outside the Swift standard lib explicit.
    return path
}

getPath(["path": "~/.profile"])
getPath(["path": "/etc/hosts"])
getPath(["path": ""])
getPath([:])

Alternately if you don't want the path result to be able to be an optional then you could define it as:

func getPath(_ arguments: [String: Any]) -> String {
    guard let path_value = (arguments["path"] as? String) else {
        return ""
    }
    let path = NSString(string: path_value).expandingTildeInPath
    return path
}

These satisfy swiftc (3.0.2) so I hope I've matched your toolchain.

@Frizlab
Copy link

Frizlab commented Jan 25, 2017

Would do something like

guard let raw_path = arguments["path"] as? String else {fail...}
let path = (raw_path as NSString).expandingTildeInPath

Not exactly your original code, but much more type safe (and dare I say, elegant 😄).

Also, question: Why do you check if the string is empty? Also, str == "" or even better str.empty seems prettier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment