Why ReturnType is not working in this Swift function? - swift

I am working with Swift 5, in Xcode 10.2.1
I have this function inside of an extension of UInt8
The compiler complains in line 5, with Unexpected non-void return value in void function
The return type is properly defined, and if the line return "\(opCode)" is commented, it works fine, with the return in the last line return "\(OpCode.NOP) I am using "\(OpCode.NOP)" to avoid adding another variable to the enum, but is a regular string
The error continues if I change the line to return "", so it has nothing to do with the OpCode enum.
extension UInt8 {
func opCode() -> String {
OpCode.allCases.forEach { opCode in
if self == opCode.uint8 {
return "\(opCode)" //Unexpected non-void return value in void function
//return "" // Error persists
}
}
return "\(OpCode.NOP)"
}
}

You can't return a value inside void return type of the forEach instead try
extension UInt8 {
func opCode() -> String {
if let item = OpCode.allCases.first(where:{ self == $0.uint8 }) {
return "\(item)"
}
return "\(OpCode.NOP)"
}
}

Related

Missing return in global function expected to return 'String' message in a function

I know this error is a common message and has already been the subject of many posts. However, as a pure beginner who just started days ago, I can't really understand the solution on other posts, and also haven't learned what Switch means. Thefore, that solution can't be used with me. Here's my block code getting the error :
func responseTo(question: String) -> String {
let lowercasedQuestion = question.lowercased()
if lowercasedQuestion.hasPrefix("hello") {
if lowercasedQuestion.hasPrefix("Hello") {
return "Why, hello there!"
} else if lowercasedQuestion.hasPrefix("where") {
if lowercasedQuestion.hasPrefix("Where") {
return "To the North"
} else {
return "Where are the cookies?"
}
}
}
}
I tried to put the last else outside the first if since I read it could change the output and remove the error, but it didn't change anything. I tried to enter return nil on the last line, but had an error. What can I do? Any answer appreciated.
Your responseTo(String) -> String function must return a String. You must consider this case, if the parameter (question) doesn't start with "hello", the function doesn't have any String to return.
let result: String = responseTo("asd") // error
As stated in the comments, there are several ways to solve this.
If your function must return a string, then consider returning a default value at the end. The return value can be an empty string (but whatever your default value is, make sure to handle it properly).
func responseTo(question: String) -> String {
let lowercasedQuestion = question.lowercased()
if lowercasedQuestion.hasPrefix("hello") {
//
} else {
return "" // this will be the default return value
}
}
or
func responseTo(question: String) -> String {
let lowercasedQuestion = question.lowercased()
if lowercasedQuestion.hasPrefix("hello") {
//
}
return "" // this will also be the default return value
}
Another way is to return an Optional String (String?). The reason why return nil doesn't work for responseTo(String) -> String is because it must return a string. To be able to return a nil, you will have to change the declaration of your function to responseTo(String) -> String?.
func responseTo(question: String) -> String? { // the "?" after String notifies the compiler that this function can return a String or a nil
let lowercasedQuestion = question.lowercased()
if lowercasedQuestion.hasPrefix("hello") {
//
}
return nil
}
you can read more about function here and optional here

Are `return nil` and `return` interchangeable?

I don't completely understand, can I use return and return nil interchangeably? Are return and return nil similar return type?
Here are two instances of a code.
1st instance:
func naming(name: Int) -> String? {
switch name {
case 0: return "Neo"
case 1: return "Matrix"
default: return nil
}
}
naming(name: 2) // nil
2nd instance:
guard let video = try? avplayer else {
print("Unable to load a movie")
return
}
Nope they're not the same.
Returning nil is used when you need to return a value but that value can be optional. So in your example:
func naming(name: Int) -> String? {
switch name {
case 0: return "Neo"
case 1: return "Matrix"
default: return nil
}
}
The function is expecting a String OR a nil value to be returned, hence String?. The question mark on the end indicates that the String is optional. When you call naming(name: 2) that calls the switch statement and doesn't find a value corresponding to the number 2, so defaults to returning nil.
Putting return like in your second example just stops the rest of the function from executing. So:
function loadVideo() {
guard let video = try? avplayer else {
print("Unable to load a movie")
return
}
print("hello")
}
If the avplayer variable is nil then the guard statement will execute its else statement and print out Unable to load a movie then return from the function. This will prevent hello from being printed.
No both are not the same!
return without any argument returns Void. This form of the return statement can only be used with a function that returns Void.
Once the return statement executes, the function exits and no more code in your function executes.
simple answer to your question is NO
in your example
func naming(name: Int) -> String? /* reference */ {
switch name {
case 0: return "Neo"
case 1: return "Matrix"
default: return nil
}
}
/* reference */
you are expected to return optional String here this could be string value or nil
if you decided to return only without value you will get compilation error
in the second example I would like you to imagine that this is a void function to understand it more clearly
func naming(name: Int) {
switch name {
case 0: return "Neo" /* reference */
case 1: return "Matrix" /* reference */
default: return nil /* reference */
}
}
you should be getting compilation error on /* reference */ if you tried to return any value from this function and you could return at any time without any value depending on your business
so consider the guard let is a void function for safety swift does check the value for you if it has a value it will make the value /* video */ available in the next lines else it will return from the function and will not execute the rest of the function code

Nested do catch swift 3.0

I'd like to use consecutive try statements. If one returns an error I'd like to proceed to the next one, otherwise return the value.
The code below seems to work fine, however I'll end up with a big nested do catch pyramid. Is there a smarter/better way to do it in Swift 3.0?
do {
return try firstThing()
} catch {
do {
return try secondThing()
} catch {
return try thirdThing()
}
}
If the actual errors thrown from those function calls are not needed
then you can use try? to convert the result to an optional,
and chain the calls with the nil-coalescing operator ??.
For example:
if let result = (try? firstThing()) ?? (try? secondThing()) ?? (try? thirdThing()) {
return result
} else {
// everything failed ...
}
Or, if the error from the last method should be thrown if everything fails,
use try? for all but the last method call:
return (try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing())
If Martin's answer is too terse for your taste you can just go with individual catch blocks.
do {
return try firstThing()
} catch {}
do {
return try secondThing()
} catch {}
do {
return try thirdThing()
} catch {}
return defaultThing()
As each throwing function's result is immediately returned no nesting is necessary.
Another way to do this is to write a function that takes all your throwing functions as an argument. It returns the first one that was successfully executed or nil.
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
The lazy ensures that the values are only called until it finds the first match. Doing it this way, you can also add a lot of cases very quickly.
You can use the function like this
return first(firstThing, secondThing, thirdThing) ?? "Default"
I also included the code I used to test this in playground:
enum ThingError: Error {
case zero
}
func firstThing() throws -> String {
print("0")
throw ThingError.zero
return "0"
}
func secondThing() throws -> String {
print("1")
return "1"
}
func thirdThing() throws -> String {
print("2")
return "B"
}
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
func tryThings() -> String {
return first(firstThing, secondThing, thirdThing) ?? "Default"
}
tryThings() // prints "0" and "1"

Can not call value of non function type

I am getting error can not call value of non function type. Whats wrong in this ?
extension FileModel {
var isPlayableMedia: Bool {
get {
return isPlayableMedia(mediaType: mediaType)
}
}
func isPlayableMedia(_ mediaType: MediaType) -> Bool {
return mediaType == MediaType.image || mediaType == MediaType.video
}
}
Either remove the label parameter when the method is called
var isPlayableMedia: Bool {
return isPlayableMedia(mediaType) // assuming `mediaType` is declared somewhere else.
}
Or specify the label parameter in the declaration (remove the underscore)
func isPlayableMedia(mediaType: MediaType) -> Bool {
return mediaType == MediaType.image || mediaType == MediaType.video
}
Nothing much just check your function signature and use it in right way.
replace your var with the following code :
var isPlayableMedia: Bool {
get {
return isPlayableMedia(mediaType)
}
}
OR
just remove the argument label from you method calling

"Missing return in a closure expected to return 'SomeType'" error in .map

I have the fallowing code:
struct AInt {
var aInt: Int
}
struct ADouble {
var aDouble: Double
static func convert(aInt: AInt) throws -> ADouble {
return ADouble(aDouble: Double(aInt.aInt))
}
}
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
}
// ^^^ error here: Missing return in a closure expected to return 'ADouble'
}
}
let aInts = [AInt(aInt: 2), AInt(aInt: 3)]
let b = B()
do {
print(try b.doAction(aInts))
}
catch {}
When i'm trying to convert [AInt] to [ADouble] in .map using function that can throw error, i get this error:
Missing return in a closure expected to return 'ADouble'.
Well, i decided to add return statement in the end of .map like this:
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
Error disappear, but when i print try b.doAction(aInts) on same aInts array, i get this: [ADouble(aDouble: 2.2), ADouble(aDouble: 2.2)], i.e. it prints my ADouble(aDouble: 2.2) that i set manually. Obviously, it's not what i want, so then i try to add return before try ADouble.convert(aInt) like this:
return aInts.map { aInt in
do {
return try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
And now i get right result: [ADouble(aDouble: 2.0), ADouble(aDouble: 3.0)]. But this code still doesn't work without return statement in the end of the .map. Any ideas how to get rid of it?
The map() method is declared as
#rethrows public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
which means (if I understand it correctly) that the transform can
either return a value or throw an error (and this will be
forwarded to the caller).
This compiles and works as expected:
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return try aInts.map { aInt in
return try ADouble.convert(aInt)
}
}
}
An error thrown from ADouble.convert(aInt) will be forwarded to
the caller of map() and from there to the caller of doAction().