Dictionary keys are no longer converted using keyDecodingStrategy under Xcode 10.2

After updating local Xcode to 10.2.0 (and later 10.2.1) I've noticed a change in how raw dictionary keys are returned from JSONDecoder. The decoder's keyDecodingStrategy used to apply to the string keys, and seems to no longer apply. A trivial script that demonstrates this:

import Foundation

#if swift(>=5.0)
print("This is Swift 5.0")
#elseif swift(>=4.2)
print("This is Swift 4.2")

struct Example: Decodable {
    var map: [String: String]

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let input = """
    {"map": {"foo_bar_baz": "ning"}}

let data = Data(input.utf8)
let decoded = try! decoder.decode(Example.self, from: data)

And the output with local xcode is:

$ /Applications/Xcode10.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -swift-version 4.2 decode.swift
This is Swift 4.2

$ /Applications/Xcode10.2.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -swift-version 4.2 decode.swift
This is Swift 4.2

I've found a previous conversation / pull request starting at

that discusses this change, but it's supposed to be in Swift 5 - what I'm seeing is that swift compiled with Xcode 4.2 exhibits the change as well.

Personally I like this change, but it's pretty backwards incompatible and I don't think Swift 4.2 should change behavior like this based on the tools used to compile it?

1 Like

cc @itaiferber

Xcode 10.2 contains the Swift 5 compiler — like previous versions of Swift, the Swift x compiler tends to have an x-1 mode, but that’s for source compatibility, not runtime compatibility. So Swift 4.2 mode with the Swift 5 compiler does not behave like Swift 4.2, but has API availability and similar syntax to Swift 4.2. The change in behavior is expected.

There have been a few threads along these lines lately but I’m on mobile at the moment and having a bit of trouble linking to one.

Ok, thanks for the reply. I'll see if I can push all the way through to swift 5 then.