One-Line Closure Without Return Type

One-line closure without return type

The reason this happens is the shorthand for single line expression closures. There is an implicit 'return' in your closure as it is written.

let closure: () -> () = {
StringReturningFunc()
return
}

Writing it like that should work

Understanding syntax of closure with no return type

The following are all equivalent

func foo1() -> () { }
func foo2() -> () { return () }
func foo3() -> () { return Void() }
func foo4() -> () { return }

func foo5() -> Void { }
func foo6() -> Void { return () }
func foo7() -> Void { return Void() }
func foo8() -> Void { return }

func foo9() { }
func foo10() { return () }
func foo11() { return Void() }
func foo12() { return }

print(type(of: foo1)) // (()) -> ()
// ...
print(type(of: foo5)) // (()) -> ()
// ...
print(type(of: foo9)) // (()) -> ()
// ...

If no return type is supplied to a function(/closure), then the empty tuple type (which is typealiased by Void) is inferred. We may, however, explicitly supply this return type, either as () (the type), or Void. From the language guide - functions:

Functions Without Return Values

Functions are not required to define a return type. ...

...

Strictly speaking, this version of the greet(person:) function does
still return a value, even though no return value is defined.
Functions without a defined return type return a special value of
type Void
. This is simply an empty tuple, which is written as ().

Conversely, if no return is given at the end of a function block, it will be the same as explicitly returning an instance of the empty tuple, namely () (the value). This may also be written simply as return.

Why can't I return a closure that returns a view from a Swift function declared as - () - some View ?

If you really need to return a closure (ie, actually a builder) then the simplest (and actually the one) variant is just to declare what is known concrete type (as we know what's returned), ie

func lbl(_ text: String) -> () -> NavLinkLabel {     // << here !!
return {
NavLinkLabel(text: text)
}
}

Otherwise just return NavLinkLabel(text: text) directly, because the some support is limited in swift (at v5.6 time). It is only

'some' types are only implemented for the declared type of properties and subscripts and the return type of functions

means direct return type, not return of returned closure - it is out of scope.

Swift. How to return a function from a closure

Closure does not support return statement. Instead use completion block inside main thread to perform the task:

i.e

function AA( completion: @escaping (Result<[Return Type], Error>) -> Void) {
localPlayer.authenticateHandler{
//…
if trigger {
DispatchQueue.main.async {
completion(//Whatever Return Value)
}
}
dosomething()
}
}

Omitting the return type in Swift closures

I would not expect that example to have worked but it does

In many cases, Swift can often infer types of variables and expressions. In this case, Swift looks at the value you're returning and can infer the type.

If I modify that closure to specify a return type then it continues working

Specifying the type explicitly doesn't change the type that's being returned, so there's no change in behavior.

Or does Swift always return something

Even a void function returns something -- it returns an empty tuple. As was pointed out in the comments, single expression closures implicitly return the value of their expression.

Function not returning value from closure

So the reason why you're having this issue is because AlamoFire.request is asynchronous. There's a great explanation of asynchronous vs synchronous here But basically when you execute something asynchronously, the compiler does not wait for the task to complete before continuing to the next task, but instead will execute the next task immediately.

So in your case, the AlamoFire.request is executed, and while it's running, the next line after the block is immediately run which is the line to return leagueId which will obviously still be equal to zero since the AlamoFire.request task (function) has not yet finished.

This is why you need to use a closure. A closure will allow you to return the value, after AlamoFire.request (or any other asynchronous task for that matter) has finished running. Manav's answer above shows you the proper way to do this in Swift. I just thought I'd help you understand why this is necessary.

Hope this helps somewhat!

Edit:

Manav's answer above is actually partially correct. Here's how you make it so you can reuse that value the proper way.

var myLeagueId = 0;
getLeagueId(country: "brazil", season: "2019",success: { (leagueId) in

// leagueId is the value returned from the closure
myLeagueId = leagueId
print(myLeagueId)
})

The code below will not work because it's setting myLeagueId to the return value of getLeagueId and getLeagueId doesn't have a return value so it won't even compile.

myLeagueId = getLeagueId(country: "brazil", season: "2019",success: { (leagueId) in
print(leagueId)
})

Add explicit type to flatmap

You didn't provide a whole lot of information about the classes involved so I mocked something up to create the playground example below.

The bit that I have added is in the closure of the flatmap operator. Basically I told the compiler what type that closure will return using the fragment input -> Future<[String], Error>. To come up with that line I had to know the return type of StorageManager.shared.saveAll(items: input) so I used the value my mocked up sample returns.

Your return value may be different.

import Foundation
import Combine

class StorageManager {
static let shared = StorageManager()

init() {
}

func saveAll(items: [String]) -> Future<[String], Error> {
Future<[String], Error> { fulfill in
fulfill(.success(items))
}
}
}

struct NetworkManager {
static func getAll(path: String) -> Future<[String], Error> {
Future<[String], Error> { fulfill in
fulfill(.success(["Duck", "Cow", "Chicken"]))
}
}
}

let path : String = "some path"
let publisher : AnyPublisher<[String], Error> =
NetworkManager.getAll(path: path)
.flatMap { input -> Future<[String], Error> in

if path == "menus" {
print("It's a menu")
}

return StorageManager.shared.saveAll(items: input)
}
.eraseToAnyPublisher()

compactMap() closure fails when adding irrelevant NOP declaration?

If you have a one line closure there's an implicit return, so the first one is returning lineText which is of type string. See "Functions With an Implicit Return" at https://docs.swift.org/swift-book/LanguageGuide/Functions.html

The second one doesn't actually return anything, once it is more than one line, there is no implicit return. So the return type is Void which is also spelled as the empty tuple, () and that's what you get there.

You need to say return lineText explicitly if you mean to return something.

This function:

{ idx, lineText in
let _ : String
lineText // This line evaluates the value of lineText and does nothing with the result
}

does not return a value. Any function that doesn't return a value returns a Void value. Void is a type with only one possible value, called (). Mapping to void is a pointless thing to do. Even if your function did a side effect, like printing something, it wouldn't be good style to use map just for side effects.

You can guard against this kind of mistake by being more explicit about the return type in the closure

{ idx, lineText -> String in ... }


Related Topics



Leave a reply



Submit