# $functionReturnValue

**URL:** <https://forums.swift.org/t/functionreturnvalue/39888>\
**Category:** Pitches\
**Tags:** function, defer-statement\
**Created:** [August 31, 2020, 3:17pm UTC](https://forums.swift.org/t/functionreturnvalue/39888 "2020-08-31T15:17:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [August 31, 2020, 3:17pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/1 "2020-08-31T15:17:27Z")

</div>

hello,

when using `defer` statement it is very tempting to have an ability to grab the function return value without introducing a special variable and tracking it manually. consider this example:

```
func foo1(param1: Int, param2: Int?, param3: UnsafePointer<Float>?) -> Int {
    
    defer { trace($functionReturnValue) }
    
    guard param1 > 0 else {
        return -1
    }
    guard let param2 = param2 else {
        return -2
    }
    guard let param3 = param3 else {
        return -3
    }
    return some(param1: param1, param2: param2, param3: param3)
}

```

in order to write this today you have to introduce a variable, and always remember to assign it before returning:

```
func foo2(param1: Int, param2: Int?, param3: UnsafePointer<Float>?) -> Int {
    
    var result = 0
    defer { trace(result) }
    
    guard param1 > 0 else {
        result = -1
        return result
    }
    guard let param2 = param2 else {
        result = -2
        return result
    }
    guard let param3 = param3 else {
        result = -3
        return result
    }
    result = some(param1: param1, param2: param2, param3: param3)
    return result
}

```

the obvious problem here is that it is very easy to forget to assign the variable:

```
    return -3

```

or mistakenly use a different variable:

```
    let result = -3
    return result

```

to be less verbose you can introduce a helper function:

```
func setResult<T>(_ v: inout T, _ val: T) -> T {
    v = val
    return val
}

```

and use it like so:

```
func foo3(param1: Int, param2: Int?, param3: UnsafePointer<Float>?) -> Int {

    var result = 0
    defer { trace(result) }
    ...
    guard let param3 = param3 else {
        return setResult(&result, -3)
    }
    return setResult(&result, some(param1: param1, param2: param2, param3: param3))
}

```

this is shorter but at the same time more awkward looking and is still easy to forget to do.

was ability to get the function return value discussed? how do you feel about adding this new feature to swift? this is a pure additive feature, hopefully not too hard to implement.

---

<div class="post-metadata">

**Author:** ![typesanitizer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/typesanitizer/32/8661_2.png) [@typesanitizer](https://forums.swift.org/u/typesanitizer)\
**Post date:** [August 31, 2020, 4:21pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/3 "2020-08-31T16:21:03Z")

</div>

Wouldn't it be easier to copy-paste the type signature and do a rename?

```swift
func foo1(...) -> ... {
  let result = foo1_inner(...)
  trace(result)
  return result
}
func foo1_inner(..) -> ... { /* old implementation */ }

```

This avoids having to change each return statement in the function.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [August 31, 2020, 4:40pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/4 "2020-08-31T16:40:44Z")

</div>

you can say the same about the `defer` statement itself. if we didn't have it today, would we introduce it, or would we use this workaround?

to see the obvious limitation here imagine you want to trace some internal variable(s) of `foo1_inner` in addition to result.

---

<div class="post-metadata">

**Author:** ![typesanitizer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/typesanitizer/32/8661_2.png) [@typesanitizer](https://forums.swift.org/u/typesanitizer)\
**Post date:** [August 31, 2020, 4:46pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/5 "2020-08-31T16:46:03Z")

</div>

I don't think it is the same thing. One of the main uses for `defer` is resource cleanup. Using a wrapper would need to extend the lifetime of the resource and obscure the logic of the code. Moreover, different paths along the function may need different resources to be cleaned up.

---

<div class="post-metadata">

**Author:** ![SlaunchaMan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slaunchaman/32/520_2.png) [@SlaunchaMan](https://forums.swift.org/u/SlaunchaMan)\
**Post date:** [August 31, 2020, 4:49pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/6 "2020-08-31T16:49:53Z")

</div>

I think this is a worthwhile addition to the language. It’s fairly niche, but I can see situations where it would be useful. One question: how would this react to methods that `throw`? I actually wasn’t sure how Swift handles `defer` and `throws` today so I threw together a quick Playground:

```swift
enum SomeError: Error {
    case shouldErrorWasTrue
}

func doSomething(andThrow shouldThrow: Bool) throws {
    defer { print("Hello") }
    if shouldThrow {
        throw SomeError.shouldErrorWasTrue
    }
}

do {
    try doSomething(andThrow: true)
}
catch {
    print(error)
}

```

In this case, the `defer` statement is still executed. Obviously, if this was using `$functionReturnValue`, then it would be invalid. Would `$functionReturnValue` need to be a `Result<T, Error>` for a throwing function returning `T`?

---

<div class="post-metadata">

**Author:** ![adamkemp](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/adamkemp/32/3017_2.png) [@adamkemp](https://forums.swift.org/u/adamkemp)\
**Post date:** [August 31, 2020, 5:00pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/7 "2020-08-31T17:00:07Z")

</div>

`defer` isn't only used at the outermost function level. You can also use it within any nested scope:

```swift
func foo() throws {
    do {
        defer { print("Hello") }
        try bar()
    }
}

```

The `defer` block in that case runs when the `do` scope exits (either by finishing successfully or by throwing). In either case there is no return value at that point.

---

<div class="post-metadata">

**Author:** ![David\_Catmull](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_catmull/32/1007_2.png) [@David\_Catmull](https://forums.swift.org/u/David_Catmull)\
**Post date:** [August 31, 2020, 5:13pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/8 "2020-08-31T17:13:08Z")

</div>

Can it be statically determined if the `defer` would execute because of a `return` statement?

Here's a thought: give the `defer` block a parameter which will be filled in with the return value (and of course its type must match the function's return type). If the function is exiting because of a `throw`, then any such `defer` is not executed. Or type it as `Result<ReturnType, Error>` if you really need something that executes in either case.

---

<div class="post-metadata">

**Author:** ![adamkemp](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/adamkemp/32/3017_2.png) [@adamkemp](https://forums.swift.org/u/adamkemp)\
**Post date:** [August 31, 2020, 5:25pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/9 "2020-08-31T17:25:56Z")

</div>

> Can it be statically determined if the `defer` would execute because of a `return` statement?

Only in the most trivial cases, and those cases can easily be solved without using `defer` at all.

> If the function is exiting because of a `throw` , then any such `defer` is not executed.

`defer` is useful specifically because it executes regardless of how the scope is exited. Any version that may be skipped seems pointless at best, and a recipe for bugs at worst.

> Or type it as `Result<ReturnType, Error>` if you really need something that executes in either case.

This still doesn't cover the cases in which there is neither a return value nor an error.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [August 31, 2020, 6:01pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/10 "2020-08-31T18:01:32Z")

</div>

i believe $functionReturnValue shall work exactly like it was an explicit variable declared at the very beginning of the function and set to return value just before every return statement. that answers all raised questions:

- if function type is **"T"** the `$functionReturnValue` is **"T?"** (see option-b below)
- if function type is **"T?"** the `$functionReturnValue` is still **"T?"**
- if function is **"foo() throws -\> T"** the `$functionReturnValue` is still **"T?"**
- if function result is not available (e.g. because function throws or in the "inner" defer contexts the `$functionReturnValue` value is **nil**
- the "inner" defer statements might additionally prohibit `$functionReturnValue` usage and raise a compilation error.

(option-b would be to have `$functionReturnValue` non optional in non throwing functions and optional in throwing functions).

---

<div class="post-metadata">

**Author:** ![SlaunchaMan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slaunchaman/32/520_2.png) [@SlaunchaMan](https://forums.swift.org/u/SlaunchaMan)\
**Post date:** [August 31, 2020, 6:58pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/11 "2020-08-31T18:58:44Z")

</div>

The inner scope is a very interesting case. Consider this function:

```swift
func foo() throws -> Int {
    if /* some condition */ {
        defer { print($functionReturnValue) }

        if /*someOtherCondition */ {
            return 42
        }
        else if /*someThirdCondition */ {
            throw SomeError
        }
    }

    return 100
}

```

The `defer` statement there could execute when the function returns a value, when the function throws an error, or when the `if` statement ends but before the function returns.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [September 1, 2020, 5:28pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/12 "2020-09-01T17:28:25Z")

</div>

good example. it shows that even the inner defer will have return value in some cases, so worth having $functionReturnValue to be typed as optional in all instances.

---

<div class="post-metadata">

**Author:** ![michelf](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michelf/32/1180_2.png) [@michelf](https://forums.swift.org/u/michelf)\
**Post date:** [September 1, 2020, 5:46pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/13 "2020-09-01T17:46:06Z")

</div>

I would suggest making it of type `Result<R, E>`, where `R` matches the function return type and `E` the error type (either `Error` or `Never`). This way you can trace thrown errors too.

Using `$` as a prefix could conflict with the projected value of property wrappers. I'd use `#` instead.

---

<div class="post-metadata">

**Author:** ![SlaunchaMan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slaunchaman/32/520_2.png) [@SlaunchaMan](https://forums.swift.org/u/SlaunchaMan)\
**Post date:** [September 1, 2020, 6:07pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/14 "2020-09-01T18:07:17Z")

</div>

Since `Result` is in the Swift standard library, doing this at the language level might instead necessitate a new type, something like this:

```swift
enum FunctionReturnValue<ReturnValue, Error> {
    case notYetReturned
    case returned(ReturnValue)
    case threwError(Error)
}

```

As an added bonus, if typed `throws` is added to the language, then the `Error` type of this enum could match the function’s.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [September 1, 2020, 7:32pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/15 "2020-09-01T19:32:41Z")

</div>

It seems like it would be a better match for what you're trying to do to just generally have some sort of "function decorator", probably as a custom attribute, that allowed you to automatically insert code that runs on entry/exit, and which would have (read-only, probably?) access to the parameters and return value.

---

<div class="post-metadata">

**Author:** ![TellowKrinkle](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tellowkrinkle/32/3370_2.png) [@TellowKrinkle](https://forums.swift.org/u/TellowKrinkle)\
**Post date:** [September 1, 2020, 10:25pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/16 "2020-09-01T22:25:37Z")

</div>

This would also make it easier to make a defer that only runs if the function throws, but not if it returns successfully

As for why a function decorator wouldn't be good enough, you can't use one to imitate a `defer` partway through a function that uses variables defined earlier in the function

e.g.

```swift
class MyDylib {
	let handle: UnsafeMutableRawPointer
	let myfn: @convention(c) () -> ()

	init(path: String) throws {
		guard let opened = dlopen(path, RTLD_LAZY) else {
			throw LoadError.noDLL(path: path)
		}
		handle = opened
		defer {
			// Deinit doesn't run if the init fails, so we need separate cleanup
			if case .threwError(_) = $functionReturnValue {
				dlclose(handle)
			}
		}
		myfn = try getSymFromDll(handle, "myfn")
	}
}

```

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [September 1, 2020, 10:57pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/17 "2020-09-01T22:57:55Z")

</div>

That does not seem like a pattern I would actually want to encourage. If you want a way to run a defer only on error paths, that's something we could support directly.

---

<div class="post-metadata">

**Author:** ![GreatApe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/greatape/32/2640_2.png) [@GreatApe](https://forums.swift.org/u/GreatApe)\
**Post date:** [September 2, 2020, 12:29pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/18 "2020-09-02T12:29:32Z")

</div>

Would you ever be able to access the return value while it has the first case?

---

<div class="post-metadata">

**Author:** ![SlaunchaMan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slaunchaman/32/520_2.png) [@SlaunchaMan](https://forums.swift.org/u/SlaunchaMan)\
**Post date:** [September 2, 2020, 7:13pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/19 "2020-09-02T19:13:43Z")

</div>

No, the way I see it in my head the `notYetReturned` case would only happen for `defer` statements inside another scope in the function (e.g. an `if` statement) and therefore would not have a return value. If that `if` statement had a `return`, then it would be the `returned` case instead.

---

<div class="post-metadata">

**Author:** ![filip-sakel](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/filip-sakel/32/8697_2.png) [@filip-sakel](https://forums.swift.org/u/filip-sakel)\
**Post date:** [September 2, 2020, 7:56pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/20 "2020-09-02T19:56:28Z")

</div>

I think we could also have set-like syntax:

```
func foo() -> Int {
    defer(returnValue) {
        print(
            “Returned \(returnValue)”
        )
    }

    ...
}

```

In the above example ‘returnValue’ would be the default name of the defer-provided value (like how ‘newValue’ works in a computed variable’s ‘set’). That is, “defer(returnValue)” could be written as “defer” and used under the name ‘returnValue’ or a different name could be specified. As for the type, I think it should be just ‘Int’. The only ways of exiting a function’s scope is by returning a value (what we expect to happen in foo), by calling a ‘Never’-returning function (which we shouldn’t be concerned about) and by throwing (which doesn’t apply to foo). As for a throwing function similar to foo, I second the idea proposed: of the return value being an optional wrapping the actual return type.

As for source breakage, I think the only way that this proposal could be considered source breaking is by the implicit ‘returnValue’ of defer being used instead of a variable of the same name declared in the outer scope. Needless to say, this case would be incredibly rare.

What do you think?

---

<div class="post-metadata">

**Author:** ![cukr](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cukr/32/889_2.png) [@cukr](https://forums.swift.org/u/cukr)\
**Post date:** [September 2, 2020, 8:09pm UTC](https://forums.swift.org/t/functionreturnvalue/39888/21 "2020-09-02T20:09:04Z")

</div>

> [@filip-sakel](#):
>
> The only ways of exiting a function’s scope is...

What about non-function scopes?

[Next page](https://forums.swift.org/t/functionreturnvalue/39888.md?page=2)
