Hacker News new | ask | show | jobs
by ICWiener 4101 days ago
Regarding 1., I don't think it follows that the pattern-macro will end up in one giant namespace. I'd love to understand why you think so.

And for 2, even though what you say seems desirable on the surface, you still approaches the problem in a way that is too fuzzy, or abstract. Just as saying "we should write more secure code" and then failing to attack the problem directly.

No offense, but even though you may have a nice idea, your explanation is a little too handwavy.

1 comments

Regarding 2: The article punts on the question of how to implement such a system, because I think it's a hard question. I could have been clearer about that, and maybe in future I'll write an article speculating on some ways one could approach the problem. But I think it's an underappreciated problem, and I hope this article will spur other people to consider it.

Re 1:

In a.clj:

    (ns a (:refer-clojure))

    (defmulti if-match*
      (fn [pat _ _ _] (if (list? pat) (first pat) (type pat))))

    (defmacro if-match [pat expr then else]
      (if-match* pat expr then else))

    (defmethod if-match* clojure.lang.Symbol
      [pat expr then else]
      `(let [~pat ~expr] ~then))
In b.clj:

    (ns b (:refer-clojure) (:require a))

    ;; a 'foo pattern-macro that does negation
    (defmethod a/if-match* 'foo [pat expr then else]
      `(a/if-match ~(second pat) ~expr ~else ~then))
In c.clj:

    (ns c (:refer-clojure) (:require a))

    ;; a 'foo pattern-macro that is the identity pattern
    (defmethod a/if-match* 'foo [pat expr then else]
      `(a/if-match ~(second pat) ~expr ~then ~else))
Now, at the repl:

     user=> (use 'a)
     nil
     user=> (require 'b)
     nil
     user=> (if-match (foo x) 'yes x 'no)
     no
     user=> (require 'c)
     nil
     user=> (if-match (foo x) 'yes x 'no)
     yes
Note that 'require doesn't actually import the symbols defined by b.clj or c.clj, and despite that we're able to use the pattern-macro 'foo they define, because they're modifying if-match's dispatch-table. So our pattern-macros aren't being scoped the same way our regular macros are. I think this is wrong. Moreover, our pattern-macros have a single namespace, so we get collisions between what b.clj defines 'foo to mean and what c.clj defines it to mean, which is why (if-match (foo x) 'yes x 'no) changes behavior after the (require 'c).