Hi community, I would like to propose a new feature in Swift.
Synthesize init of structs
Introduction
The feature adds an automatic and controlled way of generating struct
s' initializers.
Motivation
Very often our applications are divided into different layers which are implemented as modules/packages, in that situation Swift's implicit initializers for struct
s are useless because of the default access level which forbids initialization of instances from other modules if the initializers are not marked as public
. We can use an IDE (most often Xcode) to generate the initializers but the problem is that if we wanted to add another field, we would have to use the IDE to generate the initializer again, then reformat it, copy our implementation, and so on.
Proposed solution
A new keyword known from Objective-C: synthesize
. The construction would look like this
public struct SearchParams {
// some fields...
public synthesize init // đ
}
Detailed design
The keyword would be able to receive a parameter that describes the lowest access level of fields which would be included in the initializer, the default level would be public
, for example
public struct SearchParams {
public let apiToken: String
public let sortOrder: SortingOrder?
public let page: Int
internal var resultsPerPage: Int?
internal var startDate: Date?
private var endDate: Date?
private var queryPhrase: String?
public synthesize init
}
would be equivalent to
public struct SearchParams {
public let apiToken: String
public let sortOrder: SortingOrder?
public let page: Int
internal var resultsPerPage: Int?
internal var startDate: Date?
private var endDate: Date?
private var queryPhrase: String?
public init(apiToken: String,
sortOrder: SortingOrder?,
page: Int)
{
self.apiToken = apiToken
self.sortOrder = sortOrder
self.page = page
}
}
In order to include all the fields in the initializer there would be an ability to specify the lowest access level, for example
public struct SearchParams {
public let apiToken: String
public let sortOrder: SortingOrder?
public let page: Int
internal var resultsPerPage: Int?
internal var startDate: Date?
private var endDate: Date?
private var queryPhrase: String?
public synthesize(private) init
}
that means all the fields with an access level of at least the one specified in synthesize
would be in the initializer, so the code above would behave as
public struct SearchParams {
public let apiToken: String
public let sortOrder: SortingOrder?
public let page: Int
internal var resultsPerPage: Int?
internal var startDate: Date?
private var endDate: Date?
private var queryPhrase: String?
public init(apiToken: String,
sortOrder: SortingOrder?,
page: Int,
resultsPerPage: Int?,
startDate: Date?,
endDate: Date?,
queryPhrase: String?)
{
self.apiToken = apiToken
self.sortOrder = sortOrder
self.page = page
self.resultsPerPage = resultsPerPage
self.startDate = startDate
self.endDate = endDate
self.queryPhrase = queryPhrase
}
}
The examples above imply that this code should generate a compilation error "redeclaration of init"
public struct SearchParams {
public let apiToken: String
public let sortOrder: SortingOrder?
public let page: Int
internal var resultsPerPage: Int?
internal var startDate: Date?
private var endDate: Date?
private var queryPhrase: String?
public synthesize init
public init(apiToken: String,
sortOrder: SortingOrder?,
page: Int)
{
self.apiToken = apiToken
self.sortOrder = sortOrder
self.page = page
}
}
Source compatibility
The solution should not influence the existing code, it is rather the facilitation of existing mechanisms.
ABI compatibility
The change does not have an impact on ABI compatibility.
The compiled code should be similar to a manual use of init
, as it works currently.
Alternatives considered
Built-in functions in IDEs or scripts, but these solutions require manual work and the need of repeating it every time when the dependent code changes. The tools generate real code, which sometimes can count many lines, but it does nothing more than just expose the initializer to other packages outside. The proposed solution is nicer and would be a part of the language.