Shorthand init

When initializing a data structure (struct & class) with named fields, allow writing propertyName as a shorthand for self.propertyName = propertyName . This allows a compact syntax for initialization, with less duplication.

Example:

struct Point {
	let x: Int
	let y: Int

	init(x: Int, y: Int) {
		self.x = x
		self.y = y
	}
}

For now we can't write .init() like this:

struct Point {
	let x: Int
	let y: Int

	init(x: Int, y: Int) {
		x; y
	}

	init(x: Int, y: Int) {
		x
		y
	}
}

Because the parameter names and the struct field names are exactly the same.

What does the community think?

1 Like

Are you writing an 'init' there because you need to make it 'public'? I'd rather leave it out entirely, and have Swift generate it.

It would also be handy if Swift let me specify its generated init not use labels, but consider the order I declare them in. Ie:

struct Point {
   let _ x: Int
   let _ y: Int
}

let pt = Point( 123, 456 )

If the init is that simple, it can be omitted. If you need a different access level, you should try and revive the pitch from a while back to allow synthesized init with access levels other than internal.

If that syntax would be interspersed with other logic, I'm a huge no way. That syntax is already legal, though you'll get a warning for an unused value. Giving it a brand new meaning inside of init would be terribly confusing. There's also no indication that assignment is being done.

5 Likes

If there was a shorthand syntax I would prefer it to be even shorter:

struct Point {
	let x: Int
	let y: Int

	init(self.x: Int, self.y: Int) {}
}
2 Likes

Such a shorthand already exists:

struct Point {
	let x: Int
	let y: Int
}
1 Like

Yes, but you cannot mix it with non-autoassigned parameters. Also doesn‘t work with classes and you cannot run code after the assignments in the init method (I think).

Your shorthand has no code. Are you suggesting that parameters would be automatically assigned to properties of the same name?

Yes, sorry, didn‘t make that clear. Extended example:

class Point {
    let x: Int
    let y: Int
    let z: Int

    init(self.x: Int, self.y: Int) {
        z = x * y
    }
}

The self. prefix would mean „assign to property with same name“.

6 Likes

I think the justification from writability (how annoying it is to type all this stuff out manually) is very weak, because it's likely that you only have to do this once, when first declaring the struct. For a developer, some days are just more boring than others. :slight_smile:

A justification from readability might carry more weight (because the code is likely to be read a lot more often it's written), but in this case I think readability suffers, because the proposed syntax is so contextual. Bulky though it is, you can't say that this sort of thing isn't crystal clear:

	init(x: Int, y: Int) {
		self.x = x
		self.y = y
	}

However, I think a better solution is to make this a behavior of Xcode and IDEs, where they would retrieve the synthesized text (of an omitted initialization) from the compiler, and use that to provide fixits for properties that were not initialized before the end of the init. This would be roughly similar to the IDE adding stubs for missing protocol conformances.

That approach would also tie into a larger discussion about "instantiating" synthesized code in general. There are a few places we'd like this, including Codable conformance, to take a very obvious example.

One thing to consider is that it's not only a tax on writing, but also on renaming properties. So a result of this redundancy is that properties may be named less optimal (on average) than they would be if renaming them was less work.

It's crystal clear unless you accidentally wrote

init(x: Int, y: Int) {
    self.x = y
    self.y = x
}

@lassejansen's proposal makes that kind of error impossible.

5 Likes