This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-24
Channels
- # aleph (1)
- # announcements (22)
- # atom-editor (11)
- # babashka (46)
- # beginners (60)
- # calva (44)
- # cider (18)
- # circleci (1)
- # cljdoc (12)
- # cljs-dev (5)
- # cljsrn (19)
- # clojars (3)
- # clojure (162)
- # clojure-dev (9)
- # clojure-europe (6)
- # clojure-italy (2)
- # clojure-losangeles (2)
- # clojure-nl (5)
- # clojure-spec (7)
- # clojure-uk (23)
- # clojureremote (1)
- # clojurescript (55)
- # community-development (14)
- # core-async (234)
- # cursive (14)
- # data-science (3)
- # datomic (32)
- # fulcro (5)
- # graalvm (20)
- # graphql (2)
- # hugsql (4)
- # jobs (11)
- # jobs-discuss (2)
- # joker (1)
- # juxt (3)
- # kaocha (1)
- # luminus (1)
- # off-topic (33)
- # pathom (3)
- # pedestal (1)
- # reagent (24)
- # remote-jobs (3)
- # shadow-cljs (38)
- # spacemacs (4)
- # specter (4)
- # speculative (54)
- # tools-deps (62)
- # vim (8)
- # vscode (14)
@deleted-user Have you looked at the side-effects
macro in Expectations?
Hello, any tips how to avoid "IllegalAccessException: access to public member failed" when calling a default interface method under java 11 (it worked under java-8? See https://stackoverflow.com/questions/59897831/clojure-fails-to-call-an-interface-default-method-on-java-11-due-to-illegalacces for details. Thank you!
FYI @alexmiller calling the default interface method failed due to the way the proxy is coded so it has nothing to do with Clojure:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy: calling " + method);
// Default methods are public non-abstract instance methods
// declared in an interface.
if (((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
Modifier.PUBLIC) && method.getDeclaringClass().isInterface()) {
// see
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.unreflectSpecial(method, declaringClass)
.bindTo(proxy)
.invokeWithArguments(args);
}
return null;
}
which Clojure version are you using?
we have fixed a couple tickets for this in recent releases
don't know, would be happy to see a repro bug report at either http://ask.clojure.org or jira if you have access
will try
Today I started setting -Dclojure.read.eval=false
in production-like environments, as a security measure (one never knows which piece of code might do a read-string
... present or future)
However this caused a few libraries to fail. That was to be expected (and could be trivially fixed w/ binding
), however sometimes I didn't really see a #=(...)
in those codebases at all.
That left me wondering if there's a subtle way in which libraries use the read-eval feature?
which libraries and why did they fail?
EvalReader not allowed when *read-eval* is false
(is that sufficient info? would rather not share the libraries I use)
not sufficient enough to know what's causing that
#= is undoc'ed and not a public feature of Clojure, so generally no one should be using it
(it is used internally in parts of Clojure, ie print/read roundtrip on some types)
reading java classes with #My.Class... is another thing that can read eval. that's public (for records in particular), but not common
Andy's comments here are still a pretty good overview: http://clojuredocs.org/clojure.core/read#example-542692d5c026201cdc327056
you can also run into the same issue if you happen to use tools.reader
another relevant question: https://ask.clojure.org/index.php/8643/does-clojure-tools-reader-read-string-evaluate-unknown-false
Thanks for the all pointers. I'll make sure to check them out and if something was still not clear I'd post a reproducer in ask.clojure (for posterity :) )
just as data point, i think i have seen #= used on more than one occasion in lein project.clj files - often for obtaining a version string.
people do abuse it, but it is not a public or supported feature
yes, thanks for pointing that out. after your remark above to that effect, i noticed a similar statement at the bottom of: https://clojure.org/guides/weird_characters
Can I generally count on expressions in data structure literals being evaluated in the order they appear in the source code, or should I be using an explicit let
(regardless of style)
I'm shelling out to a binary and one expression produces side effects in the environment that affects the second expression
(let [a (atom 0)] {:x (swap! a inc) :y @a})
;; => {:x 1, :y 1}
is that a happy accident or a language propertyit is not guaranteed even for small maps
It sort of is, because the reader creates array maps and it has been this way for so long that people are almost certainly relying on the behavior so it is unlikely to change
this is not documented (at least I’m not aware) - meaning - you should not rely on it
where?
Maps start out as array maps and become hash maps at 8 elements and this is a well known thing
and? why I should rely on order in map reading? the way how reader actually reads data is hidden from me
This is probably similar to the read-eval :p, you shouldn't assume its not going to break in a future version of Clojure, but it most likely won't because in general core maintainers value not breaking people's code, even when they made unfortunate use of implementation details
Look dude, whatever, as I said if you care about ordering you should make it explicit, but for the most common cases of map literals in code (small maps) the order will be as written and that is unlikely to be ever change
good luck with refactoring)
But, it should be acknowledged though, that it is more likely to change than most other things.
it is not fine because you are making your code vulnerable. It can break if you add more entries to the map for example
Ya, that's true. I guess I'm not trying to impose my own trade off assessment, but simply to provide the necessary information for people to make the choice themselves.
:thumbsup:
For example, this:
(hash-map (doA) (doB) (doC) (doD))
Will guarantee left to right synchronous execution of the do fns.
But will:
{(doA) (doB) (doC) (doD)}
? I actually don't know. I think so. But I'm interested to know for sure as well.
the values are guaranteed to be read in text order, but the eval order is not guaranteed
and you should not rely on it
awesome, thanks @alexmiller 🙂
or at least, that is my opinion
(I wanted to move it into a let for explicitness anyway but I wasn't sure if that was a bug or just style)
Cool, but for function evaluation like hash-map
I'm correct that there evaluation order is a guarantee right?
afaik, this is not documented in reference docs, so I would treat it as undefined
sorry, that comment was in reference to my prior statement, not in answer to you didibus
for hash-map, I would say, yes, that should be expected
and remember if this is lazy value it can be evaluated much later than you expect at all
for the specific case of hash-map, which is a function. macros of course are not constrained to that
@kwladyka That shouldn't be. I mean, yes what is lazy will evaluate later, but function arguments are supposed to be evaluated eagerly as far as I know. Assuming they are functions and not macros.
Clojure has eager eval of args (as opposed to something like Haskell), but eval does not necessarily mean realize
(let [lazy-foo #(lazy-seq (println 1))]
(last [(println 1) (lazy-foo) (println 3)]))
1
3
=> nil
actually this is not true. With lazy seq all fn are not evaluatedit's still creating a lazy seq. When the seq
function is called on that lazy-seq is when its thunk is evaluated (when the print happens)
(let [lazy-foo #(lazy-seq (println 1))
s [(println 1) (lazy-foo) (println 3)]]
(first s)
(last s))
1
3
=> nil
My assumption is that was purpose of this question. Unless I didn’t understand intention.
lazy evaluation and lazy sequence realization both use the word lazy, but mean different things
(defn f
[arg]
arg
:done)
(let [a-lazy-seq #(lazy-seq (println :never))]
(f (a-lazy-seq)))
Wrapping in lazy seq is similar to wrapping in delay somewhat. Now when the argument gets eagerly evaluated, it evaluates the lazy-seq macro. The macro in turn will not evaluate the given println, instead it will return a sequence of thunks which later, when realized, will evaluate the contained println
(defmacro super-lazy-seq [& body]
(println "super lazy seq was evaluated")
`(lazy-seq ~@body))
(first [(println 1) (super-lazy-seq (println 2))])
super lazy seq was evaluated
1
nil
I know, but I understood the intention of the question to evaluate fn from left to right. So under the hood because of side effect or something.
Only for Functions though. lazy-seq
is a macro, so its arguments are evaluated in custom order based on the macro definition
The first
function does evaluate all arguments in order from left to right eagerly before executing. But one of its argument is a macro which returns a lazy sequence, that macro being a macro will not necessarily evaluate its argument from left to right eagerly, which is why in this case println does nothing.
Summary: 1. Function evaluation is guaranteed eager and in order from left to right 2. Macro evaluation is different for every macro, read its documentation to know how a particular macro evaluates (if at all) its arguments. 3. Map/Set literals evaluation is eagerly evaluated, but order is undefined. Assume it could be in any order. 4. Vector/List literals evaluation is eagerly evaluated, and order is guaranteed from left to right.
And list literal is a tricky one, because it quotes. So nothing is actually evaluated
Yup okay. Got it. So ya, list literal are also guaranteed in order evaluation. Cool, that one makes sense, otherwise code would evaluate in undefined order :p
don't know why i did it, but (
seems to work (as compared with
).
is that an intentionally working / supported thing? i don't get the sense that it matches any of what's listed here: https://clojure.org/reference/java_interop#_member_access
which is valid for accessing a field according to the docs, but it seems to be ambiguous with method calls, so the compiler might do some sort of reflection to disambiguate?
because on the jvm you can use reflection to distinguish between the different kinds of things '.' does
would you say (
is "idiomatic" for accessing a field though? I would say no, because this make it look like a call?
it works, but not idiomatic IMHO
I mean, (Math/PI)
works too, but is even more obviously wrong
(uh oh, my program is slow, better take out the parts where I calculate pi!)
so in theory it could be a feature for an alternative Clojure implementation to not resolve (Math/PI)
to Math/PI
and only allow the latter for field access?
oh the other hand, I've had coworkers who insisted on using (PersistentQueue/EMPTY)
instead of PersistentQueue/EMPTY
because using a static field as a data structure feels weird
fwiw, in clojurescript (js/document)
is invalid. so there's already a clojure implementation that distinguishes
and for that reason prob a good idea not to get in the habit of using it. in case you ever want to write cljs. better to keep the muscle memory consistent
cljs.user=> (macroexpand '(Math/PI))
(Math/PI)
user=> (macroexpand '(Math/PI))
(. Math PI)
cljs.user=> Math/PI
3.141592653589793
cljs.user=> (Math/PI)
#js {:isException true, :value "TypeError: Math.PI is not a function\n at <anonymous>:1:33"}
cljs tries to map clj's java interop to js interop, but js is not java so it isn't very clean