This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-03
Channels
- # bangalore-clj (1)
- # beginners (16)
- # boot (23)
- # chestnut (5)
- # cljs-dev (3)
- # cljsjs (3)
- # clojure (115)
- # clojure-conj (3)
- # clojure-italy (17)
- # clojure-russia (22)
- # clojurescript (20)
- # core-async (11)
- # events (3)
- # fulcro (91)
- # funcool (5)
- # heroku (7)
- # hoplon (5)
- # leiningen (3)
- # off-topic (2)
- # om (1)
- # onyx (9)
- # parinfer (1)
- # protorepl (2)
- # re-frame (3)
- # slack-help (2)
- # spacemacs (5)
- # unrepl (1)
Does gen-class
allow creating javadocs for methods? Does it just convert the clojure docstring, or something else?
javadoc is not something that's compiled to bytecode, it's just parsed from Java source
Quick question: transducers are functions from a reducer to another reducer. Are thy completely agnostic of the type of the first argument (accumulator) of the reducing function?
Ah, found my answer: http://conscientiousprogrammer.com/blog/2014/08/07/understanding-cloure-transducers-through-types/
I honestly don't really understand what transducers are. Is there a somewhat simple introduction article to them?
@donyorm : https://www.youtube.com/watch?v=WkHdqg_DBBs&list=PLhi8pL3xn1OTfhjnIHmokYjKzLSBtYu8- is pretty good
@donyorm Rich Hickeys original introduction: https://www.youtube.com/watch?v=6mTbuzafcII
Are there any well established patterns for making some feature provided by an embedded DSL available in the host language/runtime.
@cddr the best bet is to have a pyramid, with information at the bottom, a smaller API above that, and a smaller DSL on top https://www.youtube.com/watch?v=LEZv-kQUSi4&feature=youtu.be&t=8m0s "nothing says 'screw you' like a DSL"
(youtube link jumps directly to the slide)
That is, if you have any capacity to do any of that. If all the host provides is a DSL with no API or information model, then I guess you're stuck with treating the DSL as a target language of a compiler (eg. what people do with SQL and JS).
Are there any transducers (or should transducers) that operate on the “accumulated” value?
Or are they always supposed to pass on the accumulated value to the next reducing function untouched (or return it), and leave it to the last reducing function in the chain to touch it?
I started reading about transducers yesterday and from what I gather it seems they should be completely agnostic of what the accumulated value is, and thus unable to operate on it in any way, leaving it to the last reducing function in the chain to perform an operation on the accumulated value (e.g. conj, etc)
the transducer itself can be stateful, but there's no concept of a shared accumulator between transducing functions
whether you attach the transducing function to an accumulator (eg. via transduce) is not visible to the transducing function at all
but, certain stateful transducers (eg. partition-all or cat) can change the shape of the input data they receive, in a way that can look like accumulation in some sense
What's a common/idiomatic way to handle errors you expect (e.g. user signing-up with a taken name) and ones that you don't (e.g. couldn't connect to the database). It seem somewhat wrong to throw an exception for errors you expect since they aren't really exceptions? :thinking_face:
Throw (ex-info), and have a convention on the exception map to differentiate expected exceptions, from unexpected ones.
Then, where you can handle such exception, using ex-data you switch on type and handle each accordingly.
If you're not 100% Clojure, that's if you're doing a mixed java project, you could also create different exception type and switch on that instead, (throw (ValidationException. "X should not be empty. "))
well, Exception and Error are two different types, (both can be thrown) - catch Exception and recovering is normal, catching Error should be limited to instances where you need an extra step before bailing - it isn't meant to be something recoverable
really, you should be catching the specific failure types you know how to recover from, and either ignore or rethrow the ones you can't (I really wish this advice had been followed from the start in the code base I work on...)
Hmm ok, but since the Clojure try/catch
dispatches on type, I should derrive the Java RuntimeException just like a java program?
there are other options like conditionals and returning a response that indicates an error occurred - but the vm itself ensures you need to handle Exceptions in some way, there's no way to avoid it entirely
how does the clojure try/catch differ from java there? isn't it dispatched by type in java too?
it is, but I was wondering if it's idiomatic to create sub-types in Clojure since I've rarely had to do this
oh, in clojure I'd just use ex-info and rethrow if you don't match the specific case you were looking for
ex-info to create the exception with attached data, ex-data to get the data out when you catch it
yeah, that looks like more of what Halloway was calling an information model and API there - you're not being forced to construct text for an existing interpreter like with SQL
Is there something that describes what can be "eval'd"? I was surprised that this does indeed return "Foobar" (i.e. function objects seem to be self-evaluating).
(let [foo (fn [k]
(clojure.string/capitalize k))]
(let [foo2 (first (eval `[~foo]))]
(foo2 "foobar")))
functions don't have equality by behavior
oh, wait
let bindings are not visible to eval
(without pulling some weird tricks that is)
also, FYI, let bindings are visible to later bindings, you don't need a second let block there
@noisesmith I just tried the following:
(def foo (fn [k] (clojure.string/capitalize k)))
(= foo (eval `~foo)) ; => true
(= foo (first (eval `[~foo]))) ; => false
why is that?oh right, thanks to `~ you aren't using the binding inside the eval
@hmaurer yes, symbols of defs are resolved in eval, but this is a different thing
@noisesmith yeah but why are they equal in the first expression, and not the second? shouldn’t
(first (eval `[~foo]))
resolve to the same value as (eval `~foo)
?if I
(def bar (first (eval `[~foo])))
, bar appears to have the same behavior as foo but (= foo bar) ; => false
oh wow with a function, if you eval it, you get a new instance of the same class the function defines
+user=> (first (eval `[~foo]))
#object[user$foo 0x5ef6ae06 "user$foo@5ef6ae06"]
+user=> (type *1)
user$foo
+user=> foo
#object[user$foo 0x6b8d96d9 "user$foo@6b8d96d9"]
+user=> (type *1)
user$foo
the class defines the behavior when called
however
(def bar (eval `~foo))
does return the exact same function ((= foo bar) ; => true
but eval makes a distinct instance of the same function
boot.user=> foo
#object[boot.user$foo 0x70a377b0 "boot.user$foo@70a377b0"]
boot.user=> (eval `[~foo])
[#object[boot.user$foo 0x6d0cec74 "boot.user$foo@6d0cec74"]]
boot.user=> (eval `~foo)
#object[boot.user$foo 0x70a377b0 "boot.user$foo@70a377b0"]
see, it's still user$foo as a class, but different object identities
yeah - seems so, I'm not sure why though
really, if your code depends on one or the other you are probably doing something wrong though...
Yeah I don't care about object identity. Surprised functions work at all really. But then wondering why reified instances can't be eval'd
maybe there is an optimization when you have quote and unquote directly following eachothers @noisesmith ?
(let [prog {:foo (fn [k]
(clojure.string/capitalize k))
:bar (reify Object
(toString [this]
"bar"))}]
(eval prog))
=> Boom!
you still don't need the extra let block
+user=> (let [a 0 b (inc a) c (inc b) d (inc c)] d)
3
Right but my question is, what types of things can go into prog
, and come out the other side the same and behave the same. The docs list "Strings, numbers, characters, true, false, nil and keywords" as being self-evaluating. It seems like functions are also self-evaluating. But as the example above demonstrates, not arbitrary reified instances of Object.
right, I made this a thread because it wasn't addressing your primary point
you can only eval things that self eval, which means they have a prn representation that is readable
functions and vars are not instances of this
everything that can be fed to the reader is an Object, some of them have a readable printed form
> functions and vars are not instances of this I thought those examples demonstrated that functions were evalable.
How can I access this enum from Clojure code to call a static method on clojure.lang.Compiler
? https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L339
ugh, OK - you're right
+user=> clojure.lang.Compiler$C/STATEMENT
#object[clojure.lang.Compiler$C 0x373ebf74 "STATEMENT"]
it's how the jvm represents an inner class
right, and you'll only see it when it's an inner class
the name of the inner calss is Compiler$C
the outer class name just happens to be part of the inner class name
but it's not a structural relationship, it's a naming convention
I haven’t done much java before but I assume inner classes are then a sort of weak namespacing?
it's a class defined inside another class, which is how an enum is implemented
so there are scoping rules that enforce isolation to some degree unless you declare things public etc.
but that's not because of a structural relationship between classes, it's a separate flag thing
@noisesmith thanks for the details. I stumbled upon this: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7002
whereas when running (eval foo)
, it will lead to eval’ing a ConstantExpr, which directly returns foo
I haven’t managed to track it back all the way but I guess it might call this https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L4960
boot.user=> (.invoke (.eval (clojure.lang.Compiler/analyze clojure.lang.Compiler$C/EXPRESSION '(fn [] [foo]))))
[#object[boot.user$foo 0x70a377b0 "boot.user$foo@70a377b0"]]
but you are calling eval on a list that happens to have the symbol fn at the start
take out the ' to really eval a function
@noisesmith yep my bad, the actual call is
(.invoke (.eval (clojure.lang.Compiler/analyze clojure.lang.Compiler$C/EXPRESSION `(fn [] [~foo]))))
that does the same thing except it also namespace qualifies fn to clojure.core/fn
@noisesmith it has the same behaviour as
(eval `[~foo])
but it's not the same input - where does the extra fn come in?
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7002
oh, weird, OK
I’m just trying to understand why
(eval `~foo)
returns the same function object, whereas (eval `[~foo])
returns a new instance+user=> (->> (fn [] [foo])
(clojure.lang.Compiler/analyze clojure.lang.Compiler$C/EXPRESSION)
(.eval)
(.invoke))
[#object[user$foo 0x6b8d96d9 "user$foo@6b8d96d9"]]
+user=> (->> '(fn [] [foo])
(clojure.lang.Compiler/analyze clojure.lang.Compiler$C/EXPRESSION)
(.eval)
(.invoke))
[#object[user$foo 0x6b8d96d9 "user$foo@6b8d96d9"]]
+user=> foo
#object[user$foo 0x6b8d96d9 "user$foo@6b8d96d9"]
@noisesmith if you pass (fn [] [foo])
it’s different I think. It will take this code-path: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7009
boot.user=> (clojure.lang.Compiler/analyze clojure.lang.Compiler$C/EVAL (fn [] [foo]))
#object[clojure.lang.Compiler$ConstantExpr 0x65f7b4ef "clojure.lang.Compiler$ConstantExpr@65f7b4ef"]
I’m not sure about single-quoting, but syntax-quoting with unquote (~) leads to a different result
it's still resolved from the current namespace - ` is for the case where expansion will happen in a different namespace which won't have your bindings
it fully qualifies in order to ensure you get the expected value