Correct method to write conditional code in clojure - clojure

So I am trying to write the below in clojure (Assume all methods below return boolean)
def some_method(a, b)
if (call_this_method() )
then_call_this_method()
else
new_method()
end
What I got was this:
(defn some-method [a b]
(if (call_this_method)
:then (then-call-this-method)
:else (new-method)))
I am pretty new to clojure so am not sure if this feels like the correct manner to solve this. Is there a different approach?

if basically takes 3 params, [condition what-to-run-if-true optional-run-if-false]
(defn some-method
"My function does ..."
[ a b ]
(if (call-this-method)
(then-call-this-method)
(new-method)))

You can use if in clojure as well
(if test then-code else-code)
Or cond which is more like switch
(cond
test-A run-if-A
test-B run-if-B
...
:else else-code)
And if you wanted to do something like
if(foo) bar;
Then you would write
(when foo bar)

Related

How is an "isa?" based multimethod more than syntax sugar for instanceof?

I am taking an example from the clojure site.
(defmulti foo class)
(defmethod foo ::collection [c] :a-collection)
(defmethod foo String [s] :a-string)
(foo [])
:a-collection
(foo (java.util.HashMap.))
:a-collection
(foo "bar")
:a-string
This functionality is cool. I'm trying to understand the technical reasons why this is superior to an instanceof based implementation in (for example) java. It seems to me essentially equivalent in function with nicer syntax.
public <T> String foo(final T t) {
if (t instanceof Collection) {
return "a-collection";
} else if (t instanceof String) {
return "a-string";
} else {
throw new IllegalArgumentException("Undefined - no available dispatch");
}
}
What are the reasons why multimethods are considered a great alternative to visitor pattern based double dispatch while instanceof is not when they seem like they're essentially doing the same thing?
One of the benefits discussed in the comments is that the defmulti and defmethod can be done in different files, by different users. An excellent example is Clojure's own print-method multi-method.
From the docs, we see how we can define a custom print-method for a new record type we create:
(deftype XYZ [])
; without custom print-method defined:
user=> (prn (XYZ.))
#<XYZ user.XYZ#2670d85b>
; Note, this hooks into the pre-existing `(defmulti print-method ...)`
(defmethod print-method XYZ [v ^java.io.Writer w]
(.write w "<<-XYZ->>"))
; with print-method
user=> (prn (XYZ.))
<<-XYZ->>
So while it has similarity to a giant cond statement, it is more flexible & cleaner.

Clojure function throwing arity exception when called from within a map

(map (fn [x]
(let [username (or (:f_username x) nil)
sites_names (SITES-NAMES username)
x (assoc x :sites sites_names)]
x)) my-rows)
In the code above: SITES-NAMES gives me an arity exception. However
if I call it (SITES-NAMES "theuser") it works. Why is this the case
if username evaluates as an example to "theuser".
I don't know why this is happening, but here are a few tips:
1) Make your anonymous function a top-level function, as such:
(defn add-site [site-names {:keys [f-username] :as x}]
(assoc x :sites (get site-names f-username)))
Notice how I name the vars, refer to https://github.com/bbatsov/clojure-style-guide for more info on naming and other neat stuff.
2) Now you can change your call to map with
(map (partial add-site site-names) my-rows)
This lets you play around with the add-site function at the REPL like so:
user> (add-site {"hector" "www.hector.com"} {:f-username "hector"})
;; => {:f-username "hector", :sites "www.hector.com"}
You might want to read this as well:
https://stuartsierra.com/2015/08/10/clojure-donts-redundant-map

Clojure: how to create a record inside a function?

In clojure, I would like to create a record inside a function.
I tried:
(defn foo []
(defrecord MyRecord [a b])
(let [b (MyRecord. "1" "2")]))
But it causes an exception:
java.lang.IllegalArgumentException: Unable to resolve classname: MyRecord
Any idea?
The key points
You should only use defrecord at top level.1
So, if you do need a custom record type, you should define it outside of foo (at some point in your code which gets processed before foo's definition).
Otherwise, you could just use a regular map. In particular, if foo will be creating entities of multiple "types" (at the conceptual level), it probably makes no sense to try to create a record type (a Java class) for each; the natural solution would be to use maps holding a :type key to indicate the sort of entity represented.
Why it doesn't work
The code from the question doesn't compile, because Clojure's compiler resolves class names mentioned as first arguments to new forms at compile time. ((MyRecord. "1" "2") is expanded to (new MyRecord "1" "2") during the macro expansion process.) Here the name MyRecord cannot yet be resolved to the appropriate class, because the latter has not yet been defined (it would be created by the defrecord form after foo was first called).
To get around this, you could do something horrible like
(defn foo []
(eval '(defrecord MyRecord [x y]))
(let [b (clojure.lang.Reflector/invokeConstructor
;; assuming MyRecord will get created in the user ns:
(Class/forName "user.MyRecord")
(into-array Object ["1" "2"]))]
b))
which causes a kitten to have its finalize method invoked through reflection, resulting in a gruesome death.
As a final remark, the above horrible version would sort of work, but it would also create a new record type under the same name at each invocation. This causes weirdness to ensue. Try the following examples for a flavour:
(defprotocol PFoo (-foo [this]))
(defrecord Foo [x]
PFoo
(-foo [this] :foo))
(def f1 (Foo. 1))
(defrecord Foo [x])
(extend-protocol PFoo
Foo
(-foo [this] :bar))
(def f2 (Foo. 2))
(defrecord Foo [x])
(def f3 (Foo. 3))
(-foo f1)
; => :foo
(-foo f2)
; => :bar
(-foo f3)
; breaks
;; and of course
(identical? (class f1) (class f2))
; => false
(instance? (class f1) f2)
; => false
At this point, (Class/forName "user.Foo") (assuming again that all this happens in the user namespace) returns the class of f3, of which neither f1 nor f2 is an instance.
1 Macros occasionally might output a defrecord form wrapped in a do along with some other forms; top-level dos are special, though, in that they act as if the forms they wrap were individually processed at top level.

Clojure: Adding functions to defrecord without defining a new protocol

I'm used to OO in python/java. Doing Clojure now. I came across defrecord, but it seems like I have to define a protocol for each function or set of functions I want the record to implement. Creating a new protocol creates friction. I have to name not only the function I want, but the protocol. What I'am looking for is a way to "nicely" associate a function with a record so that the function has access to the record's parameters via the this parameter, without having to define a new protocol or add a function to an existing protocol.
If you haven't tried multimethods yet, they may be closer to what you are looking for.
Define:
(defrecord Person [first middle last])
(defmulti get-name class)
(defmethod get-name Person [person] (:first person))
Use:
(def captain (Person. "James" "T" "Kirk"))
(get-name captain)
The multimethod implementation that is chosen is based on the dispatch function in defmulti (a function that takes the args passed to the function and returns a dispatch value). Quite commonly "class" is the dispatch function, as here, to dispatch on type. Multimethods support multiple independent ad-hoc or Java-based type hierarchies, default implementations, etc.
In general though, I think perhaps you might want to take a step back and consider whether you really want either protocols or multimethods. You seem to be trying to "do OO" in Clojure. While aspects of OO (like polymorphism) are great, maybe you should try thinking in alternate ways about your problem. For example, in the example I just gave, there is no compelling reason (yet) to implement get-name polymorphically. Why not just say:
(defn get-name [x] (:first x))
Do you even need a Person record at all? Would a simple map suffice? Sometimes the answers are yes, sometimes no.
In general Clojure does not provide class inheritance. You can certainly build an equivalent (even with protocols) if you really want it but generally I find there are other better ways of solving that problem in Clojure.
Excellent question.
As usual, there's a beautiful way to do things in Clojure - here's how to implement your own simple dynamic OO system (including inheritance, polymorphism and encapsulation) in 10 lines of Clojure.
The idea: You can put functions inside normals Clojure maps or records if you want, creating an OO-like structure. You can then use this in a "prototype" style.
; define a prototype instance to serve as your "class"
; use this to define your methods, plus any default values
(def person-class
{:get-full-name
(fn [this] (str (:first-name this) " " (:last-name this)))})
; define an instance by merging member variables into the class
(def john
(merge person-class
{:first-name "John" :last-name "Smith"}))
; macro for calling a method - don't really need it but makes code cleaner
(defmacro call [this method & xs]
`(let [this# ~this] ((~method this#) this# ~#xs)))
; call the "method"
(call john :get-full-name)
=> "John Smith"
; added bonus - inheritance for free!
(def mary (merge john {:first-name "Mary"}))
(call mary :get-full-name)
=> "Mary Smith"
Using the idea of mikera I developed a way to have this (OO-like classes)
;; -----------------------------------------
;; main()
;; -----------------------------------------
(def p1 (newPoint 3 4))
(def p2 (newPoint 0 0))
(call p1 :getY) ;; == 4
(call p1 :distance p2) ;; == 5
Complete example, with a "decent and organized" way to declare a OO-like class
;; -----------------------------------------
;; begin Point class
;; -----------------------------------------
(defrecord Point [x y methods] )
(def someMethods
{
:getX (fn [this] (:x this) )
:getY (fn [this] (:y this) )
:distance (fn [this other]
(def dx (- (:x this) (:x other)))
(def dy (- (:y this) (:y other)))
(Math/sqrt (+ (* dx dx) (* dy dy) ))
)
}
)
;;
;; Point constructor
;;
(defn newPoint [x y]
(Point. x y someMethods)
)
;; -----------------------------------------
;; end Point class
;; -----------------------------------------
;; -----------------------------------------
;; helper to call methods
;; -----------------------------------------
(defn call
([obj meth] ((meth (:methods obj)) obj))
([obj meth param1] ((meth (:methods obj)) obj param1))
([obj meth param1 param2] ((meth (:methods obj)) obj param1 param2))
)
;; -----------------------------------------
;; main()
;; -----------------------------------------
(def p1 (newPoint 3 4))
(def p2 (newPoint 0 0))
(call p1 :getY) ;; == ((:getX (:methods p1)) p1)
(call p1 :distance p2) ;; == ((:distance (:methods p1)) p1 p2)

Clojure: finding out if a collection is seq-able

So there's list?, seq?, vector?, map? and so on to determine what type of collection the argument is.
What's a good way of telling the difference between
a map (i.e. something that contains key-value pairs)
a collection (i.e. something that contains values)
a non collection value like a string.
Is there a better way than
#(or (seq? %) (list? %) etc)
using seq? is about as concise and clean as it gets.
clojure.contrib.core defines:
seqable?
function
Usage: (seqable? x)
Returns true if (seq x) will succeed, false otherwise.
http://clojure.github.com/clojure-contrib/core-api.html
it does what you proposed with one big or statement of
already a seq
an instance of clojure.lang.Seqable
nil
instance of Iterable
an array
a string
instance of java.util.Map
Let's not forget about sequential?:
user=> (sequential? [])
true
user=> (sequential? '())
true
user=> (sequential? {:a 1})
false
user=> (sequential? "asdf")
false
The function seq right now does only this:
(. clojure.lang.RT (seq coll))
In RT.java in the latest version of Clojure, you'll find:
static public ISeq seq(Object coll){
if(coll instanceof ASeq)
return (ASeq) coll;
else if(coll instanceof LazySeq)
return ((LazySeq) coll).seq();
else
return seqFrom(coll);
}
static ISeq seqFrom(Object coll){
if(coll instanceof Seqable)
return ((Seqable) coll).seq();
else if(coll == null)
return null;
else if(coll instanceof Iterable)
return IteratorSeq.create(((Iterable) coll).iterator());
else if(coll.getClass().isArray())
return ArraySeq.createFromObject(coll);
else if(coll instanceof CharSequence)
return StringSeq.create((CharSequence) coll);
else if(coll instanceof Map)
return seq(((Map) coll).entrySet());
else {
Class c = coll.getClass();
Class sc = c.getSuperclass();
throw new IllegalArgumentException("Don't know how to create ISeq from: " + c.getName());
}
}
An ASeq or a LazySeq is already a seq. A Seqable is something that knows how to return a seq of itself.
That leaves things like Java core classes, which should be seqable but which Clojure can't alter to add a seq method. Those are currently hard-coded into this list. I wouldn't be surprised if the implementation changed someday, maybe using protocols to extend the Java core classes instead?
All seqables implement clojure.lang.Seqable marker:
(instance? clojure.lang.Seqable x)
Clojure 1.9 provides seqable?