I’ve been trying out Clojure lately. Clojure is a new lisp dialect, that is hosted on the JVM and interoperates nicely with it. You can easily use Java methods, classes and libraries. I’ve been using it a little bit, watching some videos about it on blip.tv by it’s author, Rich Hickey, which really is a brilliant guy. You should check them out as well, they give you a pretty good introduction to the language.
Compared to Common Lisp, which I really like allot as well, Clojure does feel a little bit more modern. For example, being not limited to reader support for lists, but also having maps and vectors (like arrays) as first class citizens, is really nice. And then theres the huge emphasis on multithreading support in a really nice way without locks and condition variables but with a stm (software transactional memory). Clojure is a functional language and focuses on immutability of data structures compared to Common Lisp, which also allows a more imperative style, if you want to. In Clojure, you’re forced to a functional style, which might seem like a downside at first, but which makes it possible to have some pretty neat features concerning multithreaded programming support. Since all the datastructures are immutable, there’s no need do use locks when having multiple threads sharing them. I suggest checking out the videos and to give Clojure a try. It seems very promising and it’s having quite a publicity boost right now. Just google for it, take a look on some mailinglists or checkout reddit etc. You’ll find plenty comments, links and blogposts about it (like this one
).
So since I thought it’s always nice to try to port an existing little application from a language I already know to a new one I want to learn, I tried to port a very small programm CallToPower, a collegue from university, wrote and posted on his website. I pretty much copied it straightly to Clojure, changing some parts.
Now I know this might not be the best way to write it in Clojure. But it was my real first (although very small) programm in Clojure and I wanted to make it as close to the original, as possible. Basically, what it does is display some values of some system properties you can choose by pressing the appropriate. Nothing fancy, but it shows some Clojure related stuff pretty well.
So here’s the code, use it as you like:
(ns sysinfo (:gen-class) (:import (java.awt BorderLayout GridLayout) (java.awt.event ActionEvent ActionListener) (javax.swing JFrame JPanel JLabel JButton))) (def *x-coord* 30) (def *y-coord* 30) (def *width* 800) (def *height* 230) (def *prog-name* "SysInfo 1.0 [Clojure]") (def *visible* true) (def *resizable* true) (def *frame* nil) (def *label-property-mappings* { "OS Name" "os.name", "OS Architecture" "os.arch", "Java Classpath" "java.class.path", "Java Version" "java.version", "Current working directory" "user.dir", "Resize to default" "Resize to default", "Clear" " "}) (defn resize-frame [frame a b awidth bheight] (doto frame (.setBounds a b awidth bheight))) (defn set-label-text [label text] (doto label (.setText text))) (defn button-listener "Returns a ActionListener, which sets the text of the content label (label-content) to the appropriate system property (System.getProperty)." [property label frame] (proxy [ActionListener] [] (actionPerformed [evt] (let [system-property-value (. System getProperty property)] (if (not (.equalsIgnoreCase property "Resize to default")) (if (not (.equalsIgnoreCase property " ")) (set-label-text label (str (.getActionCommand evt) ": \n" system-property-value)) (set-label-text label property)) (resize-frame frame *x-coord* *y-coord* *width* *height*)))))) (defmacro doto-each "Macro, that works like doto-macro, only that it does it for each object in objects. varname is bound to each object in turn inside of the body (forms) and can be used to access the current object, if needed." [[varname [& objects]] & forms] `(do ~@(map (fn [f] `(let [~varname ~f] (doto ~f ~@forms))) objects))) (defmacro add-each "Macro, that calls .add on to-object with each object in objects." [to-object [& objects]] `(do ~@(map (fn [o] `(.add ~to-object ~o)) objects))) (defn create-new-sysinfo-window "Creates the main form and returns it. Mainly GUI-related stuff (javax.swing)." [] (let [frame (JFrame. "Adztec-Independent.de: SysInfo Clojure-style!") panel-header (JPanel.) panel-main (JPanel. (BorderLayout.)) panel-left (JPanel. (GridLayout. 6 1)) panel-south (JPanel. (GridLayout. 1 1)) ;; labels label-header (JLabel. "System Information") label-blank (JLabel. " ") label-content (JLabel. " ") label-adztec-indep (JLabel. "by www.adztec-independent.de")] (.setHorizontalAlignment label-blank (JLabel/CENTER)) (.setHorizontalAlignment label-adztec-indep (JLabel/CENTER)) ;; buttons (let [btn-java-cp (JButton. "Java Classpath") btn-java-version (JButton. "Java Version") btn-os-name (JButton. "OS Name") btn-os-arch (JButton. "OS Architecture") btn-current-working-dir (JButton. "Current working directory") btn-resize-to-default (JButton. "Resize to default") btn-clear-all (JButton. "Clear")] (do ;; add button-listener to all buttons (doto-each [btn [btn-java-cp btn-java-version btn-os-name btn-os-arch btn-current-working-dir btn-resize-to-default btn-clear-all]] ;; add listener to button (.addActionListener (button-listener (get *label-property-mappings* (.getText btn)) label-content frame)))) ;; add buttons to panel (add-each panel-left [btn-java-cp btn-java-version btn-os-name btn-os-arch btn-current-working-dir]) (add-each panel-south [btn-resize-to-default btn-clear-all]) ;; add labels to panel (add-each panel-header [label-header label-blank]) (.add panel-south label-adztec-indep) ;; pack on frame (let [content-pane (.getContentPane frame)] (add-each content-pane [panel-main label-content]) (doto content-pane (.add BorderLayout/NORTH panel-header) (.add BorderLayout/WEST panel-left) (.add BorderLayout/SOUTH panel-south))) (doto frame (.pack) (.setTitle *prog-name*) (resize-frame *x-coord* *y-coord* *width* *height*) (.setVisible *visible*) (.setResizable *resizable*) (.setDefaultCloseOperation JFrame/HIDE_ON_CLOSE))) frame)) ;; return frame (defn -main "Main function. Gets called by the system, if used as an executable .jar file." [] (let [*frame* (create-new-sysinfo-window)] (. Thread (sleep 100)))) |


One Response
Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.
Hey, die System Properties sehen echt genau so aus wie die in Java geschriebenen (ist ja auch quasi Java
)
Schon cool!