# \[Pitch\] Last expression as return value

**URL:** <https://forums.swift.org/t/pitch-last-expression-as-return-value/76958>\
**Category:** Pitches\
**Created:** [January 2, 2025, 12:37am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958 "2025-01-02T00:37:10Z")\
**Posts on this page:** 20\
**Page:** 19

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [January 13, 2025, 12:07am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/381 "2025-01-13T00:07:13Z")

</div>

> [@Nobody1707](#):
>
> My point is that it already isn't what it would look like, because the natural version is already `return if` if that makes the style privileged, then it is already privileged.

That's only true if people choose to adopt `if` expressions in every single situation where they are able to, but I don't think we can or should assume that.

---

<div class="post-metadata">

**Author:** ![ben-cohen](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ben-cohen/32/296_2.png) [@ben-cohen](https://forums.swift.org/u/ben-cohen)\
**Post date:** [January 13, 2025, 12:15am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/382 "2025-01-13T00:15:53Z")

</div>

> [@allevato](#):
>
> Exactly—you've re-emphasized my point. This proposal privileges specific style choices and prevents other common ones.

I agree it privileges those "symmetric" cases where the `else` is explicitly included. But I think I'm missing how it _prevent_ other cases. Or are you saying that while "no else" code that was valid before remains valid, and doesn't itself get any kind of sugar, and so is lessened?

Personally, I'd write the `else` form anyway. I'd also say it's fine keeping the `return` if you're really keen on the "no else" style and think the elided else with it looks a bit icky.

(I have a feeling LLVM developers in particular are keen on this idiom)

---

<div class="post-metadata">

**Author:** ![Andropov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andropov/32/35955_2.png) [@Andropov](https://forums.swift.org/u/Andropov)\
**Post date:** [January 13, 2025, 12:43am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/383 "2025-01-13T00:43:22Z")

</div>

> [@ben-cohen](#):
>
> The challenge with this situation–that to achieve the low-ceremony feel we desire, we must bring together many low-impact things–is that each one has downsides. Individually they have a small impact, so for each one, one might say “we shouldn't do this because ” due to those downsides. For each one, you can say “come on, is that return/semicolon/paren/logner name really a problem? it's NBD, and consider downsides”. Each one is small, and so easy to argue against in isolation, but they add up to be huge.

I do agree that _"come on, is that return/semicolon/paren/longer name really a problem?"_ is not ever useful feedback. But I don't think that's what we have here. Most people in this thread agree that the problem described in the motivation section is a real problem worth tackling. I surely run into that limitation frequently and would love to see a way around it. But, at the same time, if the solution proposed has broad impact across the language, it's reasonable to question whether those impacts may become a bigger issue than the original problem being fixed.

Otherwise, the same argument can be reused to virtually every idea about cutting down ceremony. We could elide the `else { return }` clause in a `guard` part of a function returning `Void`. Skip the `[weak self] in` at the beginning of a closure if self is used as an optional inside. Allow implicit throws if the last expression has a type conforming to `Error`. Or any other idea where it's probably best _not_ to cut down in the ceremony.

I'm not arguing that a solution should be flawless and with no downsides. That's rarely possible. But it should be possible to conclude that for a specific proposal the downsides are greater than the benefits, even if that proposal allows cutting down some ceremony (which granted, is a huge bonus because it composes into clearer code). In fact, there must be a line somewhere, because `guard` statements in particular have been carved out from this proposal and forbidden from using implicit returns!

> [@ben-cohen](#):
>
> Really, I think it's better to break it onto a separate line:
> 
> ```swift
> func hasSupplementaryViewAfter() -> Bool {
> let cellIndex = elements.firstIndex { $0.elementCategory == .cell }
> if let cellIndex {
> return elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> } else {
> return false
> }
> }
> 
> ```
> 
> That's clearer. But now we have our ceremony back. The `return`s here don't add value, they interfere with readability.

I disagree with this statement. I absolutely read this version better than the one where both`return`s are elided. I certainly don't think they _interfere_ with readability. This case is simple enough that one may call those `return`s _redundant_, but I don't see how they interfere with readability in the same way as your other example with `$0` vs a named `i`. In that example, the problem with the `i` is that suddenly one needs to pause for a second and ask _"Wait. What is `i` here?"_. There's no such problem with `return`. I don't need ot pause to think what `return` means. It may be slightly redundant in some cases, but hardly interfere with readability.

And, in the case where you haven't immediately internalized the function signature before reading a snippet (there's many reasons to start reading code in the middle of a function), the `return`s absolutely help readability.

> [@ben-cohen](#):
>
> The ending `return` has no such role. Functions return when they reach the end. That doesn’t need re-stating, and doing so increases ceremony without increasing clarity.

Ah, but implicit returns at the end (as in **last line** ) of a function are not as controversial. Not to me, at least. The main problem is that when combining implicit returns with large expressions (which can even be nested!), a given "end of a function" may be dozens of lines above the closing brace of the function. It may not be obvious at all that the function ends at that point without reading the entire control flow of the function.

One way to limit that is by mandating one-line expressions. Maybe there are other heuristics (disallow nesting implicit returns?). But I think some guardrail should be in place to avoid writing code where an implicit return happens several lines before the end of the function.

---

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [January 13, 2025, 12:56am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/384 "2025-01-13T00:56:38Z")

</div>

> [@ben-cohen](#):
>
> Or are you saying that while "no else" code that was valid before remains valid, and doesn't itself get any kind of sugar, and so is lessened?

Exactly. Let's imagine that the user had this today, using the elided-`else` style:

```swift
func f() {
  if someConditionWhereEitherOutcomeIsLikely {
    let x = doSomething(a)
    return doSomethingElse(x)
  }
  let x = doSomething(b)
  return doSomeOtherThing(x)
}

```

That code is already a small bit asymmetric by virtue of eliding the `else`, but aside from that one concession, it's otherwise symmetric—each branch is a block of statements that ends with a `return`ed value.

If that author wanted to adopt last-expression results—let's say for the sake of argument via a formatter that could automatically remove "unnecessary" `return`s—then such a rule would introduce more asymmetry into the code by removing the second `return` but not the first. If the user wanted to improve this (where "improve" means "put back more symmetry"), they would have to introduce an `else` to remove the other `return`. This isn't an easily automatable change. If the user wants to benefit from the proposed idea that it draws attention to early `return`s, then this feature requires more manual intervention to differentiate between what's a _real_ early `return` and what's just the `false` branch of an otherwise innocuous function-final conditional, a distinction that doesn't matter/exist when `return` is required everywhere.

Of course, it's entirely possible that the two style choices—elided `else` and last-expression return—are fundamentally incompatible with each other and no code base should attempt to do both. If that's the conclusion we reach, it's fine! I'm not necessarily advocating for that style, but I've seen it in plenty of projects I work on day-to-day.

Since the topic of linters does keep coming up, since this proposal does touch on style as much as it does introducing new _functionality_, it's worth noting that a linter/formatter can diagnose and remove an _unnecessary_ `return` in a world where this proposal is accepted and the user wanted to enforce a no-`return` rule, but it cannot _insert_ a necessary `return` if the user wants to enforce a required-`return` rule. At least, not without semantic information (it needs to know whether expressions have type `Void` or not to avoid adding unnecessary returns of those), which is a much less-supported side of Swift's tooling story. (When single-expression implicit returns were added, swift-format was able to add a rule that diagnosed and removed unnecessary `return`s but it cannot do the opposite.)

So at least in terms of the tooling side of the equation, this would be another situation where a particular style is privileged by a language feature. Given that, I wonder if we're going to be heading in a direction where it makes sense to have the discussion about a more opinionated style and format being enforced by standard tooling, to avoid the "style" part of these discussions from being such a heavy factor. (My biases are certainly showing here.)

---

<div class="post-metadata">

**Author:** ![Pippin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pippin/32/24826_2.png) [@Pippin](https://forums.swift.org/u/Pippin)\
**Post date:** [January 13, 2025, 1:05am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/385 "2025-01-13T01:05:49Z")

</div>

> ceremony

I don't think that critics of this feature are arguing that less ceremony is necessarily bad. We love Swift's conciseness! We may even use this feature on some places.

However, I repeat an earlier comment that we are somewhat free to choose what reduction in ceremony we may enjoy:

> [@\[Pitch\] Last expression as return value](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/199):
>
> Great comment @austintatious, fully agreed. Besides, if we go a bit higher-level, I think we should acknowledge that keywords not only bear some function in the language, they also serve as visual markers for scanning and understanding the code faster, especially in IDE's, but not only. There are probably a few other places where Swift's syntax could be simplified by removing a keyword but the price of reducing discoverability by removing an important marker may outweigh the benefits. Being a…

But where will we draw the line for the minimum amount of ceremony necessary? The reduction of ceremony has come through fine iterations like chipping away at marble, removing ever-so-small parts to reveal a fuller form of the language. However, it only takes one bad chip to cause the largest cracks.

There are many other places throughout the language that we can apply this broad "ceremony reduction":

- remove `await`
- remove `try` if last in `do` block, or at all
- remove `()` for no function arguments
- remove trailing closure labels
- remove `func`, you can tell it's a function from the `name [-> type] {`
- remove `catch` from `do/catch`. If you have a `do`, you should know the next block is the `catch`
- \<insert your removal here that may not be difficult for the _compiler_ to parse, but may be for _people_\>

No, I don't feel like I'm being rhetorical or outlandish with these examples.

> teaching beginners

For those unconvinced by the teaching aspect, Swift is marketed as an Accessible language. This is the first line in the description at [developer.apple.com/swift](https://developer.apple.com/swift/):

> Swift is a powerful and intuitive programming language for all Apple platforms.

For teaching absolute beginners to _programming_, absolutely nothing is intuitive. You have to explain what syntax _is_ and _why_ it is the way it is. You have to teach about _types_ and why they _matter_ ("Why can't we mix `Int` and `Double`? They're both numbers?"). You have to teach so much from absolutely nothing where absolutely nothing is "intuitive", because now they're undertaking a heavily technical learning path that they may have never done before.

Eliding ceremony is not the best for beginners. The only explanation I can really offer at that level for _why it still works_ when ceremony has been reduced is: "the computer does it for you". You'd be surprised then that it makes them more upset and confused! They keep wondering "Why? Why? Why?". Many beginners don't know what a compiler "is" or is a master in linguistics. Of course we can just "write the ceremony" but these reductions are at the forefront of all syntax, they _will_ run into them "in the real world". No, these are not just "taught once". Having to remember all the time what reductions are allowed is a constant familiarity process that beginners have to fight through.

It has been commented that maybe the frame of beginners isn't the most appropriate to assess this feature. However, I've only seen proponents comment that they enjoy this feature "from other languages".

For those that don't have the expertise of "other languages", the rest of the Swift world are the "beginners". When we borrow features, they should be able to be a natural fit, but we seem to be at an impasse on that front.

---

<div class="post-metadata">

**Author:** ![austintatious](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@austintatious](https://forums.swift.org/u/austintatious)\
**Post date:** [January 13, 2025, 1:06am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/386 "2025-01-13T01:06:40Z")

</div>

> [@ben-cohen](#):
>
> edit: the code is also invalid under this proposal – it mixes explicit returns from an `if` with implicit return values in a way that would not be permitted.

The example code I provided is a snapshot into the thought process of someone who is evolving code that either they wrote a long time ago OR is a code repository they are now in charge of evolving. It highlights how difficult it is to reason with expectations.

Which is why I said the following:

> [@austintatious](#):
>
> This function needs to be fixed. There seem to be multiple ways that we can go about fixing it.

So for example when I wrote the comment (on that return in question) as follows:

```swift
//return here? Okay. I will add return because this is the value, I think they want.

```

It is exemplifying how hard it can be to tell how I am supposed to yield the value. Now that I am revisiting it or taking it over.

> [@ben-cohen](#):
>
> No matter how long, a function has only one end.

That depends on what you mean by 'last line', an if-expression whence the return value is yielded can now be hundreds of lines long. It's the last 'logical' line, I suppose, but it definitely obscures where the return is happening all the way at the top.

> [@Paul\_Cantrell](#):
>
> However, I do worry a bit about the “Did the author do this on purpose?!” problem.

This is precisely right, the critique here is not if we could theoretically have this feature work (it will work!) but it is how does it affect the code reader and the cases where a function can assume too much about what your intent is.

> [@shantini](#):
>
> I thought I could walk you through my thought process, as it’s probably different than the more experienced language experts here!

I have been programming for ~26 years now. I appreciate what you did here @shantini so much because what you point out is how something as simple as eliding `return` and having the compiler do more work for us promotes dangerous code style options that can confuse intent. I would have the same problem and have a similar thought process when trying to discover intent.

I think @xwu said it well:

> [@xwu](#):
>
> There is low ceremony, but I think we should be attentive that the pursuit of _least_ ceremony doesn't lead to so many stylistic choices that choosing _how_ to writing anything becomes a ceremony in itself.

I believe this is hardly a problem in single line closures and functions -- we can come up with examples similar to the ones provided where it obfuscates intent to the reader even in logically single line, but it is less likely. In multi-line functions, it feels more likely and should simply not be allowed.

Often it is okay to sacrifice 'consistency' for 'clarity'.

In theory, eliding `return` can seem clean, and easy to work with, but in practice it just is not. Eliding `return` hides what is happening in larger functions and that is feels very dangerous and should not be expanded into multi-lined bodies.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [January 13, 2025, 1:30am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/387 "2025-01-13T01:30:06Z")

</div>

> [@FlorianPircher](#):
>
> I think the end of a function is much clearer/easier to identify than the fact that a block inside a function is from the `else` of a `guard` statement. Highlighting the `return` within a function is part of this proposal and that is always the case for `guard` as you would not need to use one at the end of a function.

It is equally easy to identify the end of the `else` block as it is to identify the end of the enclosing function block, and in both cases you have to look at what precedes the paired opening brace to know that it’s a function or a `guard`.

---

<div class="post-metadata">

**Author:** ![100phlecs](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/100phlecs/32/34640_2.png) [@100phlecs](https://forums.swift.org/u/100phlecs)\
**Post date:** [January 13, 2025, 1:49am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/388 "2025-01-13T01:49:36Z")

</div>

> [@Daniel\_Steinberg](#):
>
> I do spend a lot of time teaching people new-ish to the language and once a single expression function didn't require a return I've wanted this as a way of removing confusion.
> 
> ```swift
> func someMethod(int: Int) -> Bool {
> int.isMultiple(of: 2)
> }
> 
> ```
> 
> works fine but
> 
> ```swift
> func someMethod(int: Int) -> Bool {
> print("inside someMethod")
> int.isMultiple(of: 2)
> }
> 
> ```
> 
> requires a return on the second line of the body and this confuses many people.

To add a data point, as a recent beginner to Swift, I ran into this same confusion.  
It seems this pitch would help with consistency, seeing as omitting `return` is already in the language.

After all, when omitting `return`, all one needs to search for is the final block of a function. Or, in the case of Swift, an early `return` which would be highlighted/boosted by the fact the default end-body `return` would no longer be needed.

---

<div class="post-metadata">

**Author:** ![jordanekay](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jordanekay/32/2499_2.png) [@jordanekay](https://forums.swift.org/u/jordanekay)\
**Post date:** [January 13, 2025, 2:41am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/389 "2025-01-13T02:41:52Z")

</div>

Upon seeing @ben-cohen’s example, my mind immediately translated it into something more declarative:

```swift
func hasSupplementaryViewAfter() -> Bool {
  elements.firstIndex { $0.elementCategory == .cell }.map { cellIndex in
    elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
  } ?? false
}

```

This of course has the added benefit of being a single statement, avoiding the issue, but I wouldn’t say that avoiding the `return` is motivation itself using this style.

---

<div class="post-metadata">

**Author:** ![ben-cohen](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ben-cohen/32/296_2.png) [@ben-cohen](https://forums.swift.org/u/ben-cohen)\
**Post date:** [January 13, 2025, 2:43am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/390 "2025-01-13T02:43:57Z")

</div>

> [@Pippin](#):
>
> There are many other places throughout the language that we can apply this broad "ceremony reduction":
> 
> - remove `await`
> - remove `try` if last in `do` block, or at all
> - remove `()` for no function arguments
> - remove trailing closure labels
> - remove `func`, you can tell it's a function from the `name [-> type] {`
> - remove `catch` from `do/catch`. If you have a `do`, you should know the next block is the `catch`
> - \<insert your removal here that may not be difficult for the _compiler_ to parse, but may be for _people_\>
> 
> No, I don't feel like I'm being rhetorical or outlandish with these examples.

You're not, but each one has an answer. The goal here is to remove ceremony where it delivers insufficient value, or is otherwise causing problems, inconsistencies etc.

So for example, "remove `()` for no function arguments" is, I think a very reasonable proposition (if you're talking about the call site). Ruby, for example, doesn't require parens for function calls. The challenges though would be considerable. Mainly, the syntax for unapplied methods is to leave off the parens. If we went back in time to Swift 1.0, added the `\` syntax for keypaths, and then extended that to also be the sigil for unapplied methods, then I could totally see an alternate reality where `()` aren't necessary for function calls. These days, however, that's almost certainly an unrealistic change to make to Swift. Unlike the change pitched here, it could not be adopted as an incremental change, and so probably not worth discussing further. But that doesn't mean it isn't interesting to consider.

As for removing `await` or `try`. There is every reason to look for ways to minimize these keywords further. They exist for a specific purpose, which is to mark a point where reentrancy could happen, or a scope can exit. Those markers are vital – but also sometimes redundant, like `return` can be.

Swift _already_ allows you to skip stating the `try` twice on one line. Sometimes. But not in this case:

```swift
try values.map { try $0.failable() }

```

The second `try` is entirely redundant. It would be nice to have a rule to avoid having to restate it.

This kind of thing is important to look at in future. If you look at some well-written modern structured concurrency code in Swift, it is a cascade of disheartening `return try await ... return try await ... return try await`. We can do better there, so long as it's done with care.

---

<div class="post-metadata">

**Author:** ![austintatious](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@austintatious](https://forums.swift.org/u/austintatious)\
**Post date:** [January 13, 2025, 3:04am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/391 "2025-01-13T03:04:49Z")

</div>

> [@ben-cohen](#):
>
> You're not, but each one has an answer. The goal here is to remove ceremony where it delivers insufficient value, or is otherwise causing problems, inconsistencies etc.

Great! As presented by the naysayers, it adds sufficient value to keep it in multi-lined functions and removing it causes problems.

> [@ben-cohen](#):
>
> As for removing `await` or `try`. There is every reason to look for ways to minimize these keywords further. They exist for a specific purpose, which is to mark a point where reentrancy could happen, or a scope can exit. Those markers are vital – but also sometimes redundant, like `return` can be.

I was afraid that you'd try to make the case.

> [@ben-cohen](#):
>
> `try values.map { try $0.failable() }`

Requiring it does it with care, it is also elegant, clean, safe and gives us the right information that we need.

A tiny bit of redundancy for the sake of safety and clarity is the Swifty way to go!

---

<div class="post-metadata">

**Author:** ![flexlixrup](https://avatars.discourse-cdn.com/v4/letter/f/50afbb/32.png) [@flexlixrup](https://forums.swift.org/u/flexlixrup)\
**Post date:** [January 13, 2025, 7:03am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/392 "2025-01-13T07:03:38Z")

</div>

I think this is a great example of the differences how people parse code. While Ben’s examples (all, even the one with the omitted return) where completely easy to read for me, my brain cannot easily comprehend your code. I have to go to the innermost part first and then switch between the different closures, check what you're mapping, go back to the contains, etc.

So while one person may find it easy to 'determine' what a method will return, others have to think more and go through the function line by line as some people can 'unwrap' closures easily, I cannot.

---

<div class="post-metadata">

**Author:** ![sspringer](https://avatars.discourse-cdn.com/v4/letter/s/e9c0ed/32.png) [@sspringer](https://forums.swift.org/u/sspringer)\
**Post date:** [January 13, 2025, 7:11am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/393 "2025-01-13T07:11:57Z")

</div>

> [@Nobody1707](#):
>
> ```swift
> …
> return if let cellIndex { …
> }
> 
> ```
> 
> Which, under the implicit return of last expression rule would become:
> 
> ```swift
> … 
> if let cellIndex {
> …
> 
> ```

Whenever I use an “ugly” combination as `return if` (which happens to be a lot in my code at the end of functions) I have the suspicion that there should be something better. And having to type `return` twice instead does not feel much better.

And after seeing some examples without any return at the end this does not feel so “bold” any more.

> [@flexlixrup](#):
>
> So while one person may find it easy to 'determine' what a method will return, others have to think more and go through the function line by line as some people can 'unwrap' closures easily, I cannot.

Yes, so I think if you have to use `return` or not at those places will not decide if you write code that is easy to read.

---

<div class="post-metadata">

**Author:** ![Andropov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andropov/32/35955_2.png) [@Andropov](https://forums.swift.org/u/Andropov)\
**Post date:** [January 13, 2025, 7:40am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/394 "2025-01-13T07:40:40Z")

</div>

> [@xwu](#):
>
> It is equally easy to identify the end of the `else` block as it is to identify the end of the enclosing function block, and in both cases you have to look at what precedes the paired opening brace to know that it’s a function or a `guard`.

Arguably easier, as it's unusual to find large `guard` bodies in practice. So the end of a `guard`'s `else` block is usually much closer to the `guard` keyword, and has simpler control flow compared to the end of a function.

I can't think of a reason to avoid extending implicit returns to `guard`s, other than enforcing the idea of using `return` only for "unusual control flow". But I'm not sure that's even achievable. Sometimes the "unusual" flow happens at the end, this is a relatively common pattern:

```swift
func handleURL() -> Bool {
    if handleWithFeatureA() {
        return true
    } else if handleWithFeatureB {
        return true
    }
    // No feature can handle this URL!
    false
}

```

Anyhow, I feel like the pitch as-is would have the effect of discouraging early returns using `guard`:

- `guard` statements can't use this new syntax to return values.
- In a `if`/`switch`/`do` expression, one must avoid using `guard`, as there's no keyword to assign the variable in the `else` block and there are no implicit returns there. This may build an 'inertia' of not using `guard` even in contexts where it's supported.

* * *

To this point, the version of @ben-cohen's final example using `guard` instead of an `if`/`else` block reads best to me, even with an elided `return`:

> [@ben-cohen](#):
>
> ```swift
> func hasSupplementaryViewAfter() -> Bool {
> let cellIndex = elements.firstIndex { $0.elementCategory == .cell }
> guard let cellIndex else { false }
> elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> }
> 
> ```

(Of course, this opens the door of what to do with `guard`s in functions that return `Void`. The logical conclusion would be to allow eliding the `else` there entirely).

---

<div class="post-metadata">

**Author:** ![Panajev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/panajev/32/1227_2.png) [@Panajev](https://forums.swift.org/u/Panajev)\
**Post date:** [January 13, 2025, 8:02am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/395 "2025-01-13T08:02:48Z")

</div>

Does not Swift need a keyword to differentiate class vs instance methods too?

---

<div class="post-metadata">

**Author:** ![Panajev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/panajev/32/1227_2.png) [@Panajev](https://forums.swift.org/u/Panajev)\
**Post date:** [January 13, 2025, 8:03am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/396 "2025-01-13T08:03:26Z")

</div>

> [@ben-cohen](#):
>
> The `return`s here don't add value, they interfere with readability.

Could you expand more on how in this particular example the returns actively “hurts” readability please? It is not clear to me it does.

---

<div class="post-metadata">

**Author:** ![Panajev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/panajev/32/1227_2.png) [@Panajev](https://forums.swift.org/u/Panajev)\
**Post date:** [January 13, 2025, 8:19am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/397 "2025-01-13T08:19:35Z")

</div>

As @xwu was mentioning before, reading your reply made me think about it even more, it is a concern where having lots of smaller ceremonies to pick from and the subtle effects each would have or they would have when combined that creates a ceremony of its own.

For all its faults, block syntax was a late addition and not always great (although it could be side stepped), Obj-C was a relatively simple language easy to compose. Actually quite readable and beyond the scare of [ brackets and message passing, the verbose syntax was a bit of a difficulty bump but after that bump the language gotchas mostly disappeared (it was a great language to make apps with…).

The reduction in ceremony in Swift and the additional features it gained vs its predecessor (generics, result builders, structured concurrency, etc…) and how it gained them have a cost in complexity (early Swift did not need famous C++ language lawyers, jury is a bit out on modern Swift…).

@ben-cohen the paragraph where you mentioned removing parentheses from methods that had no arguments gave me flashbacks of Obj-C 2.0 when properties were introduced. Few changes I was so excited about that in practice confused many people blurring the line between properties and methods 😃 .

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [January 13, 2025, 10:52am UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/398 "2025-01-13T10:52:21Z")

</div>

> [@ben-cohen](#):
>
> No matter how long, a function has only one end. That end is generally clear to the user through the closing brace and indentation.

For the pitched multiline expressions this is not holding true. Even as of right now it is possible to write the code where last line isn’t clearly denoting returned value.

Considering the initial example of this function,

> [@ben-cohen](#):
>
> ```swift
> func hasSupplementaryViewAfter() -> Bool {
> let cellIndex = elements.firstIndex { $0.elementCategory == .cell }
> if let cellIndex {
> elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> } else {
> false
> }
> }
> 
> ```

1. If we treat this from standpoint that both branches return a value, then this function has two ends that here presented as “equal”.
2. If we treat this as an expression, then whole `if` denotes the end of a function.

Both cases can be (subjectively easy) deduced in the example. Neither of them, however, follow that function has either one end or it is clearly denoted by the closing brace.

It also can be rewritten with only one return given currently available expressions, and that reads nicely:

```swift
func hasSupplementaryViewAfter() -> Bool {
  let cellIndex = elements.firstIndex { $0.elementCategory == .cell }
  return if let cellIndex {
    elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
  } else {
    false
  }
}

```

I would still prefer version with `guard` in the first place, but that’s question of preference.

* * *

I also agree with @austintatious that problematic cases tend to be more complex and less expressive in the first place, they quite often present much more critical parts of the program as well. Large `if`-`else`-`if` or `switch` is reality for many apps, more than I wish I end up working with code that looks like this one, with me not being an author of this code, so I have to guess what was intent of the author.

> [@austintatious](#):
>
> ```swift
> if let cellIndex = elements.firstIndex(where: { $0.elementCategory == .cell }) {
> if let cellIndex = elements.firstIndex(where: { $0.elementCategory == .cell }) {
> elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> } else if thisThat {
> someBool(flip: false)
> } else {
> if let cellIndex = elements.firstIndex(where: { $0.elementCategory == .cell }) {
> elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> } else {
> if let cellIndex = elements.firstIndex(where: { $0.elementCategory == .cell }) {
> elements[cellIndex...].contains { $0.elementCategory == .supplementaryView }
> } else {
> //doSomething = someBool(flip: false)
> someBool(flip: true)
> }
> }
> }
> } else if let cellIndex = elements.firstIndex(where: { $0.elementCategory == .cell }) {
> return someBool(flip: false)
> } else {
> 
> ```

* * *

There is also another issue brought by implicit `return`s. Modifying example with rays to match proposed behaviour, plus one more replacement to get this code:

```swift
func hit(_ ray: Ray, _ bounds: Range<Double>) -> Hit? {
  // snip...

  // Find the nearest root that lies in the acceptable range.
  var root = (h - sqrtd) / a
  if !bounds.surrounds(root) {
    root = (h + sqrtd) / a
    if !bounds.surrounds(root) {
      return nil
    }
  }
  
  let point = ray.at(root)
  hit(with: point) // <- changed
}

```

It is now harder to reason just by the bare last line what’s happening: does this function returns a value or not? I might be brought there via debugger, so I am not yet aware of the signature, and explicit return can help understand more from this narrow context.

Comparing to Rust, for instance, it is a bit better by at least signalling via missing semicolon:

```swift
fn hit(_ ray: Ray, _ bounds: Range<Double>) -> Option<Hit> {
  // snip...

  // Find the nearest root that lies in the acceptable range.
  let mut root = (h - sqrtd) / a;
  if !bounds.surrounds(root) {
    root = (h + sqrtd) / a;
    if !bounds.surrounds(root) {
      return None;
    }
  }
  
  let point = ray.at(root);
  hit(point)
}

```

IMHO it is still harder to get compared to explicit return, but there is some hint for better understanding.

* * *

This all can be justified that it is not the reason to block the change, because someone always be able to abuse feature to the point of non-readable code. I don’t find this argument relative to this change: the question for me not that it can be abused, but that it _promotes_ certain way to write code to the point where long `if`/`switch` expressions with side effects are extremely easy to create and language has explicitly been adjusted for that.

---

<div class="post-metadata">

**Author:** ![Pampel](https://avatars.discourse-cdn.com/v4/letter/p/3da27b/32.png) [@Pampel](https://forums.swift.org/u/Pampel)\
**Post date:** [January 13, 2025, 3:18pm UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/399 "2025-01-13T15:18:30Z")

</div>

Another big thank you for that post, it's definitely shifted my opinion a bit, although I'm still very much -1.

I've been thinking hard about just why I dislike this so much, because I want to make sure it's not a rationalization for laziness or stubbornness or something else. I think my main reason is that returning a value from a function is kind of a side effect, and when you don't have the `return` keyword, the fact you are causing this side effect becomes invisible. Consider this PR for the tail end of a long public function inside a class...

```swift
    // complicated cool stuff
    
    // other things happen
    
    // generate profits etc
    
    --- calculateCatAgeInYears(...)
    +++ calculateCatToyCount(...)
}

```

With the code seen as is, without implicit returns, we know that this function cannot directly affect the behavior of a caller **just by returning** , otherwise there would be a `return` statement. But with implicit returns, this could directly affect the functionality of callers, too, maybe even causing breaking changes to contracts if this was a public API...but that affect is invisible at the site of the code change that caused it.

---

<div class="post-metadata">

**Author:** ![Morten\_Bek\_Ditlevsen](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/morten_bek_ditlevsen/32/28133_2.png) [@Morten\_Bek\_Ditlevsen](https://forums.swift.org/u/Morten_Bek_Ditlevsen)\
**Post date:** [January 13, 2025, 5:56pm UTC](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958/400 "2025-01-13T17:56:01Z")

</div>

My two cents are not at all original, but as a person who loves Swift, I would like to chime in:

I would absolutely love this!  
I love single-statement closures without returns. I love single statement functions without returns.

I love switch-expressions allowing me to leave out returns in my many, many functions that simple map over an enum value.  
They read so much better to me, because they are very obviously just mapping values.

I do not like realizing that I can’t eliminate returns from a switch statement because of a single log statement or extra check in one of the branches.  
Hitting these situations actually annoy me and I wish that I didn’t have to keep all the returns around.

Similar for single statement functions, it feels hacky to me that I have to add a return because of an extra log statement.

I very much like that this pitch does not introduce new keywords. I really dislike the idea of adding something like ‘then’.

Knowing myself to prefer brevity - and actually believing that brevity most often helps readability, I’m certain that I will also start returns for ‘longer’ functions.

+1 from me.

[Previous page](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958.md?page=18)

[Next page](https://forums.swift.org/t/pitch-last-expression-as-return-value/76958.md?page=20)
