SE-0347: Type inference from default expressions

Hello Swift community,

The review of SE-0347 "Type inference from default expressions" begins now and runs through April 5, 2022.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager. When emailing the review manager directly, please keep the proposal link at the top of the message.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

Doug Gregor
Review Manager

25 Likes

The toolchain link appears to be 404ing.

  • What is your evaluation of the proposal?

+1

  • Is the problem being addressed significant enough to warrant a change to Swift?

Absolutely. Defining defaults for generics arguments requires boilerplatey overloads the grow with each generic argument. We can already see this in an explosion of overloads in SwiftUI, and a few libraries I work on would also benefit immensely from the feature.

This kind of boilerplate is annoying for users and a pain to maintain. It adds surfaces area to a project where things can go wrong if the overloads aren't kept "in sync" in some way, which not only includes duplicate and extraneous code, but also the duplication and synchronization of documentation.

  • Does this proposal fit well with the feel and direction of Swift?

Yup! The general direction appears to be making generics friendlier and easier to use.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

N/A

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I read and participated in the pitch, and looked into how it might theoretically improve a couple code bases. I'll also try the toolchain out whenever it's available.

6 Likes

You could use a trunk toolchain from Swift.org - Download Swift.

This feature is also implemented in nightly-main build and it can be easily tested in https://swiftfiddle.com/ adding the Compile Options -Xfrontend -enable-experimental-type-inference-from-defaults

2 Likes

I continue to think that the "Introduction" section is extremely difficult to parse. However, having read the remainder of the proposal as it now stands, I feel I have a pretty good grasp of what's going on and appreciate the effort made to explain the feature.

I think that the functionality being proposed is a sensible one. In short, it improves the expressivity of the language without introducing new syntax, with very much a "do what I mean" flavor. The limitation to a single parameter in order to avoid user astonishment is well justified and, I think, wise without substantially limiting the usefulness of what's proposed.

The proposal fits well with the feel and direction of Swift, and particularly is a nice complement to other ongoing work to make generics more ergonomic and to discourage unnecessary use of existential boxing. I don't have a good sense off the top of my head as to how this compares with other languages. I read the initial pitch and this version carefully, and participated in the discussions.

5 Likes

I believe the problem is significant enough to warrant the change and the solution seems simple and right, but I’m a bit concerned how would this affect possible future support of default generic parameters. Consider the following scenario:

struct Box<F: Flags = FooFlags> {
  init(flags: F = DefaultFlags()) {
    ...
  }
}

Would there be a problem with this, or there is a straightforward solution?

You can define multiple initializers with different defaults, so I imagine there's no conflict here.

Yes, that is the idea, if there are default value expression it would be used to infer the type of F so the default type of generic parameter is not really applicable in this case, but another overload could be added to provide a default value of FooFlags.

Though I understand the motivation and the proposed solution and many people agree that this feature is quite reasonable, I feel the syntax very strange. At this point I cannot precisely explain why it seems strange, but I'd like to share my feeling to this.

To me, flags: F = DefaultFlags() is an expression which means 'the author of init decides type of F and provides default value'. I can accept that with the call of init the type parameter is specified.
However, since it has been impossible in normal condition to overwrite decided type, when a type of F is already decided, I won't consider I can pass AnotherFlags() for flags.
Though the expression has been used for default value declaration ever, now the expression is also a default type parameter declaration. This semantic overload makes me really confused.

struct Box<F: Flags> {
  init(flags: F = DefaultFlags()) {}
}

Especially, it seems very strange to me when the feature is used with some P syntax. I cannot even consider that I can pass a collection like [String: Bool] for initialValues while the default value is apparently [Int].

func compute(initialValues: some Collection = [0, 1, 2, 3])

I don't know how universal my confusion is, but if so many people get this confusion I think this feature needs to be revised.

2 Likes

Might be out of scope, but the "Type inference from default expressions" wording may be appropriate to the following case as well:

func foo(x = 1, y = 2.0, z = true, w = "hello") { ... }

I'm going to add an example to the introduction section to show a sample use of feature which should help to clarify what is being proposed.

Thanks, everyone, the Core Team has discussed this proposal and has decided to accept.

The author will work on the introduction section so this proposal is easier to understand for future readers, thank you for pointing this out.

Doug

1 Like

The change to the introduction has been made via https://github.com/apple/swift-evolution/pull/1611

4 Likes