[swift-evolution] [Proposal Draft] Flexible memberwise initialization

Tino Heth 2th at gmx.de
Sun Jan 3 08:58:24 CST 2016


> What are those advantages precisely?  
subjective: Easier to understand
objective: Saves keywords/syntax ("…", "memberwise", "@nomemberwise", "required", "convenience", "@default"…)

>> What I can see in your example is that the proposed syntax allows me to trigger compiler errors that will never happen with Kotlin (and errors that cannot happen are the ones I like the most).
> 
> Can you point out what potential compiler errors you are concerned about?  Are you referring to the access control example where the compiler does not synthesize initialization of a private member in an internal memberwise initializer and thus requires manual initialization of the private member?
Exactly.

>> public class Customer(title: String, private var birthday: NSDate?, public address: String = "n/a"): Person {
>> 
>> 	protected let statusPoints = - birthday?.timeIntervalSinceNow() ?? 0.0
>> 
>> 	let constantWithHardToExpressValue: Int
>> 
>> 	lazy var age: Int = dateCalculationIsHard(birthday)
>> 
>> 	init {
>> 		constantWithHardToExpressValue = Int(statusPoints) + 1
>> 		super.init(title: title)
>> 	}
>> 	
>> 	public init(titlePrefix: String, titleSuffixObject: Any) {
>> 		init(title: titlePrefix + titleSuffixObject.description, birthday: NSDate())
>> 	}
>> }
>> 
>> So: Dear reader, please do my job and explain the "pseudo"-source above ;-) — or ask questions if you are just puzzled by it.
> 
> This must be what you are suggesting for Swift because the example uses NSDate?
Yes indeed — I'm quite sure Kotlin couldn't compile that ;-).

> Is it correct that this class would have the following members in addition to the ones declared in the body?
Yes (but see below)

> You used access control modifiers in that parameter list.  Would you allow any annotations that are valid for properties that can be initialized (i.e. not lazy, but maybe an observable behavior if Property Behaviors are accepted)?


> let title: String // internal
> private var birthday: NSDate?
> public let address: String = “n/a”
> 
> It actually looks like you pass `title` to super so maybe that isn’t expected to synthesize a member?
Yes

> If that is the case how does the compiler determine which parameters should receive member synthesis?
It could be inferred, but actually I'd prefer explicit rules (those could be "let x: Int" -> constant, "var…" variable, "x: Int" nothing is synthesized, the parameter is used for the parent initializer or to compute the value of a member that isn't visible)

> If not, I assume super would not have a `title` member and is doing something else with that argument.  Is that what you intend?
Yes

> Is it also correct that all of the following forms would be valid at call sites?
> 
> Customer(title: “a title”, birthday: nil)
> Customer(title: “a title”, birthday: nil, address: “an address”)
> Customer(titlePrefix: “a prefix”, titleSuffixObject: Foo())
Yes

> If so, does the initializer used in the first two call examples (the designated / memberwise initializer?) receive the same access control as the type itself since it cannot be specified directly?
Yes and no:
Kotlin allows you to limit the visibility of the initializer:
class Customer private init(...

> Is it also correct that the init block that calls super would be invoked regardless of which initializer form is used?  When would this block run?     Immediately after the memberwise initializer is called?  Is it the “body” of the memberwise initializer?
Yes, that is the idea

> It would need to run prior to any use of self in the body of `public init(titlePrefix: String, titleSuffixObject: Any)` in order to follow Swift's rules of definitive initialization.  
True, the same as it is now

> Is the `public init(titlePrefix: String, titleSuffixObject: Any)` initializer actually a convenience initializer?
Yes

> Is it required to call the designated / memberwise initializer before it does anything else?  What rules need to be followed to ensure definitive initialization happens?  Is this rule applicable to all additional initializers the author writes?  If it is a convenience initializer maybe it just follows the current rules for those in Swift?
Yes, everything in this hypothetic model behaves like it does now

> Maybe the memberwise parameters plus the body is the single and only designated initializer for the type?  Is that what you’re suggesting?
It would be possible to allow additional designated initializers, but imho this should at least be discouraged.

> What if the init body needs additional non-memberwise parameters?  Is it allowed to specify those?
Yes

> If so how is that accomplished?
See above ("which parameters receive member synthesis")

> How is the parameter ordering in the final parameter list determined?
Like in a regular function call.

> Would you use the `…` placeholder for the memberwise parameters like the current proposal does?
No, no need for the dots

> What happens if another initializer wants to initialize `constantWithHardToExpressValue` to a value different than that in the factored out init block?  
You would have to include the member in the parameter list instead of the class body

> What if the type needs to support more than one designated initializer?  Is that possible?
Yes (see above)

> Would all designated initializers be required to receive the same set of memberwise parameters?  If that isn’t what is required how would the author implement the necessary initializers?
That would be complicated, and is one reason for discouraging multiple designated initializers (the other reason is the hassle when subclassing)

> You are suggesting a design we should use for a feature in Swift.  I don’t think it is unreasonable to ask how that design would address specific use cases in Swift.  It is not enough to point at another language with a similar feature.  It is also not enough to just assume the Kotlin model is acceptable without being able to answer how it works in specific use cases.
I didn't create a real competing proposal — I just pointed out to an existing solution that addresses the problems successfully.
It's hard to define how a hypothetic feature will interact with other hypothetic features...

> I am taking a nontrivial amount of time to work through this with you and am keeping an open mind during that discussion, but it will require specific details to change my mind.
I really don't expect to convince you to discard your results — our standpoints and opinions are just very different (in other questions even more than in this one…), and consensus is very unlikely.
As said before, I have much respect for the labour associated with a proposal, and I hope you see my objections not only as an annoyance, but rather as a opportunity to sharpen your arguments.
(I personally prefer sound opposition over apathy most of the time).

> There a lot of details to work through here.  If we are do that we would could analyze the differences of the two approaches.  I think that is a fair request.  There are definitely some significant differences between them.  I will hold off on commenting further until we nail down exactly what it is you would like to see and how it would work.
> I am trying to solve a problem for Swift.  I am willing to continue working through the Kotlin approach with you so we can understand the details of how it would fit in with Swift.  That will allow a fair comparison of the differences between the approaches.
> I want to see the problems solved in the best way possible.  That is why I am investing time in the proposals and also why I am investing time in exploring the alternative you believe is better.  If there is a better approach or a way to improve my proposal I would prefer to identify that now rather than have it accepted as-is.
> I was trying to show that the two features are not strictly mutually exclusive as one can be expressed in terms of the other.  If you don’t like that approach and think it makes the language too complex I understand that position.  I am definitely not trying to just silence you.  
> 
> Let’s work together to understand in detail the differences in these approaches and their respective advantages and disadvantages.  The first step in doing that is getting the design of what you would like to see nailed down further.
Relax - no one else seems to care, so apparently I'm just a single lunatic without any support and a ticking end-of-holydays countdown (serious work won't leave much time for fighting lost battles ;-)
So taking a neutral standpoint, the best advice I could give is to basically ignore myself (taking back my own standpoint as a friend of clear words, I'd appreciate a non-implicit reaction ;-)
I still think initialization is already a heavy topic that shouldn't get even more complicated and probably won't change my mind — but I can get my head around anything that has been brought up, and considering the community reaction, the majority will do so at least as well (and those who don't follow the discussion on the list simply will have to deal the results, as it has been before).

Best regards,
Tino
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160103/979e671d/attachment.html>


More information about the swift-evolution mailing list