I have some clojure code that looks like this:
(defn rect [x y w h]
{:x x, :y y, :w w, :h h})
(def left :x)
(def top :y)
(def width :w)
(def height :h)
(defn right [r]
(+ (left r) (width r)))
(defn bottom [r]
(+ (top r) (height r)))
Now the following code seems a bit uncommon:
(def left :x)
However I don't know any other way to get encapsulation.
Suppose, I later want to represent my rect a different way.
Then relying on (:x rect) is not a good idea, because :x only works on hashmap's and records, so then I would be leaking implementation details in the api, which at least in OO languages is considered bad practice.
Now, if I decide to implement my rect in java instead, it gets even worse, because then I would have to write wrappers like:
(defn left [rect] (.getLeft rect))
to make sure the interface doesn't change.
How does clojure get around this problem?
You can use protocols.
First a Clojure record:
(defprotocol Rectangular
(left [this])
(right [this]))
(defrecord Rect [x y w h]
Rectangular
(left [this] x)
(right [this] (+ x w)))
(def my-rect (Rect. 1 2 3 4))
(right my-rect) ;=> 4
Now a Java object:
(import java.awt.Rectangle)
(extend-type Rectangle
Rectangular
(left [this] (int (.getX this)))
(right [this] (int (+ (.getX this) (.getWidth this)))))
(def my-other-rect (Rectangle. 1 2 3 4))
(right my-other-rect) ;=> 4
Clojure has protocols and types. You identify an abstraction with a protocol (like Java interfaces) and you create implementations for those abstractions. There also are multimethods which give you more freedom over how method dispatch occurs.
However, structuring your data in the way you have in your example is very common. Take a look at the Leiningen project file and the contents of Ring requests and responses. Even if you decided to completely change how you lookup the values of x and y, you can simply create a type that operates on the same abstraction as a map. In this case, that's the ILookup protocol.
Related
In Clojure, adding custom reader tags is really simple
;; data_readers.clj (on classpath, eg. src/clj/)
{rd/qux datareaders.reader/my-reader}
;; Define a namespace containing the my-reader var:
(ns datareaders.reader)
(defn my-reader [x] 'y)
;; use special tag in other namespace. Readers have to be required first.
(require 'datareaders.reader)
(defn foo [x y]
(println #rd/qux x "prints y, not x due to reader tag."))
I am trying to achieve the same thing for ClojureScript but am getting an error that #rd/qux is not defined. I am using lein cljsbuild once to build the project. Is that a limitation of ClojureScript or is it that cljsbuild builds the project before the readers have been resolved? In that case, how can I force leiningen to load the readers namespace before cljsbuild is started?
EDIT: Note that this example intends to use reader tags within ClojureScript source code and not when reading auxilliary data via read-string.
This currently isn't possible, but will be as soon as #CLJS-1194 and #CLJS-1277 are fixed. Hopefully that will happen very soon.
If you wanted to do it, just rename data_readers.clj to data_readers.cljc and use conditional readers.
As an aside, what's your use case for this?
Both #CLJS-1194 and #CLJS-1277 are fixed, so this should work as expected.
The mechanism to add a custom reader tag in cljs is different. You have to call register-tag-parser! which takes a tag and a fn.
From the cljs reader tests:
(testing "Testing tag parsers"
(reader/register-tag-parser! 'foo identity)
(is (= [1 2] (reader/read-string "#foo [1 2]")))
Your example would be:
(cljs.reader/register-tag-parser! 'rd/qux (fn [x] 'y))
(defn foo [x y]
(println #rd/qux x "prints y, not x due to reader tag."))
I am very new to Clojure. I know there is a way to include files in other files using a keyword like #include for C++. and i have done some digging and found a few things pointing to the keyword declare. Maybe I'm not using it correctly but it doesn't seem to work for me.
I am trying to write a function, for example, get_all_preds that uses another function predecessors, written in another file. the files are both under the directory src and each function is the only code in their respective files.
When i add (declare bar.clj) to the top of the foo.clj file i still get an error that bar cannot be found.
(defn get_all_preds
([tasks job]
(cond (empty? (predecessors tasks job)) (println "No predecessors")
:else (get_all_preds tasks (predecessors tasks job) (empty tasks))))
([tasks prereqs job]
(cond (empty? prereqs) job
:else (get_all_preds tasks (distinct (flatten (concat (predecessors tasks (first prereqs)) (rest prereqs))))
(distinct (cons (first prereqs) job))))))
(defn predecessors
[tasks-list job]
(cond (empty? tasks-list) 0
(= job (first (first tasks-list))) (rest (rest (first tasks-list)))
:else (predecessors (rest tasks-list) job)))
declare is for creating a var without binding it to a value.
The proper function for loading another Clojure namespace is require. To use require, you need to use namespaces, and create files with paths reflecting the semantic structure of the namespaces the files hold. The closest equivalent to #include is load, but this should be reserved for unstructured experiments where you might as well be copy / pasting into the repl, or unusual situations where namespaces are not appropriate.
A quick example:
in file src/foo/bar.clj:
(ns foo.bar)
(defn frob [] "hello")
in file src/foo/baz.clj:
(ns foo.baz
(:require [foo.bar :as bar]))
(defn frob [] (str (bar/frob) (bar/frob)))
(defn -main [& args]
(println (frob))
Running foo.baz/-main will print "hellohello" followed by a new line.
A Clojure namespace is a more structured concept than the compilation units of C, and is something that you can directly interact with in your code in a granular way. It will seem strange at first, but it allows fine grained control of what definitions are visible from various parts of your code (which in turn helps make code much easier to maintain and understand).
I'm relatively new to Clojure and going through the Clojure chapter in Seven Languages in Seven Weeks, and I can't figure out why this code from the book isn't working for me. I'm using Leiningen and Clojure version 1.5.1. As far as I can tell after careful checking, I typed the code exactly as it reads in the book.
Here is the code:
(ns seven-languages.compass)
(defprotocol Compass
(direction [c])
(left [c])
(right [c]))
(def directions [:north :east :south :west])
(defn turn [base amount]
(rem (+ base amount) (count directions)))
(defrecord SimpleCompass [bearing]
Compass
(direction [_] (directions bearing))
(left [_] (SimpleCompass. (turn bearing 3)))
(right [_] (SimpleCompass. (turn bearing 1)))
Object
(toString [this] (str "[" (direction this) "]")))
I'm running "lein repl" from within the directory ~/clojure/seven-languages (created by running "lein new seven-languages" in ~/clojure). Relative to this directory, my .clj files are in src/seven_languages. So far I've been able to successfully import and use them from the repl by typing (use 'seven-languages.filenamehere).
So, after saving the code I listed above as src/seven_languages/compass.clj, I run this from the REPL:
user=> (use 'seven-languages.compass)
nil
But then when I try to define an "instance" of the SimpleCompass, typing it exactly like in the book, this happens:
user=> (def c (SimpleCompass. 0))
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: SimpleCompass, compiling:(NO_SOURCE_PATH:1:8)
I also tried loading the file using (load-file "src/seven_languages/compass.clj"), but got the same results. Since the actual loading seemed to work as expected, I wonder if there has been some change in how defprotocol or defrecord works in versions of Clojure subsequent to when Seven Languages in Seven Weeks was written. In the introduction to the Clojure chapter, the author writes, "I’m using a prerelease version of Clojure 1.2, and it should be fully ready by the time this book is in your hands."
Can anyone tell why this code isn't working properly? If it's a version issue, how would you update this code for Clojure 1.5.1?
EDIT: Aha! I figured it out after finding this:
Clojure - deftype ignored - unable to resolve classname on tests
It's a namespace issue. I'm guessing this is a change since version 1.2 when 7LI7W was written. For whatever reason, while functions in imported files are "automatically handled" so that you can just use them directly, types are not automatically handled. You have to include the full path to the type, and make sure you use the actual path with underscores, not hyphens. I got my code to work by substituting SimpleCompass with the full path, seven_languages.compass.SimpleCompass:
user=> (def c (seven_languages.compass.SimpleCompass. 0))
#'user/c
user=> c
#seven_languages.compass.SimpleCompass{:bearing 0}
user=> (left c)
#seven_languages.compass.SimpleCompass{:bearing 3}
user=> (right c)
#seven_languages.compass.SimpleCompass{:bearing 1}
Apart from always fully qualifying the class name, you can import it and use the short name afterwards:
(import seven_languages.compass.SimpleCompass)
;; (SimpleCompass. 0) etc. will work now
Also, it's worth pointing out that defrecord creates to factory functions for you, one positional and one taking a map:
(defrecord Foo [x])
(->Foo 1)
;= #user.Foo{:x 1}
(map->Foo {:x 1})
;= #user.Foo{:x 1}
These are just regular functions and so will have been pulled in by your use call.
Relatedly, deftype, as of Clojure 1.5.1, creates the positional factory only.
How to achieve Aspect-Oriented Programming in Clojure? Do we need AOP in Clojure?
Let's say we want plain vanilla Clojure solution (no AspectJ).
Aspect-Oriented Programming is typically used to add cross-cutting functionality to code that would otherwise get hopelessly intertwined with business logic. A great example is logging - you don't really want logging code scattered everywhere in your code base.
You don't really need AOP in Clojure because it's easy to achieve this with other techniques in Clojure.
For example, you can use higher-order functions to "wrap" other functions with cross cutting functionality:
; a simple function - the "business logic"
(defn my-calculation [a b]
(+ a b))
; higher order function that adds logging to any other function
(defn wrap-with-logging [func]
(fn [& args]
(let [result (apply func args)]
(println "Log result: " result)
result)))
; create a wrapped version of the original function with logging added
(def my-logged-calculation (wrap-with-logging my-calculation))
(my-logged-calculation 7 9)
=> Log result: 16
=> 16
AOP IMHO is just an artifact of certain kinds of static programming languages. AFAIKS it's usually just a bunch of non-standard compiler extensions. I've not yet seen any application of AOP that can't be solved better & natively in more dynamic languages. Clojure is certainly dynamic enough, and that's without even considering macros.
I may be wrong, but if so, I'd need to see an actual AOP use case that can't be implemented just as well in pure clojure.
Edit: just to be clear: I refuse to see things like elisp's advice as aspect oriented. In dynamic languages, those are just techniques to be used whenever you need them, with no need for language support other than rebinding of function definitions - which all lisps support anyway.
There's no need to treat them as special - you can easily define your own defadvice-like function in clojure. See for example, compojure's wrap! macro, which is actually deprecated since you generally don't even need it.
Aspect oriented programming is a great way to achieve seperation of concernes in Java. Clojure's composable abstractions achieve this very well. See this question also. The topic is covered really well in The Joy Of Clojure.
as for an example of Aspect Oriented Clojure by another name check out the Ring web framework
Well you could be more AOP w/ Clojure easily. Just use metadata in functions to informe when you want logs:
(defn ^:log my-calculation
[a b]
(+ a b))
Then you can redefine all functions, wrapping them w/ logging automatically. Part of this code (together w/ unwrap functions bellow):
(defn logfn
[f topic severity error-severity]
(fn [& args]
(try
(if severity
(let [r (apply f args)]
(log* topic {:args args, :ret r} severity)
r)
(apply f args))
(catch Exception e
(if error-severity
(let [data {:args args, :error (treat-error e), :severity error-severity}]
(log* topic data error-severity)
(throw e))
(throw e))))))
(defn logfn-ns
"Wrap function calls for logging on call or on error.
By default, do nothing. When any :log or :log-error, enables logging. If ^:log,
only log on error (default severity error).
Can customize log severity w/ e.g. ^{:log info} or on error log severity likewise."
[ns alias]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)
f #v
log (-> v meta :log)
log-error (-> v meta :log-error)]
:when (and (ifn? f)
(-> v meta :macro not)
(-> v meta :logged not) ;; make it idempotent
(or log log-error))]
(let [log (if (= log true) nil log)
log-error (or log-error "error")
f-with-log (logfn f
(str alias "/" s)
log
log-error)]
(alter-meta! (intern ns s f-with-log)
(fn [x]
(-> x
(assoc :logged true)
(assoc :unlogged #v)))))))
(defn unlogfn-ns
"Reverts logfn-ns."
[ns]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)]
:when (-> v meta :logged)]
(let [f-without-log (-> v meta :unlogged)]
(alter-meta! (intern ns s f-without-log)
(fn [x]
(-> x
(dissoc :logged)
(dissoc :unlogged)))))))
You just call (log/logfn-ns 'my.namespace "some alias") and all is wrapped w/ logging (and some).
PS: My custom logger above have a topic which is "some alias/function name"
PS2: Also wrapped w/ try/catch.
PS3: Didn't like this so much. Reverted to have explicit logging.
After a few weekends exploring Clojure I came up with this program. It allows you to move a little rectangle in a window. Here's the code:
(import java.awt.Color)
(import java.awt.Dimension)
(import java.awt.event.KeyListener)
(import javax.swing.JFrame)
(import javax.swing.JPanel)
(def x (ref 0))
(def y (ref 0))
(def panel
(proxy [JPanel KeyListener] []
(getPreferredSize [] (Dimension. 100 100))
(keyPressed [e]
(let [keyCode (.getKeyCode e)]
(if (== 37 keyCode) (dosync (alter x dec))
(if (== 38 keyCode) (dosync (alter y dec))
(if (== 39 keyCode) (dosync (alter x inc))
(if (== 40 keyCode) (dosync (alter y inc))
(println keyCode)))))))
(keyReleased [e])
(keyTyped [e])))
(doto panel
(.setFocusable true)
(.addKeyListener panel))
(def frame (JFrame. "Test"))
(doto frame
(.add panel)
(.pack)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.setVisible true))
(defn drawRectangle [p]
(doto (.getGraphics p)
(.setColor (java.awt.Color/WHITE))
(.fillRect 0 0 100 100)
(.setColor (java.awt.Color/BLUE))
(.fillRect (* 10 (deref x)) (* 10 (deref y)) 10 10)))
(loop []
(drawRectangle panel)
(Thread/sleep 10)
(recur))
Despite being an experienced C++ programmer I found it very challenging to write even a simple application in a language that uses a radically different style than what I'm used to.
On top of that, this code probably sucks. I suspect the globalness of the various values is a bad thing. It's also not clear to me if it's appropriate to use references here for the x and y values.
Any hints for improving this code are welcome.
Those ifs in keyPressed can be replaced with a single case. Also, the dosync can be moved outside to wrap the case. In fact, alter can be moved out too, so that if you e.g. decide to change it to commute, there's just the one place to make the change. The result:
(def panel
(proxy [JPanel KeyListener] []
(getPreferredSize [] (Dimension. 100 100))
(keyPressed [e]
(let [keyCode (.getKeyCode e)]
(dosync
(apply alter
(case keyCode
37 [x dec]
38 [y dec]
39 [x inc]
40 [y inc])))
(println keyCode)))
(keyReleased [e])
(keyTyped [e])))
You could also rewrite the imports more concisely:
(import [java.awt Color Dimension event.ActionListener])
(import [javax.swing JFrame JPanel])
-- whether you'd want to is a matter of style.
I would rename drawRectangle to draw-rectangle (that's the idiomatic style for function names in Clojure) and, more to the point, rewrite it as a pure function accepting the coordinates as explicit arguments. Then you could write a small wrapper around that to use your Refs, if indeed your design would benefit from the use of Refs. (Hard to say without knowing how you might want to use & modify them etc.)
Prefer while to (loop [] ... (recur)) (see (doc while) and (clojure.contrib.repl-utils/source while)).
Also -- and this is important -- don't put anything except definitions at top level. That's because top-level forms are actually executed when the code is compiled (try loading a library with a (println :foo) at top level). That infinite loop should be wrapped inside a function; the standard name for a "main" function in Clojure is -main; same goes for panel and frame. This doesn't apply when playing around at the REPL, of course, but it's an important gotcha to know about.
Incidentally, (doto foo ...) returns foo, so you can just write (doto (proxy ...) (.setFocusable true) ...).
Otherwise, I'd say the code is fine. Normally you'd want to put it in a namespace; then all the imports would go in the ns form.
HTH
Edit, while writing the below post in a hurry I forgot to say you must not put parens around constants eg java.awt.Color/WHITE.
In addition to Michał's comments:
when you use an infinite loop, condition it with an atom (eg #switch) thus you'll be able to stop it (unless the loops runs on the repl thread -- so lauch it in a separat thread with "future")
you use refs, so it means the values of x and y are intended to be coordinated (in your code they are not: each update is independent); hence in drawRectangle you should wrap the reads in a dosync to be sure that you get a consistent view -- again in your actual code it doesn't matter because x and y are always updated independently.
hth,
(shameless plug: http://conj-labs.eu/)
Although not exactly Clojure advice - consider using KeyAdapter instead of KeyListener. That way you won't have to provide empty implementations for keyReleased and keyTyped. It's generally a good rule to use adapter classes when you're not needing all of the methods of a Listener interface.