Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-8157] Codable type with constant property with random default value #50689

Open
swift-ci opened this issue Jun 30, 2018 · 4 comments
Open
Assignees
Labels
Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself improvement

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-8157
Radar rdar://problem/41725505
Original Reporter garricn (JIRA User)
Type Improvement
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Improvement, Codable
Assignee @itaiferber
Priority Medium

md5: 2b489ed0466d80215b79b287a0e78e2c

Issue Description:

A constant property - of a Codable type - having a random default value, cannot be assigned the encoded value after decoding. This appears to be expected behavior, however, it maybe the case that we can make this more clear to the developer. Here is a gist explaining this issue:

https://gist.github.com/tinder-garricnahapetian/1e063a42c3fc94f60b5fe2e2a3e9d935

@itaiferber
Copy link
Contributor

The underlying issue here is that when you have a let property with a default value, we can’t assign to it on init(from🙂, and we don’t warn because there’s no indication that this isn’t what the developer intended.

I’ll try to elaborate on this further when I have a moment.

@belkadan
Copy link
Contributor

belkadan commented Jul 2, 2018

Right, the default init(from:) isn't allowed to do anything a manually-written one can't do, and the rules today say that property initial values are always used when present.

@itaiferber
Copy link
Contributor

To fill in more information here — Codable generates code by manipulating the AST in the compiler, and as such cannot write code for you that you can't write yourself. That means that the rules applying to it are the same rules that apply to you.

When you have a let property with a default value, you cannot override the value in any initializer:

struct Foo {
    let a = 5
    init() { a = 10 } // error: immutable value 'self.a' may only be initialized once
}

It is assigned a value before init is called, and cannot be reset later.

In the context of Codable, this means that the generated init(from🙂 cannot assign to any let properties which have a default value:

struct Foo : Decodable {
    let a = 5
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        a = try container.decode(Int.self, forKey: .a) // error: immutable value 'self.a' may only be initialized once
    }
}

Decodable synthesis doesn't assign to such properties because it can't. What is surprising here, though, is that this happens silently, which means that you might not realize that on every decode, you get the default value, rather than what's been encoded. This is doubly surprising because on encode, the property is still encoded by default, so it might look like it would be decoded, but really isn't.


What needs to improve here is the experience of discovering this:

  • If a type is Decodable and has such a property, we might need to issue a warning that explains that the property won't be decoded, and the way to silence the warning might be to provide CodingKeys which leaves that property out.

  • If a type is Encodable only and has such a property, I don't think a warning is necessary — we'll encode the value unless you leave it out of the CodingKeys

  • If a type is Codable, though, we run into a bit of trouble. To suppress the Decodable warning, you'd need to leave the value out of the CodingKeys, but this means the value isn't encoded either. There wouldn't be any way to get the behavior you already do today without either having to deal with the ever-present warning, or by overriding either encode(to🙂 or init(from🙂, which is similarly bad

We'd need to figure out how common this already-existing overlapping case is, and what the expected behavior might be.

@itaiferber
Copy link
Contributor

@swift-ci Create

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Codable Area → standard library: `Codable` and co. compiler The Swift compiler in itself improvement
Projects
None yet
Development

No branches or pull requests

3 participants