SE-0255: Implicit Returns from Single-Expression Functions

(Steven Van Impe) #103

A very passionate -1.

No. I do not believe this proposal addresses any problems. In fact, I believe it causes harm.

This proposal assumes an implicit return is somehow "better" or more clear than an explicit one, yet it does not provide any evidence to back this. From my own experience, as someone who teaches programming for a living, unnecessary sugar makes programming languages harder to use and understand. In particular, I would like to speak out for my many, many students who fall into one or more of the following categories:

  • chose to study computer science because it seemed like an interesting profession with lots of job opportunities, but don't consider themselves "a geek",
  • have some form of autism (as a trait, not a disorder),
  • have a very mathematical, analytical mind.

These students tend to appreciate explicitness. Whenever they encounter sugar, they tend to remove the sugar in their mind so they can better understand what's going on. This means unnecessary sugar increases the cognitive load of reading code, which is the opposite of adding clarity.

Just to give you an example, here's the cognitive load required to process the motivating example in the proposal:

func sum() -> Element {
    reduce(0, +)
}
  1. "OK. So this function calls some other function named reduce."
  2. (student recalls the design guidelines) "This reduce function is named using an imperative verb, so it does something and has side effects." (student now assumes sum simply calls reduce)
  3. "Oh wait, there's a return type." (easy to miss as it's and the end of the line)
  4. "So what does this function return?"
  5. "Oh right, there's this exception where return can be omitted if it's only a single line of code. This must be one of those cases."
  6. (student looks up reduce) "Ah, reduce does return something instead of having side effects. Weird, that must be an exception as well."

In this example, the return keyword plays an important role in helping the student understand what's going on. Removing it makes it much harder to understand.

So far, the core team has done a really good job at carefully selecting which sugar to include and which not to, but I don't feel like this proposal meets the standards the language has set so far. I understand where the proposal is coming from, and that it looks like an obvious improvement to many, but I don't feel like it solves a real problem and it has the potential to reduce clarity instead of improving it.

In general, I would also like to ask the community and the core team to take the utmost care when it comes to accepting new sugar. I don't see many proposals backed by studies that prove the proposed features do indeed improve the language for the general public (of which this forum is probably not a good representation). Without proper evidence, I don't think marginal gains are enough for a proposal to be accepted.

6 Likes
(Matthew Johnson) #104

This doesn’t work. The top var in your example is already valid syntax and is a stored property. I discussed this direction upthread. It would require new syntax. I used := as a strawman.

I generally don’t think this direction is a good idea unless we are willing to consider return type inference when the := shorthand is used to declare a function. I can’t think of any good reason why we would allow return type inference for a computed property but not for a function.

If we aren’t going to support return type inference (we probably aren’t) then I think this proposal is the best and most consistent direction. Using braces only requires one additional character over the = syntax and zero additional characters over the := syntax. It is also consistent with Swift’s current design that all code bodies appear inside braces (with the single exception of direct initialization of stored properties).

(Gwendal Roué) #105

This syntax could work for functions, but not for properties which already use the = operator:

// Already looks for an available `reduce` method in the current scope
var sum = reduce(0, +)

A possible solution would be to use the := operator, which is already used in several languages as a definition operator, and is not yet used in Swift:

func sum() -> Int := reduce(0, +)
var sum := reduce(0, +)

I also think that this syntax could address several concerns of @svanimpe above. Do you think it would help students understand that reduce returns a value despite its imperative form?

#106

• What is your evaluation of the proposal?

+1

Implicit returns from single-expression functions and properties seems like a natural extension of Swift, and matches implicit returns from single-expression closures.

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

Yes

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

Yes. The parallel with single-expression closures seems elegant and Swifty to me.

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

Read the proposal and followed the discussion.

Jeremy

(Matt Rips) #107

Hmm. This might be too much type omission.

The type inference system depends on having type information at the point where functions and properties are declared. Routinely omitting that information would make the system work much harder and slower, and lead to more frequent unsolvable cases.

Also, in practice, this might be harder to read at a glance if not used judiciously.

2 Likes
(Matt Rips) #108

So, now, I am way off topic. Apologies to everyone. A couple of quick thoughts, and then I will refrain.

  • Consistent Syntax: I think the operator (if any) and right-hand sides for functions and computed properties need to use the same syntax. This suggestion accomplishes that objective.

  • Syntax for Type of Computed Property: I'm not sure of the explicit type syntax for the computed property. Would it be var sum: Int := reduce(0, +)?

  • Preference: I don't know whether users would prefer this approach over that championed by the proposal at hand. Do we need data? How does one obtain such data?

  • Consistency of Braces: Omitting the braces in these instances isn't great. It feels like the language would be heading down a path of having a mish-mosh of syntax. Would it be better to use the plain = operator, and keep the braces on the right side? Such as:

func sum() -> Int = { reduce(0, +) }
var sum: Int = { reduce(0, +) }    
(Preston Sumner) #109

Do you disagree with the use of implicit returns in closures, and do you think that's comparable to this?

(Michael) #110

Good point.

I’m not convinced that adding = would serve any meaningful purpose over the proposed syntax.

This:

func sum() -> Int = { reduce(0, +) }

vs:

func sum() -> Int { reduce(0, +) }

1 Like
(Gwendal Roué) #111

My apologies. It was just an exploration of Chris Lattner's suggestion for an alternative syntax. And clearly this is not what is proposed in SE-0255. We can just leave that here.

(Steven Van Impe) #112

I think closures are a different story.

collection.filter { $0.age >= 18 }.map { $0.name }

With closures, you tend to think only about the expression. In the example above, you're filtering based on a condition and mapping to a value. You're not really thinking about declaring a function that returns a value; that's just an implementation detail.

My experiences with closures are that:

  • students with prior programming experience tend to struggle with the syntax in general because they've only used arrow syntax so far (e.g. in Java or C#).
  • students learning Swift as their first language have less issues with the syntax because they have no preconceptions as to what closures should look like. They tend to struggle mostly with trailing closures. I've seen a lot of these students avoid trailing closures at first and only adopt them when they have a better understand of closures in general.
2 Likes
(Ben Cohen) #113

Proposal Accepted

The review demonstrated clear support for this syntax for property and subscript getters, where the need to return simple single expressions is common.

On eliding the return from functions, the review feedback was more divided. While there was support from some reviewers, others expressed the view that the feature should be restricted to just getters. However, on reviewing the feedback, the core team does not see a strong case was made against applying it to functions as well, when weighed against the benefits of a single uniform rule.

Some reviewers floated the idea of a different syntax for function declaration, using = or => , as seen in other languages. The core team doesn't feel this syntax handles properties or subscripts well, and does not consider sugaring function declarations specifically with a separate syntax a useful change.

The core team also acknowledges that accepting this feature may encourage follow-on proposals that generalize it further, such as converting if/ switch statements into expressions, or allowing elision in multi-statement bodies. Accepting this proposal doesn't necessarily endorse or rule out those future directions.

Thank you to everyone who participated in this review!

Ben Cohen
Review Manager

23 Likes
[Accepted] SE-0255: Implicit Returns from Single-expression Functions
Func return elision and subjective feedback
Pitch: if/else expressions
(Ben Cohen) closed #114