Adding -var-missing to Clojure Namespace

Motivation

I Just need some mechanism like “methondMissing” in Ruby. When a nonexistent var is called, the lookup system will try to call a “-var-missing” function in the namespace. This function should return a var and clojure compiler assumes this var as the one it was looking for.

For example, in the shake library:

(ns shake.core)

(defn -var-missing [sym]
  (create-executable-var sym))

To support lazy loading, shake 0.3.0 won’t read your path. It will now create vars on demand. So on calling sh/uname, a var named `uname` will be created. And to create a var, just use intern or eval.

(require '[shake.core :as sh])
(sh/uname -a)

How to

I’m sorry there is no way to implement this except hacking into Clojure’s compiler. Fortunately, it’s not too difficult to find out the injection point.

As you may know, there are two phases in Clojure compiler: expanding macros and evaluating forms. Both phases will look up vars to find macros or values. So we should take care both of them.

All code diff is here:

Conclusion

Adding -var-missing is just an attempt to implement lazy loading of vars. And it provides another smooth syntax for writing DSLs. But actually, Clojure’s macro system provides a great metaprogramming mechanism. So in most case, you don’t have to hack into the Compiler like this. Just put your DSL into a top level macro, and you can get them done all in clojure scripts.

New shake syntax

As shake goes public, I received a lot of feedback. The top issue is about using clojure variables in shake macros. Now it has been fixed in 0.2.2. Let me show you the new syntax.

Using vars, local bindings in shake macros:

(require '[shake.core :as sh])

(let [x "/home/nsun"]
  (sh/ls -l $x))

So you have to prefix the clojure variable with a dollar sign. This is quite similar to what we did in shell programming.

And more interesting, you can also use a $ prefixed clojure form in shake:

(sh/curl $(format "https://github.com/%s" "sunng87"))

Thanks to Clojure macro system, it has great flexibility to manipulate symbols and code lists, making inventing new syntax much easier than other languages. Shake can be a great example in describing macro system.

Shake: Every Program Can Be a Clojure Function

You might have heard of sh, which brings python an interface to call subprocesses. The API of sh is pretty cool: Every command can be treated as a python function, and imported from a namespace. Options and arguments are passed in as python string.

But I think in Clojure, things can be even cooler. We dynamically create symbols for every program. We will have a beautiful DSL so you don’t have to quote arguments as string. So when you are using this library, it may look like:

(ls)
(uname -a)
(ip -4 addr)

And actually it’s just like that! I create this library called shake. When you load `shake.core`, it indexes all the executables in your path. Then all programs are available to you in a clojure native way.

(use 'shake.core)
(uname -a) ;; returns a java.lang.Process, that you can send data, read data and wait for termination.

;; for those just need output
(alter-var-root *print-outpt* (fn [_] true))
(uname -a)
;; it prints ...

There’s a lot of fun in implementing this library. First, to be able to use custom symbol in the DSL, you have to make these executables as macros. Second, find a way to programmably create vars which are named by string. The power of Clojure enables all the ideas and makes it possible. Check out the source code if you are interested in: https://github.com/sunng87/shake/.

cljts: Java Topology Suite for Clojure

I almost forgot to announce this library I made half of a year ago. This library is aiming to bring Clojure to GIS. So you can manipulate geometry objects with a set of clojure functions.

The library covers :

  • Geometries defined in Simple Feature Spec
  • Spatial relationship test, based on DE-9IM.
  • IO functions, WKT and WKB support
  • some spatial analysis functions such as buffer, convex-hull

Also, this week Alexey Pushkin sent pull request and added support for Perpared Geometry and Affine transformations.

The current release of cljts is 0.2.0-SNAPSHOT. You can find API document at here.

If you are also interested in bringing clojure to GIS, feel free to get connected and hope I could help you.

丰宁草原

来了北京以后一直没有停止到处游走的脚步,这周末去了丰宁的坝上草原。第一回去草原,第一回骑马,第一回看日出。

丰宁在承德市,我们去的地方叫大滩镇,在丰宁县的北部。晚上九点从北京出发,达到大滩的农家院已经是半夜两点了。农家院的住宿条件还不错。当天天气晴朗,晚上抬头能看到多年未见漫天星辰。本来约好当天去看日出,谁知睁开眼的时候屋里都满是阳光了。上午就直接骑马去草原:村里的旅游经济搞得红火,有开旅店的,有养马领路的。

第一回骑马,或者说第一回和个动物挨这么近。前半程紧张的够呛,坐在马上浑身紧着,都不知道哪用力(或者说全身都在使劲)。骑着骑着渐渐放松,知道用腿加紧马,手拽着缰绳。我把马的速度戏分为三档:一档起步,踱步子;二档小跑,颠着;三档叫奔,后腿蹬起来,骑着有种要飞的感觉(或者说要摔下来的感觉)。这里二档是最难受的,颠得屁股生疼,五脏六腑都快倒出来。开始的时候没觉得累,反倒是休息了一下,开始背疼腰疼腿疼,等到第二天早晨居然就真的弯不下腰了。不过侧面倒是说明,别看这好像是坐在马上,全身肌肉到是没闲着。腰背这部分常年没练,疼点也正常。再说马,马是个随大流的动物,跑不跑全看他认识的这一伙马跑不跑。他要是不想动,再怎么蹬也没有用。当然这马也能被理解,就像那句“一定有一些马,想回到古代”。

第二天早上终于坚定地看到了日出。在满天月亮金星木星的时辰披上长袖出门,看着背后的天色,一路走走跑跑生怕阳光不等看日出的人就位就露出来。坐到山坡上,等天边的第一缕阳光的心情,是美好的。不过更美好的是等到阳光普照后,你踱着步子从山上下来,穿过牛群马群羊群庄稼蔬菜,再被马群穿过。拖上长长的影子,一路鸡鸣犬吠马啸牛叫,往粉雾里的村庄走。

上午去的闪电湖,是草原上一个水坝成湖。有水的地方能有灵性,至少在干燥的地方,一片湖泊让人精神放松,有工夫想点有灵性的事。远处的大坝分隔,这水天相接,像一面镜子一样,互相照着。我在这打破了自己上个月的北纬的纪录,41.656度。

DSC_0077

DSC_0134

DSC_0146

DSC_0161

DSC_0165

DSC_0170

DSC_0176

DSC_0185

DSC_0209