This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-27
Channels
- # admin-announcements (5)
- # cider (4)
- # cljs-dev (20)
- # cljsjs (2)
- # cljsrn (6)
- # clojure (126)
- # clojure-austin (2)
- # clojure-berlin (1)
- # clojure-brasil (5)
- # clojure-japan (1)
- # clojure-russia (14)
- # clojure-spec (2)
- # clojure-uk (3)
- # clojurescript (11)
- # cursive (19)
- # datomic (5)
- # editors (1)
- # emacs (10)
- # funcool (5)
- # hoplon (170)
- # instaparse (4)
- # jobs (1)
- # om (1)
- # onyx (1)
- # re-frame (14)
- # reagent (1)
- # testing (14)
- # yada (1)
I'm getting a bizarre error in 1.8 "UnsupportedOperationException nth not supported on this type:" but no type is actually printed, and the source lines in the stack trace don't make a whole lot of sense with respect to this error. Anyone seen this?
I found the problem. A call to nth on a Java set. I understand why nth doesn't work on this, but what I don't understand is why the Clojure error failed to show the type, and why the stack trace pointed at the wrong line of code.
nth spec would catch this before
puzzaler: if you look carefully, you'll see two exceptions being thrown in the repl, one is the nth one, the other is
CompilerException java.lang.RuntimeException: Unable to resolve symbol: in this context, compiling:(NO_SOURCE_PATH:0:0)
the reason you see a blank space in both exceptions where something should be is because the compiler calls getSimpleName on the class name, and for the anonymous inner class the simple name is ""
the second exception, which in my testing is the exception that actually bubbles out (the nth one has the error message printed and that is it), is the really weird one, because it is coming out of the compiler, not the runtime
what I am seeing is(with the clojure.main repl), for that exception, for some reason, the next time the repl passes through its loop "repl-read" is returning a symbol with the name "", which of course explains the unable to resolve symbol error message from the compiler
Hah, the second exception is just me chasing my own tail, because I copied and pasted the (nth (.keySet {1 2}) 0)
from slack and it included trailing weird unicode non-breaking space characters
Okay, I'm producing hiccup-style structures from inataparse. I need help figuring out how to re-parse specific items within the structure.
Solo strings (unmatched with a tag) are one of the types I need to re- parse in place
meta-question: how do you judge the quality of Clojure books without buying them? B/c I've bought https://www.amazon.com/Professional-Clojure-Jeremy-Anderson/dp/1119267277/ , was very dissatisfied with the purchase and somehow there are three 5-star reviews now (there were none when I bought it)
"dissatisfied" as in "wtf, how this can have "professional" in the title". like when they recommended to "slurp" a bytestream in Ring middleware without ever mentioning memory consumption concerns. or when they claimed that vector lookup is O(1)
haha @si14, vector lookup being O(1), you're going to have fun debating that one with the channel
Ok, I’ll be that guy… vector retrieval isn’t O(1)? Unless the book was ambiguous between lookup and search, since search is obviously O(n)
@reitzensteinm vector is a tree, so it's O(log(n)). we can argue that the tree is shallow, but that log may show up anyway (e.g. as an abrupt change in access times when first "layer" is filled up)
I mean it's unprofessional to claim O(1) index lookup without mentioning the underlying assumptions for the claim (like log32 being "effectively" constant)
no arguments from me @si14. it's something that comes up often, and I don't personally think it's helpful to claim O(1)
> Clojure is data oriented. Choosing the right datastructure is the prerequisite for writing fast code. Clojure encourages usage of O(1) and O(log n) data structures by providing the map, the set, and the vector literal notation.
what is O(1) in that list though?
> Vectors have O(1) lookup by index. Sets and hashmaps have O(logn) lookup by key. Sequences by contrast are O(n). Choosing the right data structure usually boils down to not doing combinatorial sequential lookups O(n∧2) or higher. Exponential complexity is the primary performance assassin for algorithms.
i'm ok with that statement. It could have included information about 32-way tries but for an intro book its ok
but why not just say logn for everything?
the performance implications are subtle, and not really captured by the big O notation. so 8 branches deep (assuming balance), you're in the objects-that-take-terabytes-of-ram. so effectively, your cap is going to be 6-7
@credulous O(1) claim makes an impression that Clojure's persistence is a free lunch. It isn't, both in data locality and memory, so I would expect that the book that has the word "professional" in its title would mention this
if an algorithm were to slow itself down so it always took 8 branches, it would be considered O(1)
but it would be nice to discuss the unfriendlyness to cache of making those jumps around memory
like, if you're going to pull out the big O notation, you're going deep enough that you might as well just explain the lot
I don't have a problem with effectively constant though
just my 2 cents
@reitzensteinm yeah, right! I wish there is a Clojure book that really dives in, like from the basics (HAMT and stuff) to how you compose large systems in Clojure (do you even DDD?)
i'm trying to make my way through the functional data structures book for my talk, it's a pretty harsh introduction though
the one on the clojure bookshelf
tangential: is there a guide or book anywhere on how to build "enterprise-y" Clojure software? It feels like everything we have in a public discourse is a mix of "maps flowing through the system", "Datomic is awesome" and "data is king". While I completely agree with all of it, it doesn't help much to structure the code around complex "business logic". Java world has buzzwords like CQRS and DDD and a ton of people writing about the stuff; it feels like Clojure has almost none
@si14 I would recommend 2 books to do that. The first is “Programming Clojure” by Stuart Halloway and Aaron Bedra. That takes you from the basics, but covers much more of them and much better than most other books. Then I recommend “Clojure Applied” by Ben Vandgrift and Alex Miller (Hi Alex!), to get you up to composing large systems
how would you execute a transaction that involves a few external services and a database? would you reuse Java's pattern of lifting a graph of objects from SQL DB and relying on some ORM to save it back, or should it be ad-hock selecting and updating? questions like this are hard to get right, or maybe I'm just too ignorant :(
@reitzensteinm may I ask where that talk is going to be presented? :)
You’ll also find that many of these design frameworks are applied to Java to simplify complex flows and so on. While Clojure is not a silver bullet, many of the things that those patterns are trying to help with in Java are much more tractable in Clojure. This either makes those things unnecessary, or much simplified. Try looking at Bobby Calderwood’s Clojure/conj talk from last year where he looks at CQRS with Clojure: https://www.youtube.com/watch?v=qDNPQo9UmJA
@si14 euroclojure!
I am working on an experimental clojure->C compiler, that uses clojure.spec generators to specialize code
so you don't have to check is-it-a-float a trillion times at runtime
@quoll I see what you mean, thank you. I believe there is an inherent complexity in some things, like distributed transactions (someone clicks a button, perform a charge, record its result to DB, send an email, every step can fail at any point), so it's not Java quirkiness at fault but an underlying world's messiness. Java people came up with some solutions, sometimes I think it can be helpful to look at how they do stuff, but it's hard to disentangle Java from the underlying ideas
@reitzensteinm sounds extremely interesting! Hope I will be able to attend :)
@si14 there's a thingie I uploaded here
you can drag the slider to see the compiler optimizations being applied
and the eventual C output turning from a naive implementation of clojure's features that work at runtime, to eliding it all after specializing it
@si14 I haven't found a lot of books that are that great or up to date. But DDD and CQRS are not Java specific, so they should apply to Clojure as is. Obviously, you won't be able to benefit from the OO pattern they describe to help you implement them. The basic idea behind DDD is that you should model things as they are in your organization. The same boundary should exist. Clojure records work well for the model part, combined with protocols to implement the service layer. You can use namespaces as bounded contexts. An ATOM as your repository. And events can just be functions. There's many other way I guess you could model it. I'd recommend looking at ClojureScript actually, there's more examples of enterprise software in it, with details of the frontend and the backend.
I'm trying to figure out if I can make a macro called (catch-any) that would take a vector of exceptions and return multiple (catch) blocks from it. And if it would be possible to use it within the try special-form
didibus: if you want special catches you need to write a try macro, not a catch macro
@gfredericks I was thinking that's the case, but I'd like to understand why that is?
because (catch ...) isn't really its own special form, it is part of the syntax of the try special form's dsl
So its something with the transformation order. If the (catch-any) macro would expand first, wouldn't it be able to return a list with the first element being (catch) which would then be processed by (try) as if I had written that?
no because try isn't looking for a list with the first element that is a catch clause
a macro expands to a single form, it cannot expand to multiple forms and some how splice them in to the surrounding form
Hum, that part I don't understand. Shouldn't the macro just pre-process the AST into one form to another?
"to another" not "to several"
(catch ...) is a form, and is specifically the kind of form the try special form is looking for as catch clauses
((catch ...) ...)) is another form, and is not the kind that the try special form is looking for
the "expand to one form" vs "expand to many" isn't even the main limitation though; somehow try is processing the forms below it before any macroexpansion gets done
Ok, I see, so a macro can't produce a list of forms, which means it wouldn't be able to return (catch...) (catch...) etc.
e.g., you can't even do this: (defmacro rescue [& args] (cons 'catch args))
Thanks, I hadn't think of the output one form vs many issue, but I'd like to understand about the processing order
a list of forms like X, is different from a bunch of forms like X embedded in a surrounding form
(try ... (catch ...) (catch ....)) is two catches in the surrounding list that starts with the symbol try
Why does try happens before macroexpanssion, say I just wanted to have a macro that expands to a single catch form
@didibus: that's how it was written; not sure if there's a good reason
(try ... ((catch ...) (catch ...))) is a list of catch forms in the list that starts with try
Do every special-form have their own execution order rules like that? Or do all special-form follow a pattern?
@didibus: most of them don't have this nested syntax aspect, so the question doesn't really apply
I suppose there are parallel things like "You can't write a macro that expands to an arglist and use it inside of defn"
its like if you had a macro that you wanted to expand in to a binding pair inside the bindings given to let
@didibus: the outer macro runs first, so gets the ultimate say in everything
although you a macro can't expand its body, which is pretty annoying
s/you//
every macro is basically its own dsl and can do whatever, and unless a lot of care and consideration is given, that whatever is unlikely to be arbitrarily pluggable
I suppose "a macro can't expand its args" means you couldn't even reasonably write your own defn
that supported macros expanding to arglists
do any other lisps have that capability?
I could imagine another implicit argument to macros that is a macro expand function that the compiler passes in
Clojure is my first Lisp, but I remember reading that some Lisp can in fact compose macros
I wonder how easy that would be to add to the clojure compiler
I keep running into uses for it
oh because it'd be a 3rd positional arg?
let's pass it in as metadata on the &form
(-> &form meta :clojure.core/macroexpand)
:clojure.core/d5a7abcf-8dde-4f3c-8375-a9f40fc2b891
I'm guessing its a compromise between allowing people to do too many unpredictable things
I wrote a lisp -> go compiler using something like macroexpansion, but the expansion happened outside in, then inside out, and could pass information up and down the expansion
I've never heard of any downsides to something like this
@hiredman I bet "Unable to resolve symbol" error messages would be more complex
the compiler would have to expand down and back up and only then start looking for problems
what does that mean?