{"id":4046,"date":"2014-06-10T10:55:16","date_gmt":"2014-06-10T13:55:16","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=4046"},"modified":"2014-09-19T13:07:48","modified_gmt":"2014-09-19T16:07:48","slug":"comparing-protocols-and-extensions-in-swift-and-elixir","status":"publish","type":"post","link":"http:\/\/blog.plataformatec.com.br\/2014\/06\/comparing-protocols-and-extensions-in-swift-and-elixir\/","title":{"rendered":"Comparing protocols and extensions in Swift and Elixir"},"content":{"rendered":"
Swift<\/a> has been recently announced by Apple and I have been reading the docs and playing with the language out of curiority. I was pleasantly surprised with many features in the language, like the handling of optional values (and types) and with immutability being promoted throughout the language.<\/p>\n The language also feels extensible. For extensibility, I am using the same criteria we use for Elixir<\/a>, which is the ability to implement language constructs using the language itself.<\/p>\n For example, in many languages the short-circuiting In Elixir, however, you can implement the In Swift, you can also implement operators and easily define the The However, one of the features I suspect that will actually hurt extensibility in Swift is the Extensions<\/strong> feature. I have compared the protocols implementation in Swift with the ones found in Elixir and Clojure on Twitter and, as developers have asked for a more detailed explanation, I am writing this blog post as result!<\/p>\n The extension feature in Swift has many use cases. You can read them all in more detail in their documentation<\/a>. For now, we will cover the general case and discuss the protocol case, which is the bulk of this blog post.<\/p>\n Following the example in Apple documentation itself:<\/p>\n In the example above, we are extending the Double type, adding our own computed properties. Those extensions are global and, if you are Ruby developer, it will remind you of monkey patching in Ruby. However, in Ruby classes are always open, and here the extension is always explicit (which I personally consider to be a benefit).<\/p>\n What troubles extensions is exactly the fact they are global<\/strong>. While I understand some extensions would be useful to define globally, they always come with the possibility of namespace pollution and name conflicts. Two libraries can define the same extensions to the Double type that behave slightly different, leading to bugs.<\/p>\n This has always been a hot topic in the Ruby community with Refinements<\/a> being proposed in late 2010 as a solution to the problem. At this moment, it is unclear if extensions can be scoped in any way in Swift.<\/p>\n Protocols are a fantastic feature in Swift. Per the documentation<\/a>: “a protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality”.<\/p>\n Let’s see their example:<\/p>\n In the example above we defined a I have been long advocating this feature for Ruby. For example, imagine you have the following Ruby code:<\/p>\n And you have a method somewhere that expects an object that implements At some point, you may want to print the title too:<\/p>\n Your contract has now changed but there is no mechanism to notify implementations of such change. This is particularly cumbersome because sometimes such changes are done by accident, when you don’t want to actually modify the contract.<\/p>\n This issue has happened multiple times in Rails. Before Rails 3, there was no official contract between the controller and the model and between the view and the model. This meant that, while Rails worked fine with Active Record (Rails’ built-in model layer), every Rails release could possibly break integration with other models because the contract suddenly became larger due to changes in the implementation.<\/p>\n Since Rails 3, we actually define a contract for those interactions, but there is still no way to:<\/p>\n Similar to real-life contracts, unless you write it down and sign it, there is no guarantee both parts will actually maintain it.<\/p>\n The ideal solution is to be able to define multiple, tiny protocols. Someone using Swift would rather define multiple protocols for the controller and view layers:<\/p>\n The interesting aspect about Swift protocols is that you can define and implement protocols for any given type, at any time. The trouble though is that the implementation of the protocols are defined in the class\/struct itself and, as such, they change the class\/struct globally.<\/p>\n Since protocols in Swift are implemented directly in the class\/struct, be it during definition or via extension, the protocol implementation ends up changing the class\/struct globally. To see the issue with this, imagine that you have two different libraries relying on different JSON protocols:<\/p>\n If the protocols above have different specifications on how the precision argument must be handled, we will be able to implement only one<\/strong> of the two protocols above. That’s because implementing any of the protocols above means adding a Furthermore, if implementing protocols means globally adding method to classes and structs, it can actually hinder the use of protocols as a whole, as the concerns to avoid name clashes and to avoid namespace pollution will speak louder than the protocol benefits.<\/p>\n Let’s contrast this with protocols in Elixir:<\/p>\n Elixir protocols are heavily influenced by Clojure protocols<\/a> where the implementation of a protocol is tied to the protocol itself and not to the data type implementing the protocol. This means you can implement both JSONA and JSONB protocols for the same data types and they won’t clash!<\/p>\n Protocols in Elixir work by dispatching on the first argument of the protocol function. So when you invoke What is interesting is that we can actually emulate this functionality in Swift! In Swift we can define the same method multiple times, as long as the type signatures do not clash. So if we use static methods and extension, we can emulate the behaviour above:<\/p>\n The example above emulates the dynamic dispatch ability found in Elixir and Clojure which guarantees no clashes in multiple implementations. After all, if someone defines a JSONB class, all the implementations would live in the JSONB class.<\/p>\n Since dynamic dispatch is already available, we hope protocols in Swift are improved to support local implementations instead of changing classes\/structs globally.<\/p>\n Swift is a very new language and in active development. The documentation so far doesn’t cover topics like exceptions, the module system and concurrency, which indicates there are many more exciting aspects to build, discuss and develop.<\/p>\n It is the first time I am excited to do some mobile development. Plus the Swift playground may become a fantastic way to introduce programming.<\/p>\n Finally, I would personally love if Swift protocols evolved to support non-global implementations. Protocols are a very extensible mechanism to define and implement contracts and it would be a pity to see their potential hindered due to the global side-effects it may cause to the codebase.<\/p>\n","protected":false},"excerpt":{"rendered":" Swift has been recently announced by Apple and I have been reading the docs and playing with the language out of curiority. I was pleasantly surprised with many features in the language, like the handling of optional values (and types) and with immutability being promoted throughout the language. The language also feels extensible. For extensibility, … \u00bb<\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[213,143,216,215,60,214],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4046"}],"collection":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=4046"}],"version-history":[{"count":10,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4046\/revisions"}],"predecessor-version":[{"id":4222,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/4046\/revisions\/4222"}],"wp:attachment":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=4046"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=4046"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=4046"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}&&<\/code> operator is defined as special part of the language. In those languages, you can’t reimplement the operator using the constructs provided by the language.<\/p>\n
&&<\/code> operator as a macro:<\/p>\n
\ndefmacro left && right do\n quote do\n case unquote(left) do\n false -> false\n _ -> unquote(right)\n end\n end\nend\n<\/pre>\n
&&<\/code> operator with the help of the
@auto_closure<\/code> attribute:<\/p>\n
\nfunc &&(lhs: LogicValue, rhs: @auto_closure () -> LogicValue) -> Bool {\n if lhs {\n if rhs() == true {\n return true\n }\n }\n return false\n}\n<\/pre>\n
@auto_closure<\/code> attribute automatically wraps the tagged argument in a closure, allowing you to control when it is executed and therefore implement the short-circuiting property of the
&&<\/code> operator.<\/p>\n
Extensions<\/h2>\n
\nextension Double {\n var km: Double { return self * 1_000.0 }\n var m: Double { return self }\n var cm: Double { return self \/ 100.0 }\n var mm: Double { return self \/ 1_000.0 }\n var ft: Double { return self \/ 3.28084 }\n}\n\nlet oneInch = 25.4.mm\nprintln(\"One inch is \\(oneInch) meters\")\n\/\/ prints \"One inch is 0.0254 meters\"\n\nlet threeFeet = 3.ft\nprintln(\"Three feet is \\(threeFeet) meters\")\n\/\/ prints \"Three feet is 0.914399970739201 meters\"\n<\/pre>\n
The case for protocols<\/h2>\n
\nprotocol FullyNamed {\n var fullName: String { get }\n}\n\nstruct Person: FullyNamed {\n var fullName: String\n}\n\nlet john = Person(fullName: \"John Appleseed\")\n\/\/ john.fullName is \"John Appleseed\"\n<\/pre>\n
FullyNamed<\/code> protocol and implemented it while defining the
Person<\/code> struct. The benefit of protocols is that the compiler can now guarantee the struct complies with the definitions specified in the protocol. In case the protocol changes in the future, you will know immediately by recompiling your project.<\/p>\n
\nclass Person\n attr_accessor :first, :last\n\n def full_name\n first + \" \" + last\n end\nend\n<\/pre>\n
full_name<\/code>:<\/p>\n
\ndef print_full_name(obj)\n puts obj.full_name\nend\n<\/pre>\n
\ndef print_full_name(obj)\n if title = obj.title\n puts title + \" \" + obj.full_name\n else\n puts obj.full_name\n end\nend\n<\/pre>\n
\n
\nprotocol URL {\n func toParam() -> String\n}\n\nprotocol FormErrors {\n var errors: Dict
Protocols and Extensions<\/h2>\n
\nprotocol JSONA {\n func toJSON(precision: Integer) -> String\n}\n\nprotocol JSONB {\n func toJSON(scale: Integer) -> String\n}\n<\/pre>\n
toJSON(Integer)<\/code> method to the class\/struct and there can be only one of them per class\/struct.<\/p>\n
\ndefprotocol JSONA do\n def to_json(data, precision)\nend\n\ndefprotocol JSONB do\n def to_json(data, scale)\nend\n\ndefimpl JSONA, for: Integer do\n def to_json(data, _precision) do\n Integer.to_string(data)\n end\nend\n\nJSONA.to_json(1, 10)\n#=> 1\n<\/pre>\n
JSONA.to_json(1, 10)<\/code>, Elixir checks the first argument, sees it is an integer and dispatches to the appropriate implementation.<\/p>\n
\n\/\/ Define a class to act as protocol dispatch\nclass JSON {\n}\n\n\/\/ Implement it for Double\nextension JSON {\n class func toJSON(double: Double) -> String {\n return String(double)\n }\n}\n\n\/\/ Someone may implement it later for Float too\nextension JSON {\n class func toJSON(float: Float) -> String {\n return String(float)\n }\n}\n\nJSON.toJSON(2.3)\n<\/pre>\n
Summing up<\/h2>\n