This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
Is it possible to have a symbol (i.e. a def
) that always gets re-evaluated when evaluated? Basically I want a def
that acts like a function but I don't need to invoke it
I don’t think that is possible using a def
. What are you trying to do here?
(for example, are you trying to mirror the implicit “getter” sort of functionality that some languages have where you treat a variable like a property but it’s actually evaluating a function behind the scenes?)
I think he wants something like this:
(def time (new java.util.Date))
Where each time you refer to time
it will be re-evaluated.Yeah, several other languages have this sort of syntactic sugar that allows you to “fake treat” a function or method as though it were a symbol or variable or property. It’s something I missed a little when I started using Clojure but only for a short while.
maybe can be done with a macro, but this is breaking the tiny amount of syntax that lisp has
yeah, I think the desire for it goes away pretty quick
I imagine this feature would break other macros like threading, basically calling these type of functions 2 times
I think the closest you can get to that without things getting squirrelly is (def time (fn [] (new java.util.Date)))
then just referring to time
as (time)
from there on out.
Yes it's more of a nicety - the example here is I have a def which is referring to the contents of a file I've read. During development it would be nice if whenever that def
is used the file was read from disk every time but then during a real run of the application this doesn't happen
And what's nice is the code using the def
doesn't need to care about this detail
The solution you gave specifically is what I didn't want by changing time
-> (time)
but oh well that's what I'm doing now 😄
why does the syntax matter, why can't you use fn call syntax and dispatch in the function for your desired behavior
Because then the calling code has to understand this is something to invoke rather than use
It's very very minor, just was wondering if it's possible
I wanted to make invocation an implementation detail
you are creating an ambiguous syntax, and it sounds like you want to make a new language
are you concerned with re-evaluating the def constantly once in production?
It's like what Matthew said, other languages have this feature and it's something you can get a lot of mileage out of
Yes in production this shouldn't be evaluated again and again, it really should be a symbol
You could do this to avoid that, but I’m not sure it’s any more palatable:
(def dev true)
(def _time (new java.util.Date))
(def time (fn [] (if dev (new java.util.Date) _time)))
That way it’s eval’d once in prod and every time in dev.
Yes was thinking the same thing - still a function call but oh well
Thanks for the answers!
sure. I hear you, I missed this too.
I think it just doesn’t really fit with a functional style and that’s probably why it’s not a part of clojure.
I don't see this as functional vs something else. it really looks like a fundamental syntax issue
my programs have this behavior, it's easy to do this type of dispatch, but I don't make up new syntax for it
You typically see it in oo languages as a “magic” getter on an object property.
Here is the JS example: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
(but it doesn’t have the syntatic sugar around it, which is fine)
In the js example I linked, without this you’d need to do console.log(obj.latest());
- note the ()
after latest.
Which is probably why it’s not a part of clojure.
embrace the invoke. it's a type of documentation. however at startup you do have the ability to do some hacky things (config like things) but I think if you are doing invoke stuff, then the hacky things to not do the invoke will bite you in the bum later
(please remember, I’m not the one who was asking)
I’m just explaining why someone might want this, because I went through this too.
yeah, I understand. I am not talking specifically to you when I write. otherwise I would have just ended with it's ambiguous syntax
@U05N8AJMWQG Would you be satisfied with a solution where you use @data
instead of data
? If so, you could do something like this:
user=> (def now (reify clojure.lang.IDeref (deref [this] (java.util.Date.))))
#'user/now
user=> @now
#inst "2023-10-14T18:14:57.928-00:00"
user=> @now
#inst "2023-10-14T18:15:01.017-00:00"
user=> @now
#inst "2023-10-14T18:15:04.936-00:00"
user=>
Oh wow interesting... definitely a bit magical but would satisfy this. I'll play around with that, thanks!
What exactly do you mean by "everytime it's read in development"? Like in a bunch of calls, you see different file contents? Or more like you adjust some stuff and want to re-run the code against the latest file state?
If it's the latter, does some sort of reloaded workflow help here, where you reload the namespace rather than evaluating each individual form (I learned about this recently). In that case, every reload would rebind the def
to the latest value. And you don't have to worry about prod since you're not reloading namespaces in prod.
So you'd change your file, reload the ns, try out your functions against the current file. Rinse and repeat.
I was thinking of the deref thing @U04V70XH6 showed above, I just had no idea how to do it (still learning). Really neat how easy it is to create a custom deref-able. I guess the downside is having this weird deref in prod too. Seems like something that might be confusing later or to someone else.
Yes that's exactly what I mean - what I was wanting is the minimum amount of steps between changing the file and rerunning the code - which hopefully is 0 steps. If there is a step it may be possible to forget that step and then see incorrect behavior and potentially start debugging why the behavior is incorrect because I forgot I need to reload the file. That's happened to me many times on other projects
Do you have any habits already, like saving the file regularly? You can probably bind reloading to saving, and then you won't forget. I know what you mean though: I've been confused a few times for the same reason. I'm building the habit of reloading though. It becomes muscle memory pretty quickly.
I don't believe in infallible habits 😄 But I understand what you mean
Is there a nice idiom for getting the nth element of a collection during a set of sequence operations? Say I want to iterate a function 50 times and then perform a reduction on the result. Something like:
(->> input
(parse)
(iterate f)
(nth 50)
(reduce g))
This doesn't work since the arg order for nth
is "backwards". I could do a drop
followed by first
, but that seems a bit clunky.Preferences and contexts vary. In a case like this I might put the nth and reduce outside the thread, to make clear what are sequence ops and what are non-sequence ops. (I find this especially nice for "do this to the result" situations.) If you really prefer to stick to threading instead of nesting there's https://clojuredocs.org/clojure.core/as-%3E> or multiple techniques under "Don't" in https://stuartsierra.com/2018/07/06/threading-with-style.
Right, but then I need to name the aggregate of states which is kind of meaningless since I only care about the final state. A clearer question maybe: is there any idiom for "I want to iterate a function n times and only care about the nth result"?
I don't know that there's a common idiom for that specific thing, but one possibility for this specific use case is
(let [flip-nth #(nth %2 %1)]
(->> "abcdef"
seq
(flip-nth 3)))
and of course, if this comes up a lot in a particular place, flip-nth could be elevated up to a top-level form for re-use, or a function could be made that comp
s nth and iterate to provide a local idiom for that specific thing(#(nth % 50))
My mistake, I thought you were focused on the threading aspect. I think I understand what you're asking now.
For "I want to iterate a function n times and only care about the nth result" I consider "`drop` followed by first
" a very good solution. I don't find it clunky at all — it seems like a clear representation of your intent.
the assumption is that iteration produces a list that has at least as many els as the iteration amount. I feel like there are too many assumptions here for something like an idiom to form. also iterate isn't too popular of a function
I’d write a helper function that does exactly what you want and then invoke it. It could use a loop construct or some other profiled form to do what you want. The details aren’t important and forcing it into a threading form is pushing you towards versions that you find clunky and wasteful
Right, that's what I ended up doing. I find it easy to forget to do that when I'm playing around with the repl; it's really easy to just keep growing a giant thread macro until the whole problem is solved.
In my case, the iteration was because I was simulating something, so I lifted the iterate and nth out to a simulate
function (easy to switch to drop first
or loop
if needed, as was suggested):
(->> input
(parse)
(simulate f 50)
(reduce g))
Thanks all!