I am writing a simple service to retrieve images from different sources (instagram, flickr, google)
Currently every service served in a separate .clj file with bunch of functions, both common and specific.
I am thinking about introducing protocol ImageService for that and each specific service will implement that protocol. This way we could add documentation at the protocol level and reuse common methods.
What are pros and cons with using protocols for such type of problem? How do we create specific implementation for service: deftype, defrecord or reify? What is idiomatic approach in clojure?
We've had a great deal of success at my company using protocols over external services just like you described. Protocols are nice because they allow you to write calling code in a single agnostic fashion, and also do dependency injection for easy testing (with mock implementations of your protocol). The main downside of protocols I've run into is that you can't have (shared) default implementations, otherwise I"m very happy with them.
deftype and defrecord differ in several ways, in practice the most prominent difference is that types generated with defrecord can also behave like maps:
(defrecord Foo [bar])
(->Foo 1) ; or (Foo. 1)
; => #user.Foo{:bar 1}
(assoc (Foo. 1) :norf 2)
; => #user.Foo{:bar 1, :norf 2}
Up to you if you need this behavior or not. reify just creates an 'anonymous' implementation of your protocol, we tend not to use it much and instead use a pattern like
(deftype MyService [args...])
; Our own public constructor
(defn ->my-service [config]
(->MyService (parse-config config)))
; etc ...
Related
I'm a Clojure novice and was looking for some concrete examples of when to use protocols and when to use multimethods. I know that protocols are generally geared towards creating a type hierarchy and typical OOP things, that they were added to the language after multimethods, and that protocols generally have better performance so my question is this:
Are protocols meant to replace multimethods? If not, could you give me an example where I would use multimethods instead of protocols?
Protocol and multimethods are complementary and intended for slightly different use cases.
Protocols provide efficient polymorphic dispatch based on the type of the first argument. Because the is able to exploit some very efficient JVM features, protocols give you the best performance.
Multimethods enable very flexible polymorphism which can dispatch based on any function of the method's arguments. Multimethods are slower but very flexible
In general, my advice is to use protocols unless you have a specific case that requires multimethods.
A case where you could require multimethods is something like the following:
(defn balance-available? [amount balance] (> balance amount))
(defmulti withdraw balance-available?)
(defmethod withdraw true [amount balance]
(- balance amount))
(defmethod withdraw false [amount balance]
(throw (Error. "Insufficient balance available!")))
Note that you can't use protocols here for both of the following reasons:
The dispatch function needs to use both arguments to determine which method implementation to use (i.e. it is a multiple dispatch case).
You also can't distinguish on the type of the first argument (which is presumably always a numeric value)
Multimethods are more powerful and more expensive,
use protocols when they are sufficient but if you need to dispatch based on the phase of the moon as seen from mars then multimethods are your best choice.
Protocols exist to allow the simple stuff to stay simple and provide a way for clojure to generate very much the same bytecode that the equivalent java would. It seems that most people use protocols most of the time. I use multimethods when I need to dispatch on more than one argument, though I have to admit that this has only come up once, and full isa hierarchies are used even less often (by me). so in short use Multimethods when you need them
the best example In my expierence is right at the start, in core.clj
As mention by Arthur, multimethods are more powerful and more expensive. Indeed, protocols can be thought of as a special case of mutlimethods where the dispatch function is class. Of course, this is not really the case as protocols are more than that.
If you need to dispatch on something other than the class of the first argument, you'll need to use a multimethod, or redesign. Dispatching on type is a good use case for protocols.
I like multimethods when you don't otherwise need a class hierarchy. For example if you have a media database and your records are like {:media-type :video, :bytes ...} then you can have a multimethod
(defmulti make-grayscale :media-type)
Then you can make various
; in video.clj
(defmethod make-grayscale :video [record]
(ffmpeg ... (:bytes record))
; in photo.clj
(defmethod make-grayscale :photo [record]
(imagemagick ... (:bytes record))
That way you can avoid having a central cond expression, so you get the modularity of classes. But you don't have to go through all that "wrapper class hierarchy" boilerplate, which to me is a bane that should be left for the Java world. Multimethods are just functions and feel more clojuresque to me.
I am new to Clojure, so perhaps this is a really obvious question, but I cannot find any useful answer.
I am implementing a REST service with Spring Boot which uses Clojure to calculate the result by means of multiple calls to Compiler.eval(). I have some Clojure stuff that is supposed to be shared among all requests (constants, functions, global variables, etc.), and well as some per-request stuff that should be isolated and unique for each request.
I run this service as executable JAR with clojure.jar in the classpath. However, from JVM's perspective, you can only access Clojure through static methods, which means there is only one "instance of Clojure" per JVM. This means that if you eval (def a 1) during one request, "a" becomes visible to other requests as well.
Question 1: where and how should I define dynamic (request-scoped) variables/symbols in Clojure?
Question 2: Suppose I want a completely "new" Clojure instance for every request. How could I achieve that? So for example, I could have the variable with the same name and in the same namespace, but with different values, in the same JVM? I know I can load a whole new set of Clojure classes by using a fresh classloader, but that seems horribly cumbersome.
You shouldn't use global variables in Clojure, unless it is needed to keep track of some global "state", which has to be shared among all functions. It's a functional language (well, mostly) and the functional way of doing things is passing all required stuff along as arguments. That's how you get referential transparency and how you avoid functions seeing and influcencing each-other's values.
I don't know why you want to use SpringBoot for this, but maybe you could take a look at how Clojure-native web libraries work. They usually pass along some kind of "request context" to the handlers, where all necessary information is stored.
For instance Yada or Ring.
So to answer your (1): pass them in with each request.
And (2): you don't need that if you pass in new values per request.
Although using globals that are local to one request (pardon the ugly expression) is not a generally recommended way to do web services in Clojure, let's say you have a valid use case for this. One such use case could be building an online REPL like tryclj.com.
A possibility to isolate requests would then be to create a temporary (random) namespace for each request, and wipe the namespace after each request. tryclojure does this for requests using clojail for sandboxing (snippet from src/tryclojure/models/eval.clj):
(defn make-sandbox []
(sandbox try-clojure-tester
:timeout 2000
:init '(do (require '[clojure.repl :refer [doc source]])
(future (Thread/sleep 600000)
(-> *ns* .getName remove-ns)))))
At the moment, I have a completely functional Clojure library which is called from Java.
The way I do this : I have a file that uses gen-class to wrap the entire API as static methods of a single class and passes data in and out in the form of IPersistentVector and IPersistentMap.
Now, however, I'm refactoring the library and putting the functionality behind various Protocols.
I have four protocols, lets call them A, B, C and D. And two defrecords, X and Y. X and Y both implement protocols A, B and C. While Y also implements D.
What do I need to do to make these available to Java? Are these automatically available as Interfaces and Classes? Or do I still have to do the equivalent of the gen-class to make them public?
If not, what is the equivalent of the gen-class :methods clause, where I define the Java types for the arguments to the methods?
Does anyone have a simple example of making Protocols and records available to Java?
defprotocol
Every Clojure protocol is also a Java interface with the same name and methods. If I take an example from ibm developerworks, we see that :
(ns com.amalgamated)
(defprotocol Fulfillment
(invoice [this] "Returns an invoice")
(manifest [this] "Returns a shipping manifest"))
Is equivalent to :
package com.amalgamated;
public interface Fulfillment {
public Object invoice();
public Object manifest();
}
Clojure.org also has some (rather terse) information on this.
A Java client looking to participate in the protocol can do so most
efficiently by implementing the protocol-generated interface. External
implementations of the protocol (which are needed when you want a
class or type not in your control to participate in the protocol) can
be provided using the extend construct:
(extend AType AProtocol
{:foo an-existing-fn
:bar (fn [a b] ...)
:baz (fn ([a]...) ([a b] ...)...)} BProtocol
{...} ...)
definterface
If you are aiming at performance, you could consider using definterface, which use is similar to the protocols. This SO post also has details about how to use it :
(definterface Foo
[^int foo [x ^String y]]
[^void bar [^ints is]])
definterface seem to be faster than protocols.
defrecord
Similarly, records (as well as deftype and definterface) will generate Java Classes.
Again, Clojure.org/datatypes has useful information (emphasis mine) :
deftype and defrecord dynamically generate compiled bytecode for a
named class with a set of given fields, and, optionally, methods for
one or more protocols and/or interfaces. They are suitable for dynamic
and interactive development, need not be AOT compiled, and can be
re-evaluated in the course of a single session. They are similar to
defstruct in generating data structures with named fields, but differ
from defstruct in that: [...]
So yes if will be available from Java.
Just be careful with naming.
As a side note, you may want to have a look at calling Clojure from Java.
Coming from an OOP background, I have a doubt on the recommended way of API design in Clojure. For example in an OOP language(Python here), for using some API I would do this:
api = someWebService()
api.setWriteApiKey(WRITE_API_KEY)
api.sampleloadSong('file.mp3')
In the above example, I set the API key once and call the associated methods again and again without ever passing the API key again. What is the recommended way of doing this in Clojure or any other LISP family of languages ?
Do I need to pass the key in each and every function call like this:
(sampleloadSong "WRITE_API_KEY" "file.mp3")
Or is there any other better approach.
To prevent the repetition problem you describe, you can make a function that returns an api function that remembers the keys, (closes over them)
(defn make-client [key] (partial api key))
Then later in your program:
(let [api-fn (make-client WRITE_API_KEY)]
(api-fn :sample-song "song.mp3")
...
(api-fn :delete-song "other-song.mp3"))
Though many people consider it preferable to pass a config map as the first argument to each api call.
(api {:key WRITE_API_KEY} ....)
There is another common approach where people define the keys as a dynamically bindable symbol and require the callers to bind it appropriately:
(def *api-key* :unset)
(defn api .... use *api-key* )
from caller's namespace:
(binding [*api-key* WRITE_API_KEY]
(api :add-song "foo.mp3"))
This approach may be less popular than it used to be, and my personal preference it to pass a config map, though that is just my opinion.
There are a few different ways to create Java classes in Clojure, so what are the tradeoffs when picking between gen-class, proxy, and reify in Clojure? (are there other ways to create Java classes that I haven't listed?)
My basic understanding is that I have listed these constructs in decreasing order of power.
Use gen-class when you want a named class or you want to add new methods to objects you create. gen-class relies on AOT compilation.
When you want an anonymous, one-off implementation of a type you use reify or proxy. They do not rely on AOT compilation. Here are their differences:
reify only supports protocols or interfaces, proxy also supports concrete superclasses.
reify uses true class methods, proxy uses external functions.
Because of #2, reify uses direct method lookup, while proxy uses a map for method lookup.
Because of #3, reify does not support dynamic swapping of methods, but proxy does.
reify will perform better than proxy, so you should always use reify when possible. Only use proxy when reify's constraints are too prohibitive.
In addition to gen-class, proxy and reify, we have defrecord and deftype. These latter two options should be your first choices for the creation of named java classes (and in the case of defrecord, your first choice for any kind of struct with named components.)
The datatypes page on clojure.org is a good reference on this topic. Defrecord, deftype and reify are newer than gen-class and proxy, having been introduced in version 1.2 (I think -- possibly 1.1). Defrecord and deftype both create classes that conform to interfaces, but do not allow for inheritance. If you need inheritance, gen-class (and proxy for anonymous classes) is still your only option.
Defrecord and deftype differ in what you are given for free. Defrecord automatically creates a class which conforms to IPersistentMap and ISeq. Deftype, on the other hand, gives you more control over your class, even allowing for mutable fields (not allowed in defrecord). In general, deftype is intended for low-level implementation of data structures, whereas defrecord is intended for most day-to-day use.