{"id":395731,"date":"2024-06-29T12:23:33","date_gmt":"2024-06-29T12:23:33","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=395731"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=395731","title":{"rendered":"<span>Confusing extensions in Swift<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">This post is a little bit the information aggregator. If you find a mistake, you could write to me about it I really appreciate that. Have a nice read.<\/p>\n<h2>Example with JSONDecoder<\/h2>\n<p>  What would happen if we run the following piece of code?<\/p>\n<pre><code class=\"swift\">struct Test&lt;T>: Codable where T: Codable {     enum CodingKeys: String, CodingKey {         case value     }          let value: T     let info: String }  extension Test {     init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         self.value = try container.decode(T.self, forKey: .value)         self.info = \"Default init(from decoder:)\"     } }  extension Test where T == String {     init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         self.value = try container.decode(T.self, forKey: .value)         self.info = \"Custom init(from decoder:)\"     } }  let data = #\"{\"value\":\"Hello, World!\"}\"#.data(using: .utf8)! let object = try? JSONDecoder().decode(Test&lt;String>.self, from: data) print(object.debugDescription) <\/code><\/pre>\n<p>  Try thinking for 5 seconds about the result.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">The result<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"swift\">Optional(     Test&lt;String>(         value: \"Hello, World!\",          info: \"Default init(from decoder:)\"     ) ) <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>Why did it happen?<\/h2>\n<p>  The <code>JSONDecoder:decode<\/code> definition looks like<\/p>\n<pre><code class=\"swift\">func decode&lt;T>(_ type: T.Type, from data: Data) throws -> T where T: Decodable<\/code><\/pre>\n<p>  We see the <code>generic function<\/code> and also the metatype <code>T.Type<\/code>. I\u2019m not focusing your attention on those two definitions by accident. We should understand these structures of language.<\/p>\n<p>  You could read more about metatypes:<\/p>\n<ul>\n<li><a href=\"https:\/\/docs.swift.org\/swift-book\/ReferenceManual\/Types.html#grammar_opaque-type\">Swift documentation<\/a><\/li>\n<li><a href=\"https:\/\/swiftrocks.com\/whats-type-and-self-swift-metatypes.html\">What\u2019s .self, .Type and .Protocol?<\/a><\/li>\n<\/ul>\n<p>  Consider the example with metatype.<\/p>\n<pre><code class=\"swift\">protocol TestProtocol {     var info: String { get }     init(from value: Codable) }  struct Test&lt;T: Codable>: TestProtocol {     let value: T     let info: String }  extension Test {     init(from value: Codable) {         self.value = value as! T         self.info = \"Default init(value:)\"     } }  extension Test where T == String {     init(from value: Codable) {         self.value = value as! T         self.info = \"Custom init(value:)\"     } }  let type: TestProtocol.Type = Test&lt;String>.self print(type.init(from: \"Hello, World!\").info) <\/code><\/pre>\n<p>  We\u2019ll get the <code>\"Default init(value:)\"<\/code>. The reason is the second <code>init(from value: Codable)<\/code> not requirements of such protocol because for the swift compiler it\u2019s just another method. However, it\u2019s overloading of the method for us.<\/p>\n<p>  These methods calls <code>static<\/code> (it isn\u2019t about <code>static func<\/code>). Generally, the <code>Static dispatch<\/code> works here \u2014 the swift compiler discribes how a programm will select which implementation of a method on the compile time.<\/p>\n<p>  You will see that if you build a <a href=\"https:\/\/github.com\/apple\/swift\/blob\/master\/docs\/SIL.rst#sil-in-the-swift-compiler\">Swift Intermediate Language (SIL)<\/a> file by the example.<\/p>\n<p>  <code>> swiftc -emit-sil example.swift > example.swift.sil<br \/>  <\/code>  <\/p>\n<blockquote><p>No polymorphism for static methods.<\/p><\/blockquote>\n<p>  Where a same problem could be in <code>JSONDecoder:decode<\/code>? If we see how it works, we will find the reason. The next <a href=\"https:\/\/github.com\/apple\/swift\/blob\/80e5a51b5ba846060b887bc96db5463ef920e4a7\/stdlib\/public\/Darwin\/Foundation\/JSONEncoder.swift#L1200\">code<\/a> from the official repository.<\/p>\n<pre><code class=\"swift\">open func decode&lt;T : Decodable>(_ type: T.Type, from data: Data) throws -> T {     let topLevel: Any     do {         topLevel = try JSONSerialization.jsonObject(with: data)     } catch {         throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: \"The given data was not valid JSON.\", underlyingError: error))     }      let decoder = __JSONDecoder(referencing: topLevel, options: self.options)     guard let value = try decoder.unbox(topLevel, as: type) else {         throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: [], debugDescription: \"The given data did not contain a top-level value.\"))     }      return value }  \/\/ MARK: - Concrete Value Representations private extension __JSONDecoder {          ...      func unbox&lt;T : Decodable>(_ value: Any, as type: T.Type) throws -> T? {         return try unbox_(value, as: type) as? T     }      func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? {         ... {             return try type.init(from: self)         }     } } <\/code><\/pre>\n<p>  You would think a problem will be when the <code>unbox_<\/code> called, but the situation a little bit complicated.<br \/>  Consider another example:<\/p>\n<pre><code class=\"swift\">func generate&lt;T: TestProtocol, Value: Codable>(value: Value, as type: T.Type) -> T {     type.init(from: value) }  print(generate(value: \"Hello, World!\", as: Test&lt;String>.self).info) <\/code><\/pre>\n<p>  We\u2019ll get the <code>\"Default init(value:)\"<\/code> again. What will we see in the SIL code for the <code>generate<\/code> function?<\/p>\n<pre><code class=\"swift\">\/\/ generate&lt;A, B>(value:as:) sil hidden @$s5test28generate5value2asxq__xmtAA12TestProtocolRzSeR_SER_r0_lF : $@convention(thin) &lt;T, Value where T : TestProtocol, Value : Decodable, Value : Encodable> (@in_guaranteed Value, @thick T.Type) -> @out T { \/\/ %0                                             \/\/ user: %9 \/\/ %1                                             \/\/ users: %7, %3 \/\/ %2                                             \/\/ users: %9, %4 bb0(%0 : $*T, %1 : $*Value, %2 : $@thick T.Type):   debug_value_addr %1 : $*Value, let, name \"value\", argno 1 \/\/ id: %3   debug_value %2 : $@thick T.Type, let, name \"type\", argno 2 \/\/ id: %4   %5 = alloc_stack $Decodable &amp; Encodable         \/\/ users: %10, %9, %6   %6 = init_existential_addr %5 : $*Decodable &amp; Encodable, $Value \/\/ user: %7   copy_addr %1 to [initialization] %6 : $*Value   \/\/ id: %7   %8 = witness_method $T, #TestProtocol.init!allocator.1 : &lt;Self where Self : TestProtocol> (Self.Type) -> (Decodable &amp; Encodable) -> Self : $@convention(witness_method: TestProtocol) &lt;\u03c4_0_0 where \u03c4_0_0 : TestProtocol> (@in Decodable &amp; Encodable, @thick \u03c4_0_0.Type) -> @out \u03c4_0_0 \/\/ user: %9   %9 = apply %8&lt;T>(%0, %5, %2) : $@convention(witness_method: TestProtocol) &lt;\u03c4_0_0 where \u03c4_0_0 : TestProtocol> (@in Decodable &amp; Encodable, @thick \u03c4_0_0.Type) -> @out \u03c4_0_0   dealloc_stack %5 : $*Decodable &amp; Encodable      \/\/ id: %10   %11 = tuple ()                                  \/\/ user: %12   return %11 : $()                                \/\/ id: %12 } \/\/ end sil function '$s5test28generate5value2asxq__xmtAA12TestProtocolRzSeR_SER_r0_lF' <\/code><\/pre>\n<p>  As we see the <code>generate<\/code> function works with <code>TestProtocol.init<\/code>. Why? You could read the small article about the<a href=\"https:\/\/github.com\/apple\/swift\/blob\/master\/docs\/SIL.rst#abstraction-difference\"> Abstract Difference of SIL Types<\/a>. I just show you three base things about generics\u2019 working as I\u2019ve understood this:<\/p>\n<ul>\n<li>Don\u2019t generate a different copy of generic function for every unconstrained type.<\/li>\n<li>Don\u2019t give every type in the language a common representation.<\/li>\n<li>Don\u2019t dynamically construct a call to generator depending on an unconstrained type.<\/li>\n<\/ul>\n<p>  I hope this information will help you.<\/p>\n<h2>References<\/h2>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/swiftrocks.com\/whats-type-and-self-swift-metatypes.html\"> What\u2019s .self, .Type and .Protocol?<br \/>  <\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2015\/408\/\">WWDC 2015: Protocol-Oriented Programming in Swift<\/a><\/li>\n<li><a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2016\/416\/\">WWDC 2016: Understanding Swift Performance<\/a><\/li>\n<li><a href=\"https:\/\/medium.com\/@leandromperez\/protocol-extensions-gotcha-9ef1a42c83b6#2347\">Swift Protocol Extensions Method Dispatch<\/a><\/li>\n<li><a href=\"https:\/\/medium.com\/flawless-app-stories\/static-vs-dynamic-dispatch-in-swift-a-decisive-choice-cece1e872d\">Static vs Dynamic Dispatch in Swift: A decisive choice<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/apple\/swift\/blob\/master\/docs\/SIL.rst\">Swift Intermediate Language (SIL)<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/528650\/\"> https:\/\/habr.com\/ru\/articles\/528650\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">This post is a little bit the information aggregator. If you find a mistake, you could write to me about it I really appreciate that. Have a nice read.<\/p>\n<h2>Example with JSONDecoder<\/h2>\n<p>  What would happen if we run the following piece of code?<\/p>\n<pre><code class=\"swift\">struct Test&lt;T>: Codable where T: Codable {     enum CodingKeys: String, CodingKey {         case value     }          let value: T     let info: String }  extension Test {     init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         self.value = try container.decode(T.self, forKey: .value)         self.info = \"Default init(from decoder:)\"     } }  extension Test where T == String {     init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         self.value = try container.decode(T.self, forKey: .value)         self.info = \"Custom init(from decoder:)\"     } }  let data = #\"{\"value\":\"Hello, World!\"}\"#.data(using: .utf8)! let object = try? JSONDecoder().decode(Test&lt;String>.self, from: data) print(object.debugDescription) <\/code><\/pre>\n<p>  Try thinking for 5 seconds about the result.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">The result<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"swift\">Optional(     Test&lt;String>(         value: \"Hello, World!\",          info: \"Default init(from decoder:)\"     ) ) <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-395731","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395731","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=395731"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/395731\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=395731"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=395731"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=395731"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}