30672


Swift で以下のように書くと、Bool の文字列表現が得られます。

[code]

    let valueTrue: Bool = true
    "\(valueTrue)" // -> "true"
    
    let valueFalse: Bool = false
    "\(valueFalse)" // -> "false"
    
[/code]

このとき、文字列表現が正確に `"true"` と `"false"` であることが、Swift の言語仕様として定められているでしょうか？
あるいは定められていないでしょうか？

実用上は `let value: Bool` に対して `value ? "true" : "false"`
などと書けば事足りるのですが、言語仕様としてはどうなっているのだろう、というのが気になりました。

Swift 2 および Swift 3 の場合について知りたいです（両者で仕様が異なる可能性があると思いますが、それぞれ知りたいです）。

* * *

質問の書き方が分かりにくかったので補足します。

上記の `"\(valueTrue)"`（これは `valueTrue.description` と同じ）が `"true"`
という文字列になるのは、言語仕様として定められているのか、処理系依存や未定義なのか、というのが知りたい点です。

* * *

※追記：上に「これは `valueTrue.description` と同じ」と書きましたが、いただいた回答を読みますと、適切な記述ではありませんでした。


CC BY-SA 3.0
2016-11-24T14:44:54.553
30656
2016-11-27T11:52:44.353
2016-11-27T11:52:44.353
328
328
question
swift swift2 swift3
Swift の Bool の文字列表現の言語仕様


[Swift Standard Library - structure
Bool](https://developer.apple.com/reference/swift/bool)

このリファレンスにあるように、`Bool`は、構造体（Structure）です。`description`というプロパティを持ち、`"true"`/`"false"`の文字列（String）を返します。文字列中の`\()`という記号は、挿入したインスタンスの`description`を代入する仕様となっています。

[code]

    "\(valueTrue)"
    
[/code]

このコードは、

[code]

    valueTrue.description
    
[/code]

と書くのと同値です。

「Bool の文字列表現」は、プロパティ`description`の事です。

なお、この点は、Swiftのバージョンに関係なく、Swift 1.0から変わりないことを、最後に述べておきます。


CC BY-SA 3.0
2016-11-24T23:54:43.687
30661
2016-11-24T23:54:43.687
18540
30656
answer


**UPDATE**
(正しいとは言えない記述を…なんて始めておきながら不完全で「正しいとは言えない記述」になってしまっていたので修正しました。少し長くなってしまいましたが、
**一般のstructと`Bool`では動作が異なる**あたりをご参照ください。)

本題の「言語仕様として決まっているのか」からは離れたままになってしまいますが、説明を加えておきます。

  * `description`プロパティが定義されていない型でも文字列補間は働きます。
[code]     struct Test {

        var a: Int
    }
    
    let val = Test(a: 1234)
    let str = "\(val)" // => "Test(a: 1234)"
    
[/code]

  * `description`プロパティが定義されていても、それだけでは文字列補間には使われません。
[code]     struct Test2 {

        var a: Int
    
        var description: String { //<- description を実装しただけでは
            return "[Test2 a="+String(a)+"]"
        }
    }
    let val2 = Test2(a: 1234)
    let str2 = "\(val2)" // => "Test2(a: 1234)" <- 文字列補完構文で description は使われない
    
[/code]

  * 明示的に`CustomStringConvertible`を実装した型では`description`が使われます。
[code]     struct Test3: CustomStringConvertible { //<-
CustomStringConvertible を明示的に実装した場合には

        var a: Int
    
        var description: String {
            return "[Test2 a="+String(a)+"]"
        }
    }
    let val3 = Test3(a: 1234)
    let str3 = "\(val3)" // => "[Test2 a=1234]" <- description が使われる
    
[/code]

  * `CustomDebugStringConvertible`を実装している場合には、`description`が実装されていても、(`CustomStringConvertible`への適合が宣言されていないなら)`debugDescription`が優先される。
[code]     struct Test4: CustomDebugStringConvertible { //<-
CustomDebugStringConvertible を明示的に実装した場合には

        var a: Int
    
        var description: String {
            return "[Test2 a="+String(a)+"]"
        }
    
        var debugDescription: String {
            return "Type=Test2, properties: a="+String(a)
        }
    }
    let val4 = Test4(a: 1234)
    let str4 = "\(val4)" // => "Type=Test2, properties: a=1234" <- debugDescriptionが使われる
    
[/code]

なお、文字列補間の細かい動作はSwiftのバージョンによって変遷してきています。過去には`description`プロパティを定義するだけで、文字列補間にその値が使われる、と言う動作をしていたバージョンもあるかもしれませんが、少なくともSwift3ではそのようにはなっていません。

* * *

実は上記の動作は`String.init(describing:)`と全く同じということになります。

[init(describing:)](https://developer.apple.com/reference/swift/string/2427941-init)

>   * If `instance` conforms to the `TextOutputStreamable` protocol, the
> result is obtained by calling `instance.write(to: s)` on an empty  
>  string `s`.
>
> `instance`が`TextOutputStreamable`に適合していれば、`instance.write(to: s)`の結果を返す。
>
>   * If `instance` conforms to the `CustomStringConvertible` protocol, the
> result is `instance.description`.
>
> `instance`が`CustomStringConvertible`に適合していれば、`instance.description`を使う。
>
>   * If `instance` conforms to the `CustomDebugStringConvertible` protocol,
> the result is `instance.debugDescription`.
>
>
> もし`instance`が`CustomDebugStringConvertible`に適合していれば、`instance.debugDescription`を使う。
>
>   * An unspecified result is supplied automatically by the Swift standard
> library.
>
> Swiftの標準ライブラリが、仕様化されていない結果を自動的に返す。
>
>

(非常に似たものとして、[`String.init(reflecting:)`](https://developer.apple.com/reference/swift/string/1541282-init)と言うのがあります。文字列補間がどちらに当たるのか、ぜひご自身でPlaygroundなどの上で確かめてください。)

* * *

上記の説明が`Bool`にもあてはまるなら`TextOutputStreamable`に適合させれば文字列補間の結果も変わるはずだ…ということでやってみましょう。

[code]

    extension Bool: TextOutputStreamable {
        public func write<Target : TextOutputStream>(to target: inout Target) {
            target.write(self ? "TRUE": "FALSE")
        }
    }
    
    let valueTrue: Bool = true
    "\(valueTrue)" // -> "true"
    String(describing: valueTrue) // -> "TRUE"
    print(valueTrue) // -> "TRUE"
    
[/code]

どうやら **一般のstructと`Bool`では動作が異なる**ようです。

1024jpさんのヒントを頼りにSwift Standard Libraryのソースコードから探ってみました。

[StringInterpolation.swift.gyb](https://github.com/apple/swift/blob/master/stdlib/public/core/StringInterpolation.swift.gyb)

[OutputStream.swift](https://github.com/apple/swift/blob/master/stdlib/public/core/OutputStream.swift)

StringInterpolation.swift.gyb からわかるのは、文字列補間では、以下の型に対して特別な処理が行われると言うことです。

`String`,`Character`,`UnicodeScalar` =>
`_toStringReadOnlyStreamable(_:)`が呼ばれる。  
内部(OutputStream.swiftに定義)ではさらに`TextOutputStreamable`の`write(to:)`が呼ばれる。

`'Bool`,`Float32`,`Float64`,全ての整数型 =>
`_toStringReadOnlyPrintable(_:)`が呼ばれ、その中で`CustomStringConvertible`の`description`が呼ばれる。

* * *

さて、お尋ねの`Bool`型の場合、上記のように、nagonsoftwareさんの言われる`description`プロパティの値が使われる、と言う話にたどり着くわけですが…。

**そもそもSwiftにはきちんとした言語仕様というものがないので、その動作が言語仕様に適合しているかどうかを議論すること自体が無意味です。**

と言ってしまっては身も蓋もないので、さらに若干補足しておきますと、きちんとした言語仕様がないSwiftの世界では以下のApple製の公式ドキュメント2点が言語仕様に準ずるものとして扱われています。

[The Swift Programming Language (Swift
3.0.1)](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097)

[Using Swift with Cocoa and Objective-C (Swift
3.0.1)](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)

さらにAppleのAPI reference中のSwift Standard Libraryの記述も仕様と言ってしまっていいでしょう。

ドキュメントが豊富ではない時代には(あるいは今でも)Generated Header中のヘッダドキュメントなんかも「仕様」として見られていました。

私が探した限りでは、上記のいずれのドキュメントにも`Bool`の`description`が"true"か"false"のどちらかになるという記述は見つけれませんでした。(1024jpさんがOverviewの中に見つけられたような情報が他にも何かあるかもしれませんが。)

私なりの結論としては、 **この動作が将来変わる可能性は極めて低いと思うが、とても言語仕様とは呼べない** と言ったところです。

ちなみに「`Bool`の場合には文字列補間の際に`String(describing:)`ではなく`description`が使われる」と言う記述自体もどこにも見当たりませんので、その部分も「言語仕様」とは思わない方が良いでしょう。


CC BY-SA 3.0
2016-11-25T16:51:52.660
30672
2016-11-26T07:32:20.783
2016-11-26T07:32:20.783
13972
13972
30656
answer