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
Could you add advanced/experimental option to ignore default initializer ( and to enable Memberwise Initializers )? #938
Comments
Are you seeing issues with Swift 5.1? If so, what? The checks in the code for older swift versions are harmless, they will compile away. It keeps thing simpler to generate the support for our documented support tool range instead of making all those things conditional at generation time. |
@thomasvl Fast, thanks! First of all, generated files don't use Swift .init() syntax everywhere. It would be nice to have this option. var page: MyPage {
get {
if case .page(let v)? = _storage._content {return v}
return MyPage() // .init() <- more readable.
}
} Next, it would be nice to have structs with auto-generated memberwise initializers: // Proto file.
struct MyPage {
var id: String = String() // .init() more readable.
init()
} My options are protoc -I ./ --swift_opt=FileNaming=DropPath --swift_opt=Visibility=Internal --swift_out=./protobuf Yes, I know, that As I remember, memberwise initializers have new "outfit/behavior" in Swift 5.1, right? When I try to // Generate data.
class Create {
func page() -> MyPage {
.init() // no memberwise initializers are available.
}
} |
Ah, I see. swift-protobuf/Sources/protoc-gen-swift/MessageGenerator.swift Lines 156 to 161 in 1f798cf
Could you add option to ignore default initializer? Yes, it is undocumented, but, let's assume this functionality is only for advanced users. If anything goes wrong, it is only their problem. |
@thomasvl |
It's debatable whether using the implicit member reference notation for initializers is more readable than using the more common explicit type name form. But more importantly, why are you that concerned about minor syntactic details of the implementation of generated code? The important details are in the API, not in the implementation. There's no benefit to supporting maintaining multiple options and code paths that allow users to change the syntax of generated code but with no semantic difference. Regarding memberwise initializers, there's more discussion about why they aren't supported here: #86 |
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {/*...*/} All of these questions have one answer - because you care about person who opens |
None of those cases are analogous. You've chosen to ignore the word "minor" in the phrase "minor syntactic details". It's very important that the user be able to read the API of the generated messages so that they understand how to use them. Writing all the code on one line, not using indentation, or not choosing sane names for parameters would make that more difficult. On the other hand, the choice of explicit |
Re the initializers – proto file authors are free reorder/insert fields without an impact on the wire. If we start generating or allowing generation of initializers that latch on to the order, then it effectively becomes a place a non breaking .proto file change could break a users swift code. And I wouldn't call initializers "advanced" as after all Swift recent went out of the way to try a generate these in more simple cases. This breaking pattern is what went into the decision to do with |
What I see: struct Error {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var code: Error.Code = .null // First style
var description_p: String = String() // Second style
var unknownFields = SwiftProtobuf.UnknownStorage() // Third style
} // clumsy, but now it has one style and I see all variables.
var code = Error.Code.null
var description_p = String()
var unknownFields = SwiftProtobuf.UnknownStorage() // hm, variables and their types and don't care about their `init` except enum.
var code: Error.Code = .null
var description_p: String = .init()
var unknownFields: SwiftProtobuf.UnknownStorage = .init() In last example you see pair on left ( variable and type ) and something on right. If statements on right are the same, you just skip them and focus on left part. @thomasvl Even this may help ( all fields except // it can be convenience, of course.
extension Error {
init(code: Error.Code, description_p: String) {/*...*/}
} |
Your convenience case is what would break if a new field got added to the message and it suddenly inserted an arg inbetween As far as your what I see case, that is one possible generation, depending on the message, it might generate using storage (in part for memory or because it has to because the message has a field of its own type). |
After running script |
Not sure what At the moment, this library has the goal of never breaking existing code on a regeneration if the proto files have also made no breaking changes. Protocol buffers defines the addition of a new field as non breaking as a server would still have to work for old clients that don't know about the field either. |
@thomasvl |
I support the idea of having initializers that take all fields expect for the unknownFields property. If I add/remove a field, I get a compile time error instead of unexpected values server side. I now do everything with the |
Again, adding a field is defined as non breaking from protobuf pov.
This will never happen. Protobuf has defined behaviors around default values and for proto2 syntax the there is also the has properties to check if things are set. It is all part of the spec so there are no unexpected things. |
@Jasperav |
@lolgear not sure why I can not add an issue to the repo, but I get an error running this command:
error:
I placed image_identifier.pb.swift in the root directory of the project itself |
@thomasvl I understand that adding a field should be nonbreaking, in the sense of the api should still work if users are using an older version. IMO implementing the api should/can act differently. I don't see a reason why I should not get a compile time error in Swift when I add a new field in Protobuf, because why would I add that field anyway? Adding a new field in protobuf always results in me changing Swift code because I want to use that field. But I am sure this discussion has already been debated. |
@Jasperav I think you might be focused a little specifically on your exact use case of protobuf. If protos are used to define a the data models for taking to a server, that service might add some new fields as at some point, but that doesn't mean all clients need to use those fields. For example, say a proto is used to define some server for hosting/syncing a users' contacts. It starts with an initial set of fields (first, middle, last, title, emails, phone numbers, ...); but say a year later they add some more fields (nickname, family members, etc.). A client is going to be creating these message for new contacts their users create, they do not need to set all these new fields because they might never show the data for their specific usage. Forcing that client that happens to talk to this service to update because the service supported some more fields doesn't really make sense, and worse, a developer might start passing dummy values that then get persisted as if the user set them. Now in your case, you might be the sole consumer of your protos from a client/server pov, and in those cases, your specific needs might include that your clients also have to start adding what ever your new fields are; but from a generic pov, in all the ways protos can be used, and especially where one team/company/etc. might publish protos for any client to use, nothing says all those fields are needed by everyone. |
Hi!
Could you add support for swift 5.1?
By the way, how could I disable all checks for swift 4.2 in generated proto files?
I would like to have only latest swift version in generated proto files.
Thanks!
The text was updated successfully, but these errors were encountered: