StringLiteralConvertible protocol question


(Lo√Įc Lecrenier) #1

Hi :slight_smile:

I have been trying to understand the StringLiteralConvertible protocol, but there is something that I still can’t explain.

//-----------------------------

extension Int : UnicodeScalarLiteralConvertible {
    public init(unicodeScalarLiteral value: UnicodeScalar) {
        self = 1
    }
}

extension Int : ExtendedGraphemeClusterLiteralConvertible {
    public init(extendedGraphemeClusterLiteral value: Character) {
        self = 2
    }
}

extension Int : StringLiteralConvertible {
    public init(stringLiteral value: String) {
        self = 3
    }
}

let a : Int = "\u{65}" // e
let b : Int = "\u{65}\u{0301}" // é
let c : Int = “hello"

//-----------------------------

If I only write the first extension: I can only initialize a, and its value will be 1.
If I write the first two extensions: I can initialize a and b, and their values will be 2.
And if I keep the three extensions: a, b, and c will all have a value of 3.

So it seems like the compiler prefers calling the initializer from (in order of preference):
1. StringLiteralConvertible
2. ExtendedGraphemeClusterLiteralConvertible
3. UnicodeScalarLiteralConvertible

But for something to be StringLiteralConvertible, it needs to be ExtendedGraphemeClusterLiteralConvertible and UnicodeScalarLiteralConvertible, which means I have to define two initializers that will never be called.

Is that correct?
Is there a way to write something that is a unicode scalar literal, but not a string literal?

Thank you,

Lo√Įc


(Zhao Xin) #2

But for something to be StringLiteralConvertible, it needs to be
ExtendedGraphemeClusterLiteralConvertible and
UnicodeScalarLiteralConvertible, which means I have to define two
initializers that will never be called.

Yes. Because
‚ÄčStringLiteralConvertible inherits
from ExtendedGraphemeClusterLiteralConvertible,
ExtendedGraphemeClusterLiteralConvertible
inherits from
UnicodeScalarLiteralConvertible.
‚Äč

Is there a way to write something that is a unicode scalar literal, but not

a string literal?

‚ÄčYes. You have already done it by ‚Äčextension UnicodeScalarLiteralConvertible
only. String literal is what people read. Unicode is something string
encoding to store in computer and the computer read.

for example:

let uScalar = "a".unicodeScalars.first! // 97
print(uScalar.dynamicType) // UnicodeScalar. NOT an Int

···

On Mon, Jan 11, 2016 at 4:54 AM, Lo√Įc Lecrenier <swift-users@swift.org> wrote:

Hi :slight_smile:

I have been trying to understand the StringLiteralConvertible protocol,
but there is something that I still can’t explain.

//-----------------------------

extension Int : UnicodeScalarLiteralConvertible {
    public init(unicodeScalarLiteral value: UnicodeScalar) {
        self = 1
    }
}

extension Int : ExtendedGraphemeClusterLiteralConvertible {
    public init(extendedGraphemeClusterLiteral value: Character) {
        self = 2
    }
}

extension Int : StringLiteralConvertible {
    public init(stringLiteral value: String) {
        self = 3
    }
}

let a : Int = "\u{65}" // e
let b : Int = "\u{65}\u{0301}" // é
let c : Int = “hello"

//-----------------------------

If I only write the first extension: I can only initialize a, and its
value will be 1.
If I write the first two extensions: I can initialize a and b, and their
values will be 2.
And if I keep the three extensions: a, b, and c will all have a value of 3.

So it seems like the compiler prefers calling the initializer from (in
order of preference):
1. StringLiteralConvertible
2. ExtendedGraphemeClusterLiteralConvertible
3. UnicodeScalarLiteralConvertible

But for something to be StringLiteralConvertible, it needs to be
ExtendedGraphemeClusterLiteralConvertible and
UnicodeScalarLiteralConvertible, which means I have to define two
initializers that will never be called.

Is that correct?
Is there a way to write something that is a unicode scalar literal, but
not a string literal?

Thank you,

Lo√Įc

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--

Owen Zhao


(Lo√Įc Lecrenier) #3

Yes. Because ‚ÄčStringLiteralConvertible inherits from ExtendedGraphemeClusterLiteralConvertible, ExtendedGraphemeClusterLiteralConvertible inherits from UnicodeScalarLiteralConvertible.‚Äč

Yes, I know. But I wonder why that is, considering that something that is StringLiteralConvertible will seemingly never use the required initializer from UnicodeScalarLiteralConvertible.

Is there a way to write something that is a unicode scalar literal, but not a string literal?
‚ÄčYes. You have already done it by ‚Äčextension UnicodeScalarLiteralConvertible only. String literal is what people read. Unicode is something string encoding to store in computer and the computer read.

for example:

let uScalar = "a".unicodeScalars.first! // 97
print(uScalar.dynamicType) // UnicodeScalar. NOT an Int

Sorry, I am not sure what this answers :frowning:

I wanted to know if there was a way to write something like (for example) uscalar‚ÄĚ\u{65}‚ÄĚ, that would only be a unicode scalar literal, and not a string literal. Or if there was any other way to tell the compiler ‚Äúplease use the initializer from UnicodeScalarLiteralConvertible instead of the one from StringLiteralConvertible‚ÄĚ.

I guess the more fundamental question I wanted to ask was ‚Äúwhy must StringLiteralConvertible conform to UnicodeScalarLiteralConvertible?‚ÄĚ

Thanks,
Lo√Įc

···

On Mon, Jan 11, 2016 at 4:54 AM, Lo√Įc Lecrenier <swift-users@swift.org> wrote:
Hi :slight_smile:

I have been trying to understand the StringLiteralConvertible protocol, but there is something that I still can’t explain.

//-----------------------------

extension Int : UnicodeScalarLiteralConvertible {
    public init(unicodeScalarLiteral value: UnicodeScalar) {
        self = 1
    }
}

extension Int : ExtendedGraphemeClusterLiteralConvertible {
    public init(extendedGraphemeClusterLiteral value: Character) {
        self = 2
    }
}

extension Int : StringLiteralConvertible {
    public init(stringLiteral value: String) {
        self = 3
    }
}

let a : Int = "\u{65}" // e
let b : Int = "\u{65}\u{0301}" // é
let c : Int = “hello"

//-----------------------------

If I only write the first extension: I can only initialize a, and its value will be 1.
If I write the first two extensions: I can initialize a and b, and their values will be 2.
And if I keep the three extensions: a, b, and c will all have a value of 3.

So it seems like the compiler prefers calling the initializer from (in order of preference):
1. StringLiteralConvertible
2. ExtendedGraphemeClusterLiteralConvertible
3. UnicodeScalarLiteralConvertible

But for something to be StringLiteralConvertible, it needs to be ExtendedGraphemeClusterLiteralConvertible and UnicodeScalarLiteralConvertible, which means I have to define two initializers that will never be called.

Is that correct?
Is there a way to write something that is a unicode scalar literal, but not a string literal?

Thank you,

Lo√Įc

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--

Owen Zhao


(Zhao Xin) #4

> Yes. Because ‚ÄčStringLiteralConvertible inherits from
ExtendedGraphemeClusterLiteralConvertible,
ExtendedGraphemeClusterLiteralConvertible inherits from
UnicodeScalarLiteralConvertible.‚Äč

Yes, I know. But I wonder why that is, considering that something that is
StringLiteralConvertible will seemingly never use the required initializer
from UnicodeScalarLiteralConvertible.

I don't know it
‚Äčeither. Maybe it is because when you convert a String to Unicode, you will
need the other two init()s. As you examples show, there maybe one or two
Ints to make one Character.

let a : Int = "\u{65}" // e

let b : Int = "\u{65}\u{0301}" // é

let c : Int = “hello"

I wanted to know if there was a way to write something like (for example)

uscalar‚ÄĚ\u{65}‚ÄĚ, that would only be a unicode scalar literal, and not a
string literal. Or if there was any other way to tell the compiler “please
use the initializer from UnicodeScalarLiteralConvertible instead of the
one from StringLiteralConvertible‚ÄĚ.

I guess the more fundamental question I wanted to ask was “why must

StringLiteralConvertible conform to UnicodeScalarLiteralConvertible?‚ÄĚ‚Äč

‚ÄčFor "\u{65}" , in your words, you call it a Unicode Scalar Literal. But in
formal, it is a String Literal that include special characters.

String literals can include the following special characters:

   -

   The escaped special characters \0 (null character), \\ (backslash), \t (horizontal
   tab), \n (line feed), \r(carriage return), \" (double quote) and \' (single
   quote)
   -

¬†¬†¬†An arbitrary Unicode scalar, written as \u{*n*}, where *n* is a 1‚Äď8
   digit hexadecimal number with a value equal to a valid Unicode code point

‚ÄčIf you want to use a UnicodeScalar, you should use struct UnicodeScalar
<https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_UnicodeScalar_Structure/>‚Äč.
Here are the examples.

let uScalar = "a".unicodeScalars.first! // 97
print(uScalar.dynamicType) // UnicodeScalar, not an Int

extension UInt32 {
    func hex() -> String {
        return String(format:"0x%2X", self)
    }
}

var aUnicodeScalar = UnicodeScalar(97)
print(aUnicodeScalar.value) //97

aUnicodeScalar = UnicodeScalar(0x61)
print(aUnicodeScalar.value) //97
print(aUnicodeScalar.value.hex()) //0x61

aUnicodeScalar = UnicodeScalar("a")
print(aUnicodeScalar.value) //97

aUnicodeScalar = UnicodeScalar("e")
print(aUnicodeScalar.value.hex()) // 0x65

aUnicodeScalar = UnicodeScalar("é")
print(aUnicodeScalar.value.hex()) // 0xE9

aUnicodeScalar = UnicodeScalar("\u{65}")
print(aUnicodeScalar.value.hex()) // 0x65

// aUnicodeScalar = UnicodeScalar("\u{65}\u{0301}")
// above doesn't work as there are two characters instead of one
// struct UnicodeScalar only conforms UnicodeScalarLiteralConvertible

extension UnicodeScalar:ExtendedGraphemeClusterLiteralConvertible {
    public init(extendedGraphemeClusterLiteral value: String) {
        self = String(value.characters.first!).unicodeScalars.first!
    }
}

aUnicodeScalar = UnicodeScalar(extendedGraphemeClusterLiteral:
"\u{65}\u{0301}")
print(aUnicodeScalar.value.hex()) // 0x65

zhaoxin

···

On Mon, Jan 11, 2016 at 10:08 PM, Lo√Įc Lecrenier <loiclecrenier@icloud.com> wrote:

> Yes. Because ‚ÄčStringLiteralConvertible inherits from
ExtendedGraphemeClusterLiteralConvertible,
ExtendedGraphemeClusterLiteralConvertible inherits from
UnicodeScalarLiteralConvertible.‚Äč

Yes, I know. But I wonder why that is, considering that something that is
StringLiteralConvertible will seemingly never use the required initializer
from UnicodeScalarLiteralConvertible.

> Is there a way to write something that is a unicode scalar literal, but
not a string literal?
> ‚ÄčYes. You have already done it by ‚Äčextension
UnicodeScalarLiteralConvertible only. String literal is what people read.
Unicode is something string encoding to store in computer and the computer
read.
>
> for example:
>
> let uScalar = "a".unicodeScalars.first! // 97
> print(uScalar.dynamicType) // UnicodeScalar. NOT an Int

Sorry, I am not sure what this answers :frowning:

I wanted to know if there was a way to write something like (for example)
uscalar‚ÄĚ\u{65}‚ÄĚ, that would only be a unicode scalar literal, and not a
string literal. Or if there was any other way to tell the compiler “please
use the initializer from UnicodeScalarLiteralConvertible instead of the one
from StringLiteralConvertible‚ÄĚ.

I guess the more fundamental question I wanted to ask was “why must
StringLiteralConvertible conform to UnicodeScalarLiteralConvertible?‚ÄĚ

Thanks,
Lo√Įc

>
> On Mon, Jan 11, 2016 at 4:54 AM, Lo√Įc Lecrenier <swift-users@swift.org> > wrote:
> Hi :slight_smile:
>
> I have been trying to understand the StringLiteralConvertible protocol,
but there is something that I still can’t explain.
>
> //-----------------------------
>
> extension Int : UnicodeScalarLiteralConvertible {
> public init(unicodeScalarLiteral value: UnicodeScalar) {
> self = 1
> }
> }
>
> extension Int : ExtendedGraphemeClusterLiteralConvertible {
> public init(extendedGraphemeClusterLiteral value: Character) {
> self = 2
> }
> }
>
> extension Int : StringLiteralConvertible {
> public init(stringLiteral value: String) {
> self = 3
> }
> }
>
> let a : Int = "\u{65}" // e
> let b : Int = "\u{65}\u{0301}" // é
> let c : Int = “hello"
>
> //-----------------------------
>
> If I only write the first extension: I can only initialize a, and its
value will be 1.
> If I write the first two extensions: I can initialize a and b, and their
values will be 2.
> And if I keep the three extensions: a, b, and c will all have a value of
3.
>
> So it seems like the compiler prefers calling the initializer from (in
order of preference):
> 1. StringLiteralConvertible
> 2. ExtendedGraphemeClusterLiteralConvertible
> 3. UnicodeScalarLiteralConvertible
>
> But for something to be StringLiteralConvertible, it needs to be
ExtendedGraphemeClusterLiteralConvertible and
UnicodeScalarLiteralConvertible, which means I have to define two
initializers that will never be called.
>
> Is that correct?
> Is there a way to write something that is a unicode scalar literal, but
not a string literal?
>
> Thank you,
>
> Lo√Įc
>
>
>
>
>
>
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
>
>
> --
>
> Owen Zhao

--

Owen Zhao