Fix/enhance ^:export to work with properties that will be modified externally


  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Declined
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
  • Patch:


Thin line between bug/enhancement here, but whatever...

Given this code:


(def ^:export baz 42)

(defn ^:export quux [] baz)

Advanced compilation yields code where baz is inlined, and even the property itself disappears. Whatever a downstream user/app/lib does to, quux will always return 42. Here's that code:

var d = this;
function f(g, e) {
  var b = g.split("."), a = d;
  b[0] in a || !a.execScript || a.execScript("var " + b[0]);
  for (var c;b.length && (c = b.shift());) {
    b.length || void 0 === e ? a = a[c] ? a[c] : a[c] = {} : a[c] = e;
;f("", 42);
f("", function() {
  return 42;

Initially, I thought this was only because baz was a scalar, but the problem remains the same if an exported fn is returned by another fn; if the former is set to a different value downstream, the latter will continue returning the original that it closed over.

Based on this exchange with a GClosure compiler contributor, we need to use the @expose annotation on each exported property, and export the symbol for each intervening "namespace" segment in order to ensure that functions that refer to exported properties will return the same value that downstream users (might) mutate.



Vote (0)
Watch (1)


  • Created: