Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function to safely assign an optional to a var, or assign default if nil: Could not cast value of type 'Swift.Int' to 'Swift.String'

Hey there!


. . I'm breaking bad once again asking for help--hopefully this code + any possible answers will help the community.

. . So I'm trying to make a method that allows me to safely assign optionals to the lhs, such as:

var cool_variable = risky_optional!,

without necessarily interrupting the flow of whichever scope it's in.. the point of this is to cut down on control statements, and to not crash the program immediately on a forced unwrap (which I spend much time trying to design good code that doesn't do this naturally).

. . At first, I thought I had succeeded, because everything was working perfect... then on my fourth round of tests, I got a

Could not cast value of type 'Swift.Int' (0x105c52190) to 'Swift.String' (0x105c584d8).

. . I spent a good bit of time trying to refactor and rework, but I'm realizing that my understanding on generics, Any, and optionals just isn't concrete yet--though I do study and practice, every now and then I try to do something that just won't work.

Here's the code:


>> Here's a screenshot of the func, all nice and pretty in XCODE if that's your thing <<

>> And here is the implementation in XCODE <<

/** 
    Safely assign the lhs to this call--the value of $0?, or a default.
    - Don't include ? or ! in the parameter
*/
func safeAssign <ReturnType> (value_to_return: ReturnType?)
 -> ReturnType  {

    // Ensure safety
    guard value_to_return != nil 
    else {

        // Entry: found nil
        print ("SA() -> 1  : SR: $0 was nil! Can't assign to lhs")

        // -Value is irrelevant at this point
        // -switch (value_to_return) would be confusing
        let type = value_to_return

        switch ( type ) {

         case is Int?:
            print("SA() -> 2.1: assigning lhs to default Int >0<")
            return 0 as! ReturnType

         case is String?:
            print("SA() -> 2.2: assigning lhs to default String")
            return "" as! ReturnType

         default:
            // In case our switch breaks, we will know why it crashes
            print("SA() -> 2.0: No cases found--RTE incoming")

        }//switch/>

        // Should force crash, but at least I'll know exactly why
        return type!

    }//guard/>

    // Let's get out of here safely ;)
    print("SA() -> Exit: Successfully Assigned lhs to \(value_to_return!)")
    return value_to_return!

}//safeAssign/>

//---------
// Testing:
//--------

// Optional for test 1-2
var int_opty : Int? = 5

// Soon to be safe-assigned
var zizzle = 0

// Safe assign to 5
print ("\n SA Test 1:")
zizzle = safeAssign(int_opty)

// Will cause a non-safe-assignment to force unwrap nil
int_opty = nil

// Safely assign to default value, instead of unwrapping nil
print ("\n SA Test2:")
 zizzle = safeAssign(int_opty)
  print(">>>>>>>>>> Zizzle is \(zizzle)")

// Optional for test 3-4
var str_opty : String? = "five"

// Soon to be safe-assigned
var zazzle = "zero"

// Safe assign to 5
print ("\n SA Test 3:")
 zazzle = safeAssign(str_opty)

// Will cause a non-safe-assignment to force unwrap nil
str_opty = nil

// Safely assign to default value, instead of unwrapping nil
print ("\n SA Test 4:")
 zazzle = safeAssign(str_opty)
  print ("3: Zazzle is \(zazzle)")

The output:

 SA Test 1:
SR -> Exit: Successfully Assigned lhs to 5

 SA Test2:
SR -> 1  : SR: $0 was nil! Can't assign to lhs
SR -> 2.1: assigning lhs to default Int >0<
>>>>>>>>>> Zizzle is 0

 SA Test 3:
SR -> Exit: Successfully Assigned lhs to five

 SA Test 4:
SR -> 1  : SR: $0 was nil! Can't assign to lhs
SR -> 2.1: assigning lhs to default Int >0<
Could not cast value of type 'Swift.Int' (0x105c52190) to 'Swift.String' (0x105c584d8).

. . So I see where it's hanging up, tried replacing switch with If / Guard statements, tried it with Any, Optional<>, and a couple other approaches that got nowhere... I can't get it to work, and feel that I'd just be beating my head on the keyboard at this point in my knowledge of Swift

. . I don't really need this method, (because I try to be a good designer, haha), but it's always good to save a bit of whitespace, and if I use this for most of my assignments, then should a small bug pop up later, it's possible it could correct itself (say in a while loop or update cycle) instead of crashing the program.

. . That, and even though I'm sure something with Try/Catch could work...I want to figure out why this won't run so I can learn and be a better coder.

Thanks much.

Peace and blessings! -Fluid

like image 700
Fluidity Avatar asked Oct 18 '22 03:10

Fluidity


1 Answers

Actually you don't need a method for this, just do:

zazzle = str_opty ?? ""

Easy!

I don't really know why your method fails to do the job. But I think it's better to switch ReturnType.self:

switch ReturnType.self {

case is Int.Type:
    print("SR -> 2.1: assigning lhs to default Int >0<")
    return 0 as! ReturnType

case is String.Type:
    print("SR -> 2.2: assigning lhs to default String")
    return "" as! ReturnType

default:
    // In case our switch breaks, we will know why it crashes
    print("SR -> 2.0: No cases found--RTE incoming")

}

EDIT:

I now found out why your method did not work! Consider the following code

func f<T>(x: T?) {
    print(x is Bool?)
    print(x is Int?)
    print(x is NSNumberFormatter?)
    print(x is NSURLSessionDelegate?)
}

let a: String? = nil
f(a)

Guess what it prints?

true
true
true
true

It seems like that nil is every optional type, no matter whether it is a struct, a class, or a protocol. If you think about this, it actually makes sense. nil can be assigned to any optional type, right?

like image 186
Sweeper Avatar answered Oct 21 '22 04:10

Sweeper