Remix.run Logo
tarentel 19 hours ago

As someone who has been coding production Swift since 1.0 the Go example is a lot more what Swift in practice will look like. I suppose there are advantages to being able to only show the important parts.

The first line won't crash but in practice it is fairly rare where you'd implicitly unwrap something like that. URLs might be the only case where it is somewhat safe. But a more fair example would be something like

    func fetchUser(id: Int) async throws -> User {
      guard let url = URL(string: "https://api.example.com/users/\(id)") else {
        throw MyError.invalidURL
      }
    
      // you'll pretty much never see data(url: ...) in real life
      let request = URLRequest(url: url)
      // configure request
      
      let (data, response) = try await URLSession.shared.data(for: request)
      guard let httpResponse = response as? HTTPURLResponse,
            200..<300 ~= httpResponse.statusCode else {
        throw MyError.invalidResponseCode
      }
    
      // possibly other things you'd want to check
    
      return try JSONDecoder().decode(User.self, from: data)
    }
I don't code in Go so I don't know how production ready that code is. What I posted has a lot of issues with it as well but it is much closer to what would need to be done as a start. The Swift example is hiding a lot of the error checking that Go forces you to do to some extent.
eptcyka 13 hours ago | parent | next [-]

Oh, don't get me started on handling the same type of exception differently depending on what call actually threw the exception. I find the happy path in Swift to be lovely, but as soon as exceptions have to be handled or there's some details that have to be gotten right in terms of order of execution, everything turns into a massive mess.

Still better than the 3 lines of if err is not nil that go gets you to do though.

Jtsummers 19 hours ago | parent | prev | next [-]

I'm not familiar with Swift's libraries, but what's the point of making this two lines instead of one:

  let request = URLRequest(url: url)
  let (data, response) = try await URLSession.shared.data(for: request)

  // vs
  let (data, response) = try await URLSession.shared.data(from: url)
That aside, your Swift version is still about half the size of the Go version with similar levels of error handling.
tarentel 19 hours ago | parent [-]

The first one you can configure and it is the default way you'd see this done in real life. You can add headers, change the request type, etc. Likely, if you were making an actual app the request configuration would be much longer than 1 line I used. I was mostly trying to show that the Swift example was hiding a lot of things.

The second one is for downloading directly from a URL and I've never seen it used outside of examples in blog posts on the internet.

scottmf 14 hours ago | parent | prev | next [-]

Thanks. What could possibly cause an invalid URL in this example though?

fainpul 2 hours ago | parent | next [-]

Nothing. You would use `!` to force unwrap in this case.

I think the point of the comment was that in many cases, when constructing a url, you can't be sure that the input will result in a valid url (e.g. when receiving a string instead of an int), so you have to be more defensive and the required code is more verbose.

2 hours ago | parent [-]
[deleted]
mrbombastic 13 hours ago | parent | prev | next [-]

Not OP, There is none as far as I can tell but still force unwrapping that way is something people try to avoid in Swift and often times have the linter warn about. Reason being people will copy the pattern elsewhere and make the assumption something is safe, ultimately be wrong and crash your app. It is admittedly an opinionated choice though.

andrekandre 10 hours ago | parent [-]

there has been some talk ofmusing macros ro validate at runtime; personally i'd love it if that got in officially.

[0] https://forums.swift.org/t/url-macro/63772

jshier 10 hours ago | parent | prev | next [-]

Anything taking arbitrary values or user input could cause an invalid URL, especially on earlier OS versions. Newer OS versions will use a newer URL standard which is more flexible. You could wrap your URL encoding logic into a throwing or non-throwing init as well, the example just used the simple version provided by Foundation.

lawgimenez 13 hours ago | parent | prev [-]

In my experience, migrating to a new API endpoint while your stubborn users just refused to update your app for some reason.

willtemperley 9 hours ago | parent | prev [-]

Yes swift-format will say "never force-unwrap" because it is a potential crash.

saagarjha 3 hours ago | parent [-]

No it will not.

2 hours ago | parent | next [-]
[deleted]
2 hours ago | parent | prev | next [-]
[deleted]
willtemperley 2 hours ago | parent | prev [-]

Are you sure about that?

let x: Int? = 0

let y: Int = x!

git ls-files -z -- '*.swift' | xargs -0 swift format lint --parallel

error: [NeverForceUnwrap] do not force unwrap 'x'

saagarjha 2 hours ago | parent [-]

You’ve turned that on; it’s off by default for good reasons: https://github.com/swiftlang/swift-format/blob/02c5a88a32719...

willtemperley 2 hours ago | parent [-]

That's the standard for swiftlang CI which is what I use.