7
votes

In Swift, I would expect the following to be a perfectly valid code:

let snailCharacter: Character = "????"
let snailString = snailCharacter as String

But apparently, it produces an error:

Cannot convert value of type 'Character' to type 'String' in coercion

Solution to this is to use String initializer like this:

let snailString = String(snailCharacter)

I thought Character is kind of a subset of String, so that surprised me. Why is it forbidden to cast Character to String?

I'm using Swift 4 in Xcode 9 beta 4.

2
A String is a collection of Characters. You cannot cast because that are different types. - Martin R
It's just a design decision, so only who designed Swift Character can explain why. In Swift Standard Library, Character is designed as a completely different thing than String, which has an efficient internal representation for holding a single BMP-character. So, the relationship between Character and String does not match any of the cases where as-casting provided: -- upcasting, bridging, annotating literal types, disambiguating overloaded functions. Int8 can be considered to be sort of a subset of Int16, but you cannot use as-casting to convert Int8 to Int16. - OOPer
Arriving here to address the error, I think the question provided the solution, the answer was just a bonus :) +1 for both! - benc

2 Answers

4
votes

Looking at the documentation, you can see, that Character is just one of the several representations of String in Swift (emphasis added to the relevant parts by me)

A string is a series of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type. The contents of a String can be accessed in various ways, including as a collection of Character values.

In Swift, String is not just an array of Characters unlike in some other languages. In Swift, Character is just a way to represent a String instance in a certain way. Strings can be represented using Views, such as CharacterView, utf8View, etc.

One of the key principles behind the architecture of Swift's String type was Unicode correctness, which is one of the reasons Strings are not just simply an array of Characters.

For more information about the changes to String in Swift4, see the String Manifesto.

To be more specific about why casting doesn't work. There are two kinds of castings, type casting and bridge-casting. Type casting is only possible between classes, where inheritance is involved. You can either upcast a subclass to its superclass, which always succeeds or you can try to downcast a superclass to a subclass, which only works if a subclass instance was first upcasted to its superclass.

It should be quite clear from the above explanation why type casting doesn't work between Character and String, since the neither of the two types inherit from each other.

For bridge casting, this is a method Apple introduced for interoperability between some Swift and Foundation types, such as String and NSString, but since both String and Character are Swift types, bridge casting has nothing to do with this problem either.

-2
votes

First you need a textual representation of that. You can convert to String only the description of a Character like this

let snailCharacter: Character = "🐌"
let snailString = snailCharacter.description as String