Fork me on GitHub

hello folks. i always used components and didn’t like the way components look (oo style) and watched one apropos episode where they discussed how they never used component model, I didn’t understand how can you build a server which needs a database and many more other things without component... how can you restart a server to make changes?


One could quit an entire JVM process and start a new one, yes?


Or implement the kinds of start/stop functions that component encourages, using hand-written functions?


I would encourage you to examine and dig in to why you think component is oo style. It doesn't match alan kay's idea of oo "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.", and it definitely doesn't match C++ or Java's


so you may need to step back, figure out what it is you actually don't like about component without describing it as something it isn't, and then once you have done that you will be in a better place to evaluate and determine what you want


in general, most people that don't like component use mount (several popular templates use mount), but if you don't like oo style, you will really hate mount because it keeps your state in a bunch of global singletons


that’s what i thought. i think component it’s not elegant but the best solution for developer workflow


I was only questioning why some people never use this model


because some people have no sense of taste

😄 8

they must evaluate all the functions on the repl and trust the router/db to do its thing


because every change in the server needs a full jvm restart? i guess


mount lets you hang start/stop actions on your global singletons


we’re talking about mike fikes here


he almost never used component


so I don't know mike or the kind of work he does, but in general I have crossed paths with him on clojurescript stuff


maybe it’s not a library thing


so my guess is he is primarily a front end guy, and primarily the role of composing a system is played by whatever front end framework he is using


well now I know that I’m not crazy when I use component to all my servers


I, on the other hand, never write clojurescript, avoid writing js as much as possible, and use component all the time, and heavily advocate its use

👍 4

they said that a defonce could resolve the problem but it doesn’t lol


I think they were talking about using it on a deployed server maybe


> didn’t like the way components look this is because of defrecord I assume? You can also use metadata-based protocol extension, which allows you to write start / stop as plain defn or fn s

👍 8

yeah I love the workflow just don’t like the defrecords


There is also integrant - I have not used it myself but I have heard plenty of people speaking highly of it


that was like. at the same time lol

😁 4

oh cool @UG00LE5TN imma check it out


I haven't used integrant, but I have worked on a project that monkeyed with component to make it use multimethods instead of a protocol for Lifecycle, and protocols are much nicer to deal with for creating stubs in tests, etc


cool, i can see its value


Ive recently switched from component to integrant and Im loving it. Things compose much better without having to wrap everything with records. It's also easy to mock stuff: all you have to do is assoc the stub in the config map


There’s also clip. Lots of strategies for dep injection.

❤️ 8

Is it a discussed/documented fact that the Clojure compiler is slow? I feel there's been a lot of more talk about the startup time... For example:

(dotimes [_ 1000000] (time (eval (list `defn 'foo [] "<Insert some trivial functionality here>"))))
(inserting actual code instead of that string) informs me that we can only compile 1000-2000 tiny defns per second... Might seem enough, but in a nontrivial codebase, various categories of tooling suffer


There is no 'official' documentation on speed of anything, other than some constant / "effectively constant" / linear time things in doc strings. None of that for compilation speed itself. There has probably been some discussion about it occasionally spread over 10 years, but I have no links to share, if there were such discussions.


I wouldn't be surprised if there were 2x performance gains that could be had there, if you tried hard enough. Whether such changes would ever become part of the Clojure itself is much much more 'iffy'. If the core team really wants those changes, and they are trivial to review as not changing the behavior of the compiler, and they speed things up measurably on common use cases, and do not slow down anything else, then maybe, but no one will promise you that such changes will ever be looked at in your lifetime.


You can create your own personal GitHub fork of the Clojure code base with all of the experiments you want to try, and let others try, if that interests you.


> There is no 'official' documentation on speed of anything [...] Thanks! It's something I've tried to google a couple times with no luck. The ideal material I would love to find is an explanation/analysis of why a single eval takes that much. > You can create your own personal GitHub fork of the Clojure code base with all of the experiments you want to try, and let others try, if that interests you. Yes, this could be a cool side project :)


Someone like bronsa has looked at this a lot, and may be willing to share what he knows on the topic. Not many people dive into the compiler a lot. Except for one's own curiosity/learning/knowledge, there isn't much benefit to doing so. I agree that those things can be big benefits.

👍 4

One thing to note is that Clojure's compiler is mostly "fairly straightforward" translation of Clojure data structures into JVM byte code. i.e. unlike an optimizing compiler for C++, there is no extensive data flow analysis/etc. that runs quadratic time algorithms on the data structures representing the code, so a lot of it is pretty close to linear time in the size of the code.


Because JVM JIT is there to do the heavy optimization.


You may want to do some quick benchmarks on 3 or 4 significantly different sized Clojure defn forms to check what actual measurements show.


There are some fixed overheads to calling eval, my guess is you will get very different behavior if you batch up code into dos vs calling eval repeatedly. The typical code loading case (outside the repl) is going to behave much more like a batch job

👍 4

> so a lot of it is pretty close to linear time in the size of the code. yes, this is what I've observed. I thought it was a matter of bigger defns -> more "sauce" in them. Not merely size directly related to data structures... that's interesting


There are exceptions to that "mostly close to linear time", e.g. one or both of for and/or doseq generates code size that is exponential in the depth of the nesting, but most people don't write code that nests those deeply.


> There are some fixed overheads to calling eval Fair one, I might play with a more representative benchmark At the same time, (c.t.n.repl/clear), (c.t.n.repl/refresh) should be the most practical benchmark, and it's certainly slow-ish in every project (proportional to codebase size)


I haven't looked into case in detail, but the Clojure compiler does some compile-time hashing to create a branch table there that I do not know whether it is nearly linear time, or slower.


When I said "data structures" above, I was referring to the data structures read by the reader, of the code. Not data structures being manipulated by the program at run time.

👍 4

Refresh is going to be more of the code loading you mentioned, not entirely equivalent to calling eval repeatedly


Yeah, refresh also does read, too, not only eval.


Alex has written about and investigated that

👀 4

There are also at least some Clojure devs, most vocally Sean Corfield, who avoid 'reloaded' workflow completely, preferring instead to remember to evaluate any changed functions while developing


I believe primarily not because of speed (although that might be part of it), but because of not wanting to deal with the problems that sometimes arise with reloaded workflow tools (but believe his word over mine for his reasons).


Anyway my point wasn't about eval or refresh, but about the perceived fact that clojure compiling / code loading is slow. This seems to have multiple implications (e.g. refactor-nrepl, Eastwood, which perform code analysis based on eval, and also refresh) One sometimes hears from other toolchains that they can compile xxxK LOC per second. My medium-sized codebases cannot say anything like that :)


Eastwood is using tools.reader and tools.analyzer and tools.analyzer.jvm, so speeding up Clojure's compiler and reader would have 0 effect on Eastwood's speed (well, except maybe indirectly)


fwiw, I know that It'd help to understand that I'm not asking "I have problem practical x and want a solution", but "I see the x pattern of problems in various tools, is this something well-known?"


And the first replies seemed to shed light on the topic :)


I don't think anyone advertises xxxK LOC compilation speed for Clojure. Much higher on the list would be "often significantly smaller and less complex code bases, for faster human reasoning and development speed"


where "less complex" is enabled by some of Clojure's features, but Clojure developers are free to introduce as much complexity using those features as they are willing, so there is no guarantee of achieving those benefits, of course.


> I don't think anyone advertises xxxK LOC compilation speed for Clojure. Much higher on the list would be "often significantly smaller and less complex code bases, for faster human reasoning and development speed" I agree, and also am interested in bridging the former and the latter (within reason, and with a large risk of failing) i.e. it'd kind of surprise me that if the JVM is fast, and Clojure can be fast, then code loading couldn't possibly be fast


It is virtually guaranteed that it is possible to make it faster, as nearly any code can be made faster if you work at it enough. "Programming is an economic activity", and it probably isn't on the list of the top 20 problems the Clojure core team is interested in tackling for the official Clojure compiler code. Thus it is relegated to experimentation, which for most people reduces their interest in spending much time on it.

👍 4
Alex Miller (Clojure team)02:02:28

We do periodically check that we didn’t do something stupid at least

Alex Miller (Clojure team)02:02:26

There were some issues particularly in macro compilation that we fixed back in 1.7 or 1.8 or so

Alex Miller (Clojure team)02:02:42

The Clojure compiler is intentionally very simple - in the broad sense it takes a Clojure expression and turns it into bytecode

👀 8
Alex Miller (Clojure team)02:02:19

But if you find something interesting please run it down


Since I was invoked in this thread... speeding up c.t.n.repl would have zero impact for any workflow that I think is useful.


Could the Clojure compiler be sped up? Probably. Would it help lots of people's workflows? Maybe. Would it help any production workflows? Yeah, folks who aren't doing AOT.

👍 4

So, yeah, work on speeding up the Clojure compiler is valuable as long as it doesn't change any of the semantics.


Hi All! How does one go about specifying something like Maven’s “provided” dependencies in deps.edn?


For example, what would be the idiomatic way to represent the following in deps.edn?



I think you meant idiomatic, 🙂

😸 4

thanks @UJRDALZA5 . typing on the phone is hard. 😂


@abdusalam The simple answer is "you don't". Scope makes no sense in the deps.edn world. Either your project needs a lib or it doesn't.


Any consumer of your library can easily override your version choices by specifying their own.


i see. thanks, Sean.


that moment when you realize you've picked leap day to test date comparators 😎

(let [t1 #inst"2020-02-29T21:29:33.479-00:00"
      t2 #inst"2021-02-29T21:29:33.479-00:00"]
  (compare t1 t2))
Syntax error reading source at (REPL:2:46).
failed: (<= 1 days (days-in-month months (leap-year? years))) 

😆 4
📆 8