3

there are plenty protocols vs multimethods comparisions, but why not to use higher order functions? Let's come with example: We have some data (record for example). And we have methods serialize and deserialize. Say that we want to save it into file, into json, and into database. Should we create protocol called SerializationMethod and records called database, json, file that implement them? It looks kind of hack to create records only to use protocol. Second solution - multimethod - could take string parameter with serialization output and decide how to do this. But I am not sure that is right way to go... And third way is to write function serialize and then pass there data and serializing function. But now I can not name serializing and deserializing method with same name (json fo example):

(defn serialize [method data]
  (method data))

(defn json[data]
  (...))

The question is how can I (or how should I) do this. Is there more generic way with higher order function? Or maybe I don't understand something well? That are my first steps with clojure so please be tolerant.

ravenwing
  • 668
  • 3
  • 20

1 Answers1

2

Converting to JSON is different from writing to a database or a file because the latter are IO operations, the first is a pure transformation of data. With that in mind, I wouldn't recommend to implement them under the same interface.

Now assuming you had various serialization implementations, lets say json and fressian, it would certainly not be a good idea to implement them on every data structure that you want to (de-/)serialize. Your observation that that would be a hack is correct. More concisely, it would be limiting a record to be only (de-/)serializable with one implementation.

Instead, it would be more effective to have different Serializers, each implementing the same interface:

(defrecord JSONSerializer []
  SerializationMethod
  (serialize [this data] ...)
  (deserialize [this data] ...))

(defrecord FressianSerializer []
  SerializationMethod
  ...)

This way we end up having several serializer objects that can be passed to functions that require one. Those functions don't need to be concerned with the implementation.

Could higher order functions be passed instead?

(defn do-something 
  [params serialize deserialize]
  ...)

It would work, too. Notice however that this style can quickly grow out of hand. E. g. consider a scenario where a function should be written that deserializes data from one format and serializes it to the other.

Leon Grapenthin
  • 9,246
  • 24
  • 37
  • As for differentiation json and writting to database/file I totally agree. But as for solution with records - it is creation of records that have no fields - that's hacky for me. And every time we want to (de)serialize data we have to create instance of record (.serialize ->JSONSerializer data). As for HOF What I meant was: (serialize JsonSerialization data). And serialization of deserialization: (serialize FressianSerialization (deserialize JsonDeserialization data)) or using arrow makro. – ravenwing Oct 27 '14 at 00:02
  • I left fields out for example purposes. There are good reasons for having fields containing e. g. configuration parameters. You don't have to create a JSONSerializer everytime you invoke a method of the SerializationMethod Protocol. If implemented correctly, the methods of one record can be invoked many times - if implemented thread safe, even from different threads. The HOF example in your comment involves no passed functions (???) -- – Leon Grapenthin Oct 29 '14 at 19:01
  • JsonSerialization is function also FressianSerialization. But now I see how stupid that solution is - it's not worth even calling solution. – ravenwing Oct 29 '14 at 22:27