34

For example, I have the following code:

    let numberOfBlocks = 3
    let blockWidth = SKSpriteNode(imageNamed: "image.png").size.width
    let padding = 20.0

    let offsetX : Float = (self.frame.size.width - (blockWidth * numberOfBlocks + padding * (numberOfBlocks-1))) / 2

I got the error:

'Double' is not convertible to 'UInt8'

Is there a way to implicitly convert the data type (maybe only for primitive data type)?

Edit:

I know how to do the explicit conversion by using constructor of particular type as Iducool suggested. But it's not a big help to my question because we even don't know where to add the conversions. I simplified my expression in playground:

enter image description here

The problem is in "padding" variable, the error message is

'Double' is not convertible to 'UInt8'.

So I did the conversion:

enter image description here

Then the problem is in "blockWidth" variable now.

I added the conversion again:

enter image description here

And error message is:

Type 'UInt8' does not conform to protocol 'FloatLiteralCovertible'

The final working expression is:

enter image description here

Is it simple and swift? I don't think so.

Community
  • 1
  • 1
Bagusflyer
  • 12,675
  • 21
  • 96
  • 179
  • 4
    Apple is very explicit that there is no implicit type conversion in Swift, and has been fairly public and explicit about why as well. Eliminating implicit type conversion removes at least one common (and potentially difficult to find) class of errors. – David Berry Jul 09 '14 at 05:51
  • 2
    @David There are many implicit type conversion in Swift Foundation framework. e.g. `Array`/`NSArray`, `Int`/`NSNumber`. – Bryan Chen Jul 09 '14 at 05:54
  • 3
    At least in the case of Array/NSArray they aren't converted, they're bridged. An Array IS an NSArray, it has an isa slot and everything. The same with the other Foundation bridging that happens. And even then, in most cases you wind up having to explicitly cast it to make it useful. In the case of Int/NSNumber it's done only in very specific semantic cases, and, like much of the ugliness of Swift, is because of trying to maintain Objective-C compatibility. In many ways it looks like they had a nice clean language and then decided to graft Objective-C compatibility onto it. – David Berry Jul 09 '14 at 06:01
  • 2
    I edited this question to remove the highly subjective language from the title and body — the question itself is fine, but I would recommend staying away from wording that seems provocative. – jtbandes Jul 09 '14 at 06:17
  • 2
    I love swift become the syntax is neat and simple so that I can write elegant code for complicated case. But for such a simple case, Swift make it so difficult. I'm not saying the implicit conversion is good for all the cases. But it will make programmer's life easier if it supports implicit conversion at least for primitive data type. – Bagusflyer Jul 09 '14 at 07:11
  • 2
    The idea of Swift is not to make programmer's life easier by allowing them to write possibly broken code. It makes life easier by forcing you to write code that is definitely correct. – gnasher729 Aug 06 '14 at 12:06
  • 1
    "But it will make programmer's life easier if it supports implicit conversion at least for primitive data type" is betraying your lack of experience. Please trust my 20+ years of C++ programming that you do NOT want implicit conversion of primitives. – Andy Dent Jun 24 '15 at 03:00
  • 1
    @bagusflyer i agree with you. Errors like `'Float' is not convertible to 'Double'` make no sense no matter what reasons or philosophy anyone would suggest. – user1244109 Oct 14 '15 at 09:56
  • @AndyDent not questioning your experience, but swift and C++ are different animals; so you can't really apply all that experience onto swift - wouldn't you agree? Maybe in few years we'll see, but now... I dont have 20 years of programming behind me, but i never had implicit conversion problems in objective-c, and i dont know anyone who did. – user1244109 Oct 14 '15 at 10:03
  • String is implicitly converted to Selector – nielsbot Feb 19 '16 at 23:58

4 Answers4

37

There is no implicitly cast in Swift.

Easy way of conversion in swift is using constructor of particular type.

Like if you want to get Float from double then you can use Float(doubleValue) and Same way if you want to convert float to integer then you can use Int(floatValue).

In your case:

let intValue = UInt8(doubleValue)

Beware that you will lose any value after the decimal point. So, choose a better way. Above conversion is just to help you in understanding.

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

devios1
  • 36,899
  • 45
  • 162
  • 260
Iducool
  • 3,543
  • 2
  • 24
  • 45
  • 3
    The last sentence is very important hint so that I normally use Double as the data type in SpriteKit to simplify the conversion. By the way, CGFloat is Double instead of Float. – Bagusflyer Jul 09 '14 at 08:47
  • You might be able to get away with your objective by using the "ExpressibleBy...Literal" protocols such as `ExpressibleByStringLiteral`. See [this answer](https://stackoverflow.com/a/69298077/35690) for more info. – Senseful Oct 02 '22 at 20:41
26

Swift doesn't support implicitly cast anymore in Xcode6 GM. Following answer only apply to Xcode6 beta version.


I don't want to talk about implicitly cast is good or bad, but you can have it if you really want with __conversion()

e.g. If you need UInt8 and Int be able to convert from Double

extension Double {
    func __conversion() -> UInt8 { return UInt8(self) }
    func __conversion() -> Int { return Int(self) }
    // add more if you need to
}

xcrun swift
Welcome to Swift!  Type :help for assistance.
  1> extension Double {
  2.     func __conversion() -> UInt8 { return UInt8(self) }
  3. }
  4> var d = 1.0
d: Double = 1
  5> var u8 : UInt8 = d
u8: UInt8 = 1
  6>

Note: I won't put this in my production code. I only want to point out it if possible but not recommending it.

Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • 2
    Great find, but I bet this won't be possible in Swift 1.0 (or if it is, it might be but with a less privatey API). I would love to be able to do it though; a powerful feature when used with extreme care and moderation. – Form Aug 19 '14 at 16:04
  • Although it's not exactly implicit conversion, you might be able to get away with using something like [ExpressibleByIntegerLiteral](https://developer.apple.com/documentation/swift/expressiblebyintegerliteral) instead. See [this answer](https://stackoverflow.com/a/69298077) for more info. – Senseful Oct 02 '22 at 20:44
2

using bridgeToObjectiveC() method you can call the methods provided in Objective - C to convert from one primitive data type to another for e.g.

variable_name.bridgeToObjectiveC().intValue

will convert that variable named variable_name to integer

Raj
  • 413
  • 1
  • 4
  • 5
  • 8
    At least thank you for not suggesting converting to string and back. – hamstergene Jul 09 '14 at 05:36
  • 1
    The question was about implicit conversion within expressions, e.g. from `Double` to `Int`. Your answer is only remotely related to this - but may be useful in other contexts ;) – CouchDeveloper Jul 09 '14 at 05:41
1

Implicit conversion is possible but with literals only and some conversions are available from the box e.g. Int -> Double:

let a = 3 // Int
let b = 100.5 // Double

// Doesn't work with variables
let c = a * b // Error: Binary operator '*' cannot be applied to operands of type 'Int' and 'Double'

// But this works, because Int(3) literal converts to Double(3.0) implicitly
let d = 3 * b // 301.5

If you want to make backward conversion Double -> Int you should extend Int with ExpressibleByFloatLiteral:

extension Int: ExpressibleByFloatLiteral {
    public init(floatLiteral value: Double) {
        self.init(value)
    }
}

// Double(100.5) converts to Int(100)
let e = a * 100.5 // 300

Even more it's possible to implicitly convert to any type from literals, for instance String -> URLRequest:

extension URLRequest: ExpressibleByStringLiteral {
    public init(stringLiteral value: String) {
        self.init(url: URL(string: value)!)
    }
}

let request: URLRequest = "https://www.google.com"
iUrii
  • 11,742
  • 1
  • 33
  • 48
  • There are other types like this, e.g. for [dictionaries](https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral) or [arrays](https://developer.apple.com/documentation/swift/expressiblebyarrayliteral). – Senseful Oct 02 '22 at 20:39