Replies: 7 comments 12 replies
-
Hi @hedukas, thank you for your thoughtful suggestion! Personally, I'm torn. I seldomly use
@MemberwiseInit(.public)
public struct ViewModel {
public let title: String
public let subtitle: String?
} I think making members public is a better practice in general, and I'd almost always recommend it over
Like Swift itself, I've made Another concern is that this feature may be hard to get right. There would be several usage interactions that need to be carefully considered. A couple come to mind:
|
Beta Was this translation helpful? Give feedback.
-
Hi! Thanks for the reply and sorry it took so long to get back. Value semantics For context in our codebase we have a lot of frameworks. Sometimes we need to pass just the type, sometimes we need to initialise it, but we have taken the YAGNI approach. We’ll only make something public when it becomes unnecessary. For example we have 1500 public structs (about 5000 in total) in our project out of which over 300 have private properties which could all potentially benefit from this macro and even more if we start counting classes as well. It’s a very common pattern (at least for us). For a viewmodel yes it makes more sense to keep the members at the same level as the struct, but if we want to use it on more (for example in all viper stack components), then I can’t see the macro being useful without a flag such as this. Or is this much larger of a scope than this macro is made for? Conflicting macros
I see where you’re coming from and I indeed did not consider this before. If they were allowed to be used at the same time it could create a lot of confusion. This is where I think errors and diagnostic could help with. It could show an error that either the This would apply to all the different access levels this macro could have.
This flag I think should be respected when the Because of this I think it wouldn’t be too hard to assume how this ignore flag cooperates with |
Beta Was this translation helpful? Give feedback.
-
I was about to create a thread to make the same proposal. My app is split in multiple SPM packages to improve compilation times. I have structs that I use as "input" of the code in the packages, that the main app instantiates and gives when calling a function, but never reads any fields from. So the init is exposed and public but all fields are internal and unused by the importers of the package. This is the intended design of my packages API. Right now I put all fields in Maybe instead of a |
Beta Was this translation helpful? Give feedback.
-
How about adding a special
Example: @UnsafeMemberwiseInit(.public)
public struct ViewModel {
private let title: String
private let subtitle: String?
// Macro generates init:
public init(title: String, subtitle: String?) {
self.title = title
self.subtitle = title
}
} Implementation-wise, this still needs careful consideration of edge cases and potential conflicts with other @nathansalaun-sofia @hedukas Thoughts? |
Beta Was this translation helpful? Give feedback.
-
While I like the idea of a separate macro for this I don’t really agree that it is unsafe. And accidentally exposing something would be caught by building the app very fast? I don't think these would make it to code you ship? And just by looking at it I think people would get confused by what exactly is unsafe. In addition I think it will create more friction when writing code. If I had a type that used this unsafe annotation and I update the type to not have private properties anymore then I’d also need to change the annotation (and know I need to change it). Though you could argue that the same applies if it had an property attached. I also don’t think this is a behaviour we want to discourage. If we were to advocate for everything to be made the same access level as the type then we’d be exposing so much more to the entire codebase than what is necessary. In the codebase I’m working on we’re rather encourage encapsulation. |
Beta Was this translation helpful? Give feedback.
-
@hedukas @nathansalaun-sofia Thank you for your valuable input and discussion on this issue. Based on our conversation, I've implemented Key points:
I encourage you to try out this new macro and provide feedback on its usage. Your experiences will help us refine the feature and decide on its future stable implementation. |
Beta Was this translation helpful? Give feedback.
-
@gohanlon the new macro works great for me so far, thanks! What do you mean by |
Beta Was this translation helpful? Give feedback.
-
In my instance there are a lot of types in the codebase that have private properties which are then exposed through the init. And also sometimes a mixture of private and internal and public variables. (Example below)
I would love to use the macro for this, but it means that the usage looks like this
While it’s not too much trouble for such a small type, the more variables you have the more annoying it gets. At that point it seems easier (and less cluttered) to just write the initialiser yourself.
So I’m proposing adding a parameter to the macro that would allow you to specify what kind of access level variables should be included in the initialiser. So the usage could look like this:
This could make the macro even easier to use across different types. If this is acceptable, I’m happy to contribute the change.
Beta Was this translation helpful? Give feedback.
All reactions