Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why let x as Float case is not matching in a switch on a Any variable?

Tags:

swift

swift3

I have an enum for tagged values (this is from a toy Scheme interpreter project), like this:

enum Value {
  case int(Int)
  case float(Float)
  case bool(Bool)
  ...
}

I wrote an initializer for it:

init?(value:Any) {
  switch v {
    case let v as Int: self = .int(v)
    case let v as Float: self = .float(v)
    case let v as Bool: self = .bool(v)
    ...
    default: return nil
  }
}

With that, calling Value(3) returns an (optional) Value.int(3), as expected. Bool's and the other types work too.

But Value(0.1) hits the default case and returns nil.

(Edited for correctness and recommended style. Thank you everyone for pointing those issues out.)

like image 535
Dietrich Avatar asked Nov 30 '16 07:11

Dietrich


People also ask

Why float is not allowed in switch?

Explanation: The switch/case statement in the c language is defined by the language specification to use an int value, so you can not use a float value. The value of the 'expression' in a switch-case statement must be an integer, char, short, long. Float and double are not allowed.

Can I use float value in switch-case?

Switch case allows only integer and character constants in case expression. We can't use float values.

Can your switch statement accept long double or float data type?

The switch statement doesn't accept arguments of type long, float, double,boolean or any object besides String.


2 Answers

The default inferred type for floating point constants is Double, not Float. It's defined by the swift standard library here: https://developer.apple.com/reference/swift/floatliteraltype using the compiler-known FloatLiteralType typealias.

like image 133
Jack Lawrence Avatar answered Sep 26 '22 02:09

Jack Lawrence


The documentation of type inference says:

Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.

If you want to use Float, you must explicitly cast the literal:

enum Value {
    case Int(Int)
    case Float(Float)
    case Bool(Bool)
    case Double(Double)
    init?(v:Any) {
        switch v {
        case let v as Int: self = .Int(v)
        case let v as Float: self = .Float(v)
        case let v as Bool: self = .Bool(v)
        case let v as Double: self = .Double(v)
        default: return nil
        }
    }
}


Value(v: 0.1) //Infer Double > Result: Double(0.10000000000000001)
Value(v: Float(0.0002)) //Specify Float > Result: Float(0.000199999995)
like image 24
William Hu Avatar answered Sep 26 '22 02:09

William Hu