{"action":"created","issue":{"url":"https://api.github.com/repos/daokoder/dao/issues/412","labels_url":"https://api.github.com/repos/daokoder/dao/issues/412/labels{/name}","comments_url":"https://api.github.com/repos/daokoder/dao/issues/412/comments","events_url":"https://api.github.com/repos/daokoder/dao/issues/412/events","html_url":"https://github.com/daokoder/dao/issues/412","id":89411367,"number":412,"title":"New faces for old interfaces","user":{"login":"Night-walker","id":5074460,"avatar_url":"https://avatars.githubusercontent.com/u/5074460?v=3","gravatar_id":"","url":"https://api.github.com/users/Night-walker","html_url":"https://github.com/Night-walker","followers_url":"https://api.github.com/users/Night-walker/followers","following_url":"https://api.github.com/users/Night-walker/following{/other_user}","gists_url":"https://api.github.com/users/Night-walker/gists{/gist_id}","starred_url":"https://api.github.com/users/Night-walker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Night-walker/subscriptions","organizations_url":"https://api.github.com/users/Night-walker/orgs","repos_url":"https://api.github.com/users/Night-walker/repos","events_url":"https://api.github.com/users/Night-walker/events{/privacy}","received_events_url":"https://api.github.com/users/Night-walker/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":8,"created_at":"2015-06-18T22:21:49Z","updated_at":"2015-06-27T09:34:19Z","closed_at":null,"body":"> \"HA-HA-HA-HA\"\r\n> -- *Fantomas*\r\n\r\nImagine a facility aimed to be defined for broad range of data types. One which is meant to be adaptable to new scenarios. Like serialization. Plenty of things can be serialized, you can't possibly define the complete list of them in advance. \r\n\r\nNow take the serialization facilities in `serializer`, `json`, `xml` -- all of them are basically only aware of primitive types. What about `time::DateTime`, `os::Path`, `re::Regex` or `BigInt`? Obviously you can manually handle their serialization should the need appear. But that's merely a workaround -- the mountain approaches Mahomet, though we know it should be the other way around. That's how the manual way looks like:\r\n```ruby\r\nroutine processStuff(stuff: list<A|B|C|...>){ # may be a map, a tree-like structure, anything.\r\n    for (item in stuff)\r\n        switch (item) type { # handle each type separately\r\n        case A: handleA(item); \r\n        case B: handleB(item);\r\n        case C: handleC(item);\r\n        ...\r\n        }\r\n}\r\n```\r\nAnd each time you face similar task, this boilerplate code will emerge over and over, whereas the solution should actually resemble the following:\r\n```ruby\r\ninterface I { # which supposedly generalizes over A, B, C, ... \r\n    routine handle()\r\n}\r\n\r\nroutine processStuff(stuff: list<A|B|C|...>){\r\n    for (item in stuff)\r\n        item.handle() # assuming I is defined for A, B, C, ...\r\n}\r\n```\r\nPretty evident that the latter variant, so seductive and desirable, is an unattainable dream unless the interface is actually implemented for all concerned classes *beforehand*. Which is so cruelly untrue for our case with wrapped types which happen to have no notion about serialization.\r\n\r\nThat is, there is currently no way to express a *universal* solution here, one which would encompass all similar cases. And that's sad. After all, code reuse is one of the most pursued goals in the programming. The Holy Grail of OOP, no less.\r\n\r\nWell, it is of course possible to just add built-in serialization support for any of those types. Isn't that the simplest way to deal with the problem? Not exactly, as it\r\n- requires you to modify existing source (and what if it's not yours to tackle with?)\r\n- bloats the type with stuff which doesn't really belong there (dead weight most of the time)\r\n- makes the related module's interface dependent on how serialization is done in some other module (incurring 'cascade changes' in the API)\r\n\r\nDon't forget that serialization is just an example here -- plenty of tasks can potentially benefit from being defined on interfaces instead of strict sets of types.\r\n\r\nThe ~~salvation~~ solution actually exists and lies within our reach.\r\n\r\nContinuing with the serialization subject, let's assume we're dealing with JSON. First, we gonna need an interface, the one to rule them all: \r\n```ruby\r\ninterface Serializable { # in json namespace\r\n    invar routine serialize() => json::Data\r\n}\r\n```\r\nWhat do we need to appease the gods and grant e.g. `time::DateTime` support of `json::Serializable`? A separate implementation of this interface for `DateTime` at the place where we actually require it, in the spirit of Rust:\r\n```ruby\r\nimplement json::Serializable for time::DateTime {\r\n    # 'selfless' notation is also an option\r\n    routine serialize(invar self: time::DateTime) => json::Data {\r\n        self.value()\r\n    }\r\n}\r\n```\r\nNote that this is not supposed to change existing `time::DateTime` type -- `serialize()` is *not* to be injected into it like extension method or so. Implementation here just defines the way how existing type can be 'mapped' to interface. Should you cast a `DateTime` to `Serializable`, `serialize()` from the implementation will come into play as if it was `DateTime` method.\r\n\r\nAnd that's not the end (but know that the end is nigh -- just few paragraphs remain). The way interface implementations are defined makes it possible to use them *for any type including built-in primitive types*. If that doesn't sound convincing, imagine that Dao suddenly acquires *unified* type system. Almost as in Scala or Rust. No more need for exhaustive variant types coupled with `switch type` when you can express what you need with a single interface. And then, afterwards, bind whatever you wish to that interface. At any point, without affecting the existing source.\r\n\r\nThis feature does make things substantially more complicated, I know. We already have lots of stuff in the language, and this one looks like a major feature. So I wouldn't claim that it is undoubtedly a good idea to support what might turn out to be yet another fancy trinket to toy with when one feels bored.\r\n\r\nBut I think it is worth to pay some attention to this idea. Interface implementations promise capabilities unachievable by the use of more traditional OOP idioms (at least not without potent doping). In Rust, they bring unparalleled flexibility to the language. All in all, seems like an interesting topic to discuss."},"comment":{"url":"https://api.github.com/repos/daokoder/dao/issues/comments/115999084","html_url":"https://github.com/daokoder/dao/issues/412#issuecomment-115999084","issue_url":"https://api.github.com/repos/daokoder/dao/issues/412","id":115999084,"user":{"login":"daokoder","id":1860002,"avatar_url":"https://avatars.githubusercontent.com/u/1860002?v=3","gravatar_id":"","url":"https://api.github.com/users/daokoder","html_url":"https://github.com/daokoder","followers_url":"https://api.github.com/users/daokoder/followers","following_url":"https://api.github.com/users/daokoder/following{/other_user}","gists_url":"https://api.github.com/users/daokoder/gists{/gist_id}","starred_url":"https://api.github.com/users/daokoder/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daokoder/subscriptions","organizations_url":"https://api.github.com/users/daokoder/orgs","repos_url":"https://api.github.com/users/daokoder/repos","events_url":"https://api.github.com/users/daokoder/events{/privacy}","received_events_url":"https://api.github.com/users/daokoder/received_events","type":"User","site_admin":false},"created_at":"2015-06-27T09:34:19Z","updated_at":"2015-06-27T09:34:19Z","body":"More or less done:)"}}