Initializer sugar

Has there been any discussion about using let and var as sugar in initializers?

// verbose: each parameter is mentioned FOUR times
class User {
    let name: String
    var points: Int
    init(name: String, points: Int = 0) {
        self.name = name
        self.points = points
    }
}
// sugary sweet: each parameter is mentioned once.
class User {
    init(let name: String, var points: Int = 0) { }
}

p.s. I tried posting in Evolution, but button was greyed out.

Um, you *did* post this in Evolution. You posted it in Evolution/Discussion, which is the proper place for it.

1 Like

This syntax is convenient, but it raises some questions if there are multiple initializers. What would you imagine the behavior would be in that case?

1 Like

@bjhomer a very good point! As multiple initialisers are quite rare, I would suggest that only a single initialiser would be allowed with this syntax, perhaps with an error "Multiple initialisers disallow the use of 'let' and 'var' within an initialiser".

As a refinement perhaps the error "All initialisers require same 'let' and 'var' parameters", allowing multiple initialisers containing the same set of 'let' and 'var' arguments. But, for 99 of 100 cases, this would not be relevant.

I’d like to auto generate initializers by compiler for any given class similar to struct but with public.

I don't think moving instance variables from the type they belong in somewhere else, such as the initializer parameter list, is a good idea.

That said, I think there is something here. Similar to C++ initializer lists, we could maybe allow something like this:

class User {
    let name: String
    var points: Int
    init(name self.name: String, points self.points: Int = 0) {}
}

Or maybe even

init(self.name: String, self.points: Int = 0) {}

as shorthand for the same as above, although I'm not so sure about this one.

6 Likes

There's been a lot of discussion about this already. With a formal proposal that was deferred with the following rationale. There's also the evolution discussion about it and the formal review.

Best to at least read the proposal and the subsequent rationale to continue with the discussion as there were plenty of insightful ideas discussed.

2 Likes

@ahti very interesting, though I assume in your shorthand case

init(let self.name: String, var self.points: Int = 0) {}

would be necessary

@Letan I was looking for that! cheers. I'll give it a read. A summary would be great for readers of this thread though. Thanks again.

When Kotlin was introduced, its initializer concept was one of the coolest features for me; basically, you would write the (single) designated initializer like

class Person(firstname: String, lastname: String) {}

Imho this topic is one of the weakest points of Swift — but a simple yet powerful init model like Kotlins most likely isn't possible for Swift without a huge break in compatibility.
The suggested addition would definitely be convenient, but it would make Swift even more complex :frowning:

1 Like

@Letan from my quick scan of the prior material, none suggest this syntax. None are quite as terse. This suggestion does not need to introduce a memberwise keyword. It's sugar, pure and simple, and would be rejected in the 1 of 100 cases that it would introduce ambiguity.

@Tino this syntax doesn't handle let vs var bindings and doesn't deal with defaults, and multiple initializers. It's not swifty. I prefer the suggested syntax.

Kotlins syntax can do all this and more — but I didn't actually propose it, because I wouldn't consider either spelling a good fit for Swift.

1 Like

@Tino Kotlin seems super cool :sunglasses:

I think they stole most of it, too ;-)

1 Like

@Tino My Life as a Tech Transfer Monad by Erik Meijer is testament to the art of theft. Meijer and Picasso :)

1 Like

The prior discussions are to try and help lead the newer discussion into what might be good ideas and try to help avoid bad ideas. The previous discussions are also there for inspiration.

Your proposal and the deferred proposal are also similar enough that I imagine only one will ever make it into the language. This would then mean your proposal must be better than the already deferred proposal and any of the other proposed solutions mentioned in the rationale.

Simply being terse isn't a goal on its own in Swift. In fact, proposing "pure sugar" requires strong justification. As is stated in the meta-points of rationale linked to above.

Even so I think this idea mentioned in the rationale is terser.

1 Like

@Letan surely David Owen's syntax requires TWO mentions of each parameter, and additional self annotations.

Simply being terse isn't a goal on its own in Swift. Agreed. Terse expression often requires context to avoid ambiguity. But multiple mentions of obvious intent is redundancy.

I certainly haven't thought through all the implications, but so far, I feel the suggestion still deserves a broader critique.

con) the self.x syntax is weird and surely can be improved, but anything we came up with would be magic and weird.
con) doesn’t address the problems of replacing the var/let initial values (zapping a side effect in either of them, and breaking ‘let’ axioms).

Does the proposed syntax suffer either of these cons?

thanks to the wonderful Swift community for such a quick and lively response to this suggestion!

Kotlin and Scala allow the equivalent of class User(let name: String, var points: Int) { ... } and then allow the equivalent of extra convenience initialisers. This is well liked in these communities and extensively used, there is no reason why they wouldn’t be popular in Swift.

However in the past Chris Lattner has said he is not in favour and maybe others in the core team don’t like the idea also.

2 Likes