set!

254 views
Skip to first unread message

Mark Engelberg

unread,
Mar 13, 2013, 2:39:31 PM3/13/13
to clojure
In Clojure, there are a handful of global variables that you can set!, for example
(set! *warn-on-reflection* true)

Is there any mechanism for providing a similar feature in a user library?

Michael Klishin

unread,
Mar 13, 2013, 3:06:04 PM3/13/13
to clo...@googlegroups.com
2013/3/13 Mark Engelberg <mark.en...@gmail.com>

In Clojure, there are a handful of global variables that you can set!

They are not global, they reside in clojure.core which is referred to automatically.

user=> *warn-on-reflection*
false
user=> clojure.core/*warn-on-reflection*
false
--
MK

http://github.com/michaelklishin
http://twitter.com/michaelklishin

Mark Engelberg

unread,
Mar 13, 2013, 4:35:42 PM3/13/13
to clo...@googlegroups.com
OK, thanks.  The apparent "globalness" is not the piece I want to imitate.  I want to make a var available for users to set!, where the var controls overall behavior of how the library operates.

I understand that I can just declare the var dynamic, and then they can control it with the binding construct, but I want users to be able to set! it once and forget about it.

I believe one can mimic the functionality with alter-var-root! (I haven't tried it though), but I'd rather imitate core's style of using set! for those sorts of overall controlling variables.

I'm generally of the philosophy that ideally, a language should make available for users any features it uses in its own built-in libraries, so I'm hoping there's a way to do it.

--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Marko Topolnik

unread,
Mar 13, 2013, 5:06:38 PM3/13/13
to clo...@googlegroups.com
On Wednesday, March 13, 2013 9:35:42 PM UTC+1, puzzler wrote:
OK, thanks.  The apparent "globalness" is not the piece I want to imitate.  I want to make a var available for users to set!, where the var controls overall behavior of how the library operates.

I understand that I can just declare the var dynamic, and then they can control it with the binding construct, but I want users to be able to set! it once and forget about it.

As far as I understand it, set! modifies the thread-local binding, just like the binding macro, but doesn't delimit a definite scope of validity for the binding. You can set! any dynamic var with the same semantics.

-Marko
 

Cedric Greevey

unread,
Mar 13, 2013, 5:09:21 PM3/13/13
to clo...@googlegroups.com
To expand on what Marko said, the set!able Vars that come with Clojure just have thread-local bindings created already in the REPL thread. They're really only meant to aid developers working at the REPL, rather than to be set! as part of normal running code.


 

--

Michael Klishin

unread,
Mar 13, 2013, 5:36:30 PM3/13/13
to clo...@googlegroups.com

2013/3/14 Mark Engelberg <mark.en...@gmail.com>

I believe one can mimic the functionality with alter-var-root! (I haven't tried it though), but I'd rather imitate core's style of using set! for those sorts of overall controlling variables.

Mark Engelberg

unread,
Mar 13, 2013, 5:39:16 PM3/13/13
to clo...@googlegroups.com
On Wed, Mar 13, 2013 at 2:09 PM, Cedric Greevey <cgre...@gmail.com> wrote:
To expand on what Marko said, the set!able Vars that come with Clojure just have thread-local bindings created already in the REPL thread. They're really only meant to aid developers working at the REPL, rather than to be set! as part of normal running code.


Well, there are things like *unchecked-math* which seem like they are intended for uses other than working at the REPL.

Mark Engelberg

unread,
Mar 13, 2013, 5:46:06 PM3/13/13
to clo...@googlegroups.com
On Wed, Mar 13, 2013 at 2:06 PM, Marko Topolnik <marko.t...@gmail.com> wrote:


As far as I understand it, set! modifies the thread-local binding, just like the binding macro, but doesn't delimit a definite scope of validity for the binding. You can set! any dynamic var with the same semantics.

You can't just set! any dynamic var, you can only set! vars that are both dynamic *and* have been bound again with the binding construct.

=> (def ^:dynamic a 2)
#'user/a
=> (set! a 3)
IllegalStateException Can't change/establish root binding of: a with set  clojure.lang.Var.set (Var.java:233)
=> (binding [a 1] (set! a 3))
3


This is why I'm puzzled about how things like (set! *unchecked-math* true) are handled.  Clearly, in this special case you can use set! without first calling binding.

Mark Engelberg

unread,
Mar 13, 2013, 5:47:30 PM3/13/13
to clo...@googlegroups.com
On Wed, Mar 13, 2013 at 2:36 PM, Michael Klishin <michael....@gmail.com> wrote:

Thanks.  That's probably what I'll end up doing.  Still, it would be nice to understand whether it's possible to achieve the same effect as Clojure core's settable vars.

Cedric Greevey

unread,
Mar 13, 2013, 5:52:15 PM3/13/13
to clo...@googlegroups.com
Again, those are already given bindings. Think of it as if somewhere there's (binding [*unchecked-math* false] (loop [] (do-repl-stuff!) (recur))).

As for "intended for uses other than working at the REPL", they still tend to be compile/macroexpansion-time uses, and presumably dynamic bindings exist in the threads that compilation and macroexpansion take place on.


--

Marko Topolnik

unread,
Mar 13, 2013, 6:12:45 PM3/13/13
to clo...@googlegroups.com
Yes, I'd say there is no low-level magic about those vars except that they are well-supported in all the relevant contexts. However, the fact that they need such special support does make it hard to use one's own vars in the same way.

Alan Malloy

unread,
Mar 13, 2013, 8:01:42 PM3/13/13
to clo...@googlegroups.com
Not really a special case, although I suppose you could argue it either way. These vars, too, must be bound before being set!. But the code that binds them is in the compiler: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compile.java#L72 binds *unchecked-math*  *warn-on-reflection* before it starts compiling files. The only way you could make your own vars be set!able is to use them inside a context in which they've already been bound; for example, you could define a (let-me-set-stuff &body) macro and evaluate the user's code in that context. That's basically the same as how the compiler and the repl work: they run all of your code in a context where bindings are established. 

Herwig Hochleitner

unread,
Mar 13, 2013, 8:29:32 PM3/13/13
to clo...@googlegroups.com
2013/3/13 Mark Engelberg <mark.en...@gmail.com>
Still, it would be nice to understand whether it's possible to achieve the same effect as Clojure core's settable vars.

It is, because clojure doesn't do anything magic here (apart from the effects its set!-able vars have ;-).
The catch is: The set of commonly set!-able vars is tied to clojure's release version. And as we all know, this context is controlled by clojure/core, in the hope of ruling out bad majority decisions.

Proof by command line:

> java -cp clojure-1.5.0.jar clojure.main -h
... snip ...
  operation:

    - Establishes thread-local bindings for commonly set!-able vars
... snip ...

So presumably, you would have to get the var you want to have "globally" set!-able into clojure.main, or lobby for a general purpose hook to globally add dynamic bindings to a thread (a bad idea in my gut intuition).

user=> (.start (Thread. #(set! *unchecked-math* true)))
nil
Exception in thread "Thread-3" java.lang.IllegalStateException: Can't change/establish root binding of: *unchecked-math* with set
at clojure.lang.Var.set(Var.java:233)

;; so no, clojures set!-able vars aren't magically carried over to new threads either

Opinions

IMO set!-able vars only make sense, if you control the context in which the vars are set!-able. Dynamic bindings are plenty volatile as they are, especially in combination with lazy sequences (just happened to me again today). The ability to introduce *new* bindings *across* or *up* the dynamic scope certainly wouldn't help there.

I think the easiest way to offer your users to control part of their context (to "globally" introduce set!-able vars and other stuff) are: leiningen plugins.

Stephen Gilardi

unread,
Mar 13, 2013, 8:30:38 PM3/13/13
to clo...@googlegroups.com
The repl's thread binding for those vars is set here:


using this macro:


Users of your library would need to do something similar, possibly wrapping a call to clojure.main/repl within a clojure.core/with-bindings form, to allow the same set! ability for your vars.

--Steve

Mark Engelberg

unread,
Mar 13, 2013, 9:17:54 PM3/13/13
to clo...@googlegroups.com
OK, that answers my question.  Thanks for the insights everyone!
Reply all
Reply to author
Forward
0 new messages