Showing posts with label Java Interop. Show all posts
Showing posts with label Java Interop. Show all posts

Monday, 6 August 2012

Macros I've been using

Here are a few macros I've been using.

The epic trio of Debug macros:

 

1. The regular, simple debug:

(defmacro ?? [& form]
  `(let [result# ~form]
     (println "DEBUG:" '~form "=>" result#)
     result#))

This really is the most simple version there is. If you want to know what a particular expression you cannot for some reason simply extract returns, add ?? as the first element of that expression.

(+ 2 3 (* 4 5) (?? - 5 3))
DEBUG: (- 5 3) => 2
=> 27

2. The regular, abridged debug:

(defmacro ? [& form]
  `(let [result# ~form]
     (println "DEBUG:" '~(map #(if (coll? %)
                                 "..."
                                 (str %)) form) "=>" result#)
     result#))

This one will replace sub-forms in the form with "...". This is useful if you don't want your output too cluttered:

(? + 2 3 (* 4 5) (- 5 3))
DEBUG: (+ 2 3 ... ...) => 27
=> 27

3. The deep inspect:

(defmacro ??? [& form]
  `(? ~@(map #(if (coll? %)
                `(??? ~@%)
                %) form)))

This one places an abridged debug "?" in every form in the tree in which it is placed. For example:

(??? + 2 3 (* 4 5) (- 5 3))
  is equivalent to
(? + 2 3 (? * 4 5) (? - 5 3))

Thus giving:

(??? + 2 3 (* 4 5) (- 5 3))
DEBUG: (* 4 5) => 20
DEBUG: (- 5 3) => 2
DEBUG: (+ 2 3 ... ...) => 27
=> 27

So, recapping, add one to three question marks, the more you put, the more info you get.

It would be, of course, trivial to implement ????, which would be equivalent to a tree full of ??'s, but what's the point? Since ??? is intended to be used on trees, not shallow expressions, the verbosity of ?? on every level would be thorough overkill.

Multi-set!:

 

(defmacro multi-set! [target & pairs]
  (let [x (gensym)]
    `(let [~x ~target]
       ~@(for [[field value] pairs]
           `(set! (. ~x ~field) ~value)))
       ~x)))

Due to working with java.awt.GridBagConstraints a lot recently, I got annoyed with how often I have to rewrite the line (.set! (.[some field] c) [some value]). So, being lazy as hell, I'd much rather write

(multi-set! [instance-expr]
  ([field] [value])
  ([field] [value])
  ([field] [value])
  ...)

In fact, I wrote a macro called "constraints" for working with GridBagConstraints, but it's a tad too long to share here. Also, it's boring.

This macro actually uses a fun trick, aka displays a subtle problem with the auto-gensym feature (symbols with # appended are replaced with a unique name, in order to avoid name clashes).

If you were to write...

(defmacro multi-set-wrong! [target & pairs]
  (let [x# ~target]
    ~@(for [[field value] pairs]
        `(set! (. x# ~field) ~value))
    x#))

In this case, the auto-gensymmed symbols x# in the let-form and inside the set!-form are DIFFERENT symbols, because they are within DIFFERENT quotes. So, this version doesn't work as intended. In fact, the generated (set! ...) expressions will throw an exception, because the symbol x# in them could not be found.

Thus, in the actually working version, we create a symbol by hand, and use that symbol throughout the macro. This is a trick I learned from reading the source of the doto macro (I had a hunch I'd find something useful there, because the macro works similarly to mine - I was right!).

Convenient Map Writing Macros: 


More than once, I've written macros that simply implement a more convenient syntax for maps. For example, since I'm learning japanese right now, I wrote a program to quiz me on Hiragana. For that, I had to store all corresponding Unicode characters in the program, and map them to the Romaji (latin) transcriptions.

(defmacro defseries [group & chars]
  `(def ~group
     ~(into [] (map (fn [[name code]]
                      (let [code (+ code 0x3000)]
                         {:name name, :code code}))
                     chars))))

While this wasn't the perfect approach in this case (here, I still had to type char => pairs, just with smaller values and less overhead), but it still vastly reduced the typing I had to do. I do things like that quite frequently.

(defseries a ("a" 0x42) ("i" 0x44) ("u" 0x46) ("e" 0x48) ("o" 0x4A))

I typed out roughly 15-16 series like that. So I did save me some typing with just a tad of thinking.

That's it for now.

N.

Thursday, 14 June 2012

VK_VERYLONGKEYNAME (on reflection in Clojure)

So, I'm still writing a game. As it happens with games, I rely on keypresses for the user to tell me what he wants to do. That made me fall back on Java's KeyListener/KeyAdapter facilities.

The basic idea is that I get callbacks with information about the pressed key as argument (WARNING: GROSS OVERSIMPLIFICATION.), among other things the keycode, which is an integer. Now, I'm supposed to dispatch it using constants defined in KeyListener/KeyAdapter/KeyEvent/probably some other places.

Problem?

It's a lot of typing in Clojure. Especially since each constant is called VK_(something). I had large maps looking like that:

{ KeyEvent/VK_UP [some function]
  KeyEvent/VK_DOWN [some function]
  KeyEvent/VK_RIGHT [some function]
... }

You get the idea. Since I have several keymaps, that gets annoying quickly. So I started to define aliases for some frequently used ones in a seperate "keys" namespace. Now I only had to write, for example, "keys/up" instead of "KeyAdapter/VK_UP". That's a lot of saved space (and some gained readability).

But that introduced something else that annoyed me: Some of the more rare keys were still written out fully, and it created an aesthetic discrepancy, which upset my minor OCD. Besides, having to redefine tons of variables by hand isn't particularly elegant in itself.

(Disclaimer: I am aware of clojure.contrib/import-static. But I don't rely on that library enough to warrant including it in my project just for this.)

Sure enough, there is a better way.
The first nugget of information I needed was... how to get a list of all fields in a Java class?

Of course, Stack Overflow helped me there. It's

(clojure.reflect/reflect java.awt.event.KeyEvent)

It spews out a LOT of things like this:

{:bases #{java.awt.event.InputEvent},
 :flags #{:public},
 :members
 #{{:name VK_F17,
    :type int,
    :declaring-class java.awt.event.KeyEvent,
    :flags #{:static :public :final}}
   {:name VK_DEAD_DOUBLEACUTE,
    :type int,
    :declaring-class java.awt.event.KeyEvent,
    :flags #{:static :public :final}}
...}

This is the abridged pretty-print output of the stuff. We know all the VK_ fields are keycodes. Everything else falls in place itself, basically. Most of what I need I covered in a previous post already.

We want to:
1. From the list of members, filter out everything that is not a keycode.
2. Define the aliases over it.

Simple enough.

(->> (clojure.reflect/reflect java.awt.event.KeyEvent)
     (:members) (map :name) (filter #(.startsWith (str %) "VK_")))

This yields us a list of symbols (which I am grateful for, as it simplifies the next step) of all fields that contain keycodes. Now, as in my earlier post, we doseq over the list and define the aliases via eval in the loop. I also wanted the VK_ dropped and the entire name downcased, but that's just my whim.

(doseq [sym (->> (clojure.reflect/reflect java.awt.event.KeyEvent)
            (:members) (map :name) (filter #(.startsWith (str %) "VK_")))]
  (eval `(def ~(symbol (.toLowerCase (drop 3 (str sym))))
           (. java.awt.event.KeyEvent ~sym))))

That's it. Now, there are vars like "a", "up" and so on that hold the corresponding keycodes. I put the entire thing into a new namespace (game.keys) that I require like that:

(ns game.some-module
  (:require [game.keys :as keys])

Another nonproblem solved! :D