For data that needs to be serialized I often write code like this:
public struct MyType: Codable, Sendable {
public var id: UUID
public var createdAt: Date
public var title: String
public var description: String
public var items: [Int]
public init(
id: UUID,
createdAt: Date,
title: String,
description: String,
items: [Int]
) {
self.id = id
self.createdAt = createdAt
self.title = title
self.description = description
self.items = items
}
}
These types must often be public because they are part of a package or another target. There are two redundancies that are quite annoying:
public must be repeated for each property.
The initializer repeats each field type once, and each field name three times.
What do you think of re-using the open keyword for structs to simplify this? The rules would be:
All stored properties are automatically public, visibility modifiers are not allowed for stored properties
The memberwise initializer is always available and public
The example would look like this then:
open struct MyType: Codable, Sendable {
var id: UUID
var createdAt: Date
var title: String
var description: String
var items: [Int]
}
Not sure about overloading the open keyword, but empathic to the general idea.
Also, I often find myself creating structs with a standard set of base members, such as id, createdAt, updatedAt, createdBy or similar. It would be nice to have a light-weight syntax for creating structs that just "extends" another. Or perhaps a kind of "template" struct? Idk.
You can handle all of this using macros, without the need to introduce keywords ambiguity. You can write your own (for this cases it is pretty simple to implement) or use some ready solution that covers the need. You will still have to repeat public, but that's universal for Swift - type members does not inherit its visibility implicitly.
Maybe you can create a @DTO macro to decorate your struct, and maybe the macro could even have an optional set of "standard" vars be auto-generated.Your macro could synthesize inits, Codable etc.
You can mitigate that by using precompiled binary once you sure macros does what you need. This is something you are not expecting to change a lot anyway
Not sure, since I have tried only early versions and it has changed since then, but you can try and find out fairly quickly. I maybe will give it a try as well, that is an interesting case
I think you can achieve that with additional type:
@DTO
public struct MyType {
private struct Blueprint {
var id: UUID
var createdAt: Date
var title: String
var description: String
var items: [Int]
}
}
so the macro will expand (roughly) like the following:
public struct MyType: Codable, Sendable {
private struct Blueprint {
var id: UUID
var createdAt: Date
var title: String
var description: String
var items: [Int]
}
public var id: UUID
public var createdAt: Date
public var title: String
public var description: String
public var items: [Int]
public init(
id: UUID,
createdAt: Date,
title: String,
description: String,
items: [Int]
) {
self.id = id
self.createdAt = createdAt
self.title = title
self.description = description
self.items = items
}
}
So you actually generate you public struct with the bluepring/spec of desired fields.
Compiler synthesized memberwise initialisers are internal to avoid accidentally publicising the ability to create the struct outside the module. This is a safety mechanism so you have to opt in to being able to publicly construct the type, which is a capability you may not want to expose.
And this has been the subject of various past discussions, around how to better handle this (e.g. the ability to say public init = default to get a publicly-available synthesised). I don't recall a formal proposal ever being tendered, though.
Well, with macros the public init synthesis macro can become a part of stdlib in that case. It shouldn't be working on declaring properties public, though, I believe.