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.
Related
Is it ok to use binding with core.async? I'm using ClojureScript so core.async is very different.
(def ^:dynamic token "no-token")
(defn call
[path body]
(http-post (str host path) (merge {:headers {"X-token" token}} body)))) ; returns a core.async channel
(defn user-settings
[req]
(call "/api/user/settings" req))
; elsewhere after I've logged in
(let [token (async/<! (api/login {:user "me" :pass "pass"}))]
(binding
[token token]
(user-settings {:all-settings true})))
In ClojureScript1, binding is basically with-redefs plus an extra check that the Vars involved are marked :dynamic. On the other hand, gos get scheduled for execution1 in chunks (that is, they may be "parked" and later resumed, and interleaving between go blocks is arbitrary). These models don't mesh very well at all.
In short, no, please use explicitly-passed arguments instead.
1 The details are different in Clojure, but the conclusion remains the same.
2 Using the fastest mechanism possible, setTimeout with a time of 0 if nothing better is available.
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 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.
I've written a rather primitive test program (I am writing a wrapper around LWJGL's OpenGL classes for mostly aesthetic reasons, and I decided to bring multi-threading in there because I actually never wrote a concurrent program before). When the program finishes, I always get the warning
I actually get the warning before the program enters the main function. Sorry for the confusion (I think this may not be my program at all, but rather something in clojure itself):
Reflection warning, NO_SOURCE_PATH:1 - call to invokeStaticMethod can't be resolved.
I don't get any warnings during compilation though, which I find rather strange. Anyway, here is the program:
(ns opengltuts.core
(:import (org.lwjgl.opengl GL11 Display))
(:use opengltuts.opengl)) ;my wrapper
(def world-state (ref {:running true :color [1.0 0.0 0.0 1.0]}))
(defn render-world [state]
(apply glClearColor (:color state))
(glClear GL11/GL_COLOR_BUFFER_BIT)
(Display/update))
(defn render []
(Display/create)
(loop []
(let [world #world-state]
(when (:running world)
(do (render-world world)
(recur)))))
(Display/destroy))
(defn -main []
; without the annotation, I get a warning here too.
(let [render-thread (doto (Thread. ^Runnable render) (.start))]
(Thread/sleep 3000)
(dosync (commute world-state assoc :color [0.0 1.0 0.0 1.0]))
(Thread/sleep 3000)
(dosync (commute world-state assoc :running false))
(.join render-thread)))
This probably isn't too idiomatic (I heard that in Clojure you normally don't start threads with new Thread, but rather with Agents or something, but I don't fully grasp how that works yet), but I guess for such a short program that doesn't matter.
Your Clojure source code is being loaded and compiled at runtime (see http://clojure.org/compilation), which is why you don't see the reflection warning until program execution.
It is difficult to determine where you're making a reflective call against a static method, so here are steps I recommend:
Add (:gen-class) to your (ns) declaration
Add (set! *warn-on-reflection* true) or (binding [*warn-on-reflection* true] body) where you suspect the reflective call is occurring.
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.