#clojure log - Jan 22 2016

The Joy of Clojure
Main Clojure site
Google Group
IRC
List of all logged dates

0:14 rhg135: I'm an idiot; I had slf4j misconfigured and hence did not log the exception in my transducer...

0:36 baritonehands: justin_smith: Continuation from yesterday, https://github.com/baritonehands/avalon/blob/master/src/clj/avalon/models/crud.clj

0:36 https://github.com/baritonehands/avalon/blob/master/src/clj/avalon/models/memdb.clj

0:36 Still not sure what to do with sate

0:36 state

2:13 WickedShell: post upgrade to clj 1.8.0 I periodically get error messages that disappear after doing a lein clean; lein repl again. (lein version 2.5.3) It appears that lein isn't reliably rebuilding files based on dependencies. Is this expected or related to turning on direct linking?

4:43 marianoguerra: hi! I'm building an uberjar with lein uberjar but I want to have the ability to add some jars from the classpath at run time (jdbc drivers) by printing the classpath I can't get it to add another classpath than the current jar, any hint on how to do it?

5:01 Glenjamin: marianoguerra: that's a limitation of `java -jar`, you have to add the uberjar to the classpath and specify the main class

5:05 marianoguerra: Glenjamin: you mean I have to run the non standalone jar, add the standalone jar in the classpath and specify the main class?

5:06 Glenjamin: yep: java -cp somejar.jar:uberjar.jar your.main.Class

5:07 marianoguerra: Glenjamin: it worked, thanks!

5:07 Glenjamin: i ran into that exact issue last week :)

5:08 marianoguerra: Glenjamin: I was googling for the last half hour, many false positives with terms like lein uberjar and classpath :/

11:38 tangled_z: hi! I was wondering if anyone tried to combine using typed clojure with re-frame?

11:41 because re-frame puts all of its content into a single app-db elemement, and I have no idea how that would be typed.

11:42 by "content" i meant "state".

11:49 dnolen: tangled_z: I think you mean Typed ClojureScript?

11:49 if so, Typed ClojureScript has been maintained in a couple of years

11:51 Glenjamin: did you mean to say has?

12:16 dnolen: er yeah I mean "hasn't"

12:48 tangled_z: dnolen: thanks for the reply! yeah, that's what i meant.

12:48 Hmm, that's a shame.

12:48 I guess I'll use prismatic/schema then

12:52 rcassidy: anyone use paredit.vim? it seems to be mucking with being able to yank and delete to registers

13:14 bja: rcassidy: I was using vim-sexp and tpope's mappings for it

13:14 https://github.com/tpope/vim-sexp-mappings-for-regular-people

13:15 I had no such problems with it messing with my registers

13:27 rcassidy: bja: thanks, i'll check this out.

13:28 i've been used to the paredit mappings though, these are way different.... taking over the word movement operators seems both a great and awful idea.

13:29 oh man even the normal vim-sexp mappings are also pretty different. gah, muscle memory

13:32 ridcully: yep paredit messes with a lot of things (., block edits, registers...). yet i prefer it as it makes a good job on keeping the file intact

16:04 WorldsEndless: Trying to get some interop code to work, java has "Text.class" but it doesn't seem to have the same result as (class Text)

16:06 ridcully: ,(= (class String) (.getClass String))

16:06 clojurebot: true

16:06 WorldsEndless: Ok

16:08 luma: ,(class String)

16:08 clojurebot: java.lang.Class

16:09 ridcully: ,String

16:09 clojurebot: java.lang.String

16:19 justin_smith: WorldsEndless: java's Text.class is the same as clojure's Text (in case that is not clear here)

16:43 xyh: If I have (ns interpreter.buffer) in 'interpreter/buffer.clj' how do I use it in 'interpreter/core.clj' ?

16:43 justin_smith: (ns interpreter.core (:require [interpreter.buffer :as buffer])) (buffer/foo ...)

16:45 you can put anything after :as but the convention is just to grab the last part of the ns

16:46 xyh: repl says :: FileNotFoundException Could not locate interpreter/buffer__init.class or interpreter/buffer.clj on classpath.

16:46 justin_smith: so if you did [interpreter.buffer :as b] you could call (b/foo ...)

16:46 xyh: was there an error in interpreter.buffer when you first tried to load it?

16:47 oh wait, no

16:47 xyh: are you using leiningen?

16:49 xyh: I am using the REPL in emacs (but not cider.el)

16:49 justin_smith: xyh: what kind of repl? clojure.jar, lein?

16:49 xyh: clojure.jar

16:50 justin_smith: xyh: start the repl like this: java -cp clojure.jar:path/to/code/ clojure.main

16:50 where path/to/code is the path leading to the directory containing the interpreter/ directory

16:51 xyh: oh, this path is included in classpath then ?

16:51 justin_smith: xyh: the deal is that when you use require, clojure looks for the code on the classpath, so the code has to be findable on that path

16:51 xyh: that's what -cp does, yeah

16:51 xyh: thx

16:52 justin_smith: xyh: also, once you start using other people's libs, you'll find it much easier to use lein or boot, but for starting I think it's great to use clojure.jar (and know when it's simpler to just use that)

17:07 domgetter: leiningen says "WARNING: You're currently running as root; probably by accident." but I'm not logged in as root, just an account with sudoer access. Is this something I should worry about or should I make an account that doesn't make lein say that?

17:08 justin_smith: domgetter: huh, I have sudoer access and lein never tells me this...

17:08 (unless I'm root that is)

17:08 domgetter: hmm

17:09 oh I'm a dummy. I ran sudo ./lein

17:39 kwladyka: i want solve my old topic... i am looking solution to manage architecture in Clojure: 1) Change how functions work inside in any moment of project. For example function for save/read in DB. Or integration with ERP. 2) Change how functions work depend on configuration file. For example use another DB engine or another ERP system. 3) Do not pass nested injection dependency from function on level 1 to function on level 10 through level

17:39 2,3,4,5,6,7,8,9 if only level 10 needs it. 4) I could change how system work in configuration file and it should be use in one main file to inject into system. One place to control dependency.

17:40 In that moment i am thinking about defprotocol, Monads,Stuart Sierra compontent - somebody can say something clever in topic? :)

17:41 ridcully: have you looked into component, mount, ...

17:42 also imho a _massive_ change like this does not happen to often in a project. it _could_ take away valuable dev time for nothing. or just take the time to pick the "

17:42 kwladyka: ridcully yes and i am even more confuse :

17:42 :)

17:43 ridcully: right" db in the beginning

17:43 kwladyka: ofcourse but db is a good example

17:43 it could be ERP system

17:43 but it is easier to think about DB because everybody know how it works

17:44 so.... in your experience which of these are the best for my point 1,2,3,4 ?

17:46 ridcully: try them out and see what fits your needs. there is no "best"

17:47 if there would be a best we all would be using it it and nothing else would exist

17:49 kwladyka: ok so i will reverse the question. Can definitely say some of this methods don't meet the conditions?

17:50 justin_smith: kwladyka: all conventional clojure approaches fail your criteria

17:50 kwladyka: justin_smith why?

17:51 justin_smith: kwladyka: because clojure doesn't have mainstream options for config based DI

17:54 kwladyka: justin_smith so what do you use when you want have good flexible architecture? What is your opinion? Business is changing and need from time to time change part of system from definition. For example we can imagine we want change ERP system and another system with integrations should be ready for that. Just change way of communication and all should works.

17:55 justin_smith: kwladyka: I define an interface, my code is all written in terms of using that interface, and then I change the implementation of that interface (or which one we realize) in the apropriate place in the code

17:55 well, usually a protocol, but same concept

17:56 the problem with doing this via the config is then everyone has to agree on a config system, and the magic by which the config system controls the code, and unless everyone decides on the same one it will be worse than not having one

17:57 kwladyka: justin_smith so don't you use monads, Stuart Sierra components or similar solutions?

17:57 justin_smith: kwladyka: I absolutely do use components, but they have nothing to do with what we were just talking about

17:57 stuartsierra's component is about managing lifecycles of stateful resources

17:58 I mean yeah you could also use it to pass implementations of some protocol to clients, but that's not special about his system, you could do that via regular functions or data atached to ring requests or magic top level vars or whatever

18:01 kwladyka: also, when you mention passing some object from a to b, and from b to c, c to d, d to e, all the way down but only e needs it, every namespace level var is an extra arg passed to every function in your codebase, at least in the former case you can pick which things you are passing

18:01 kwladyka: so the conclusion is.... defprotocol is probably the best

18:02 justin_smith: That's what I'd use at least. And yeah, really clojure doesn't have the thing you are describing.

18:04 kwladyka: just looking the way to do really good architecture and i am doing loop in my head all the time about how it should work. I get lost somewhere in my head :)

18:07 but i learned more about how it shouldn't work ;) it is always something ;)

18:08 justin_smith: kwladyka: one comparison that I like to make is that a var, a dynamic threadbound var, a value in a config atom, and an argument passed explicitly to your function are all ways to get the right value to the place it is needed. It turns out that if you write the base level stuff in terms of explicitly passing an arg, you can use that to implement all of the others (and more). The others are not as flexible, and trying to use them other ways is a total

18:09 kwladyka: so on an app architecture level - when tying it all together - use whatever makes sense / whatever is simplest without hindering you

18:09 kwladyka: but in terms of putting together the parts that make up the whole, write it in terms of values explicitly passed in. That's 100% flexible and will be compatible with any system structure you ever decide to use.

18:10 so do all the details with explicitly passed in args, because it is easier, and then use whatever you want at the top level

18:14 kwladyka: justin_smith i have one problem with that. I don't want situation where something from function on level 1 is pass to function on level2,3,4,5,6,7,8,9 to use that in function on level 10. It makes a mess after some time. But maybe it has to be like that.

18:16 justin_smith: kwladyka: that's the price yes, but even that is simpler than what you would need to do if the code expects the thing to be a global and you need to bind it locally or use a different value in a specific context.

18:17 and it's not hard to write a wrapper that lets the higher level code just set a global or something, which the wrapper code passes in as args.

18:26 amalloy: think of the way ring handlers and middlewares work. there's all kinds of junk at the top level that is needed by stuff at the bottom level, and it all gets passed through by hand, but you don't "notice" because it's in one giant map

18:27 as long as you make the thing your level-10 function needs be part of the big ol' "configuration" object that every layer is passing through anyway, it's no big hassle to add more stuff to that

18:27 ie, it only hurts once

18:28 justin_smith: "clojure: it only hurts once"

18:29 ridcully: and ideas like "lets replace the db-url in config", pass it down and everything magically works, are pipe dreams

18:29 justin_smith: ridcully: so that's never actually worked?

18:30 ridcully: but remember he's not even talking about db-url, he's talking about which implementation of the db storage interface

18:30 ridcully: have you ever tested your stuff against h2 and the actualy production db is something "real"?

18:30 kwladyka: justin_smith bigger problem is after some time it make a mess in code. Imagine somebody change function 10 to not use some data passed into all this levels. And add something else. After some time when new person will see this code he wouldn't have any idea this parts of code/data are necessary and why it is that. Something deeper need this or somebody didn't remove it.

18:30 It is what i want to avoid.

18:31 and mess on higher function pass to function below and after few function, few programmers and time....

18:31 justin_smith: kwladyka: do you delete random fields from classes because you don't know what they are for? why would you do this with function arguments?

18:31 amalloy: kwladyka: that's why i'm saying you want one big parameter, instead of a lot of small ones, so that the intermediate functions don't need to know the details of what's being passed except the part they care about

18:31 ridcully: justin_smith: it (might) work on the level you suggested. domain-model. swap out "create customer" withing something else.

18:32 kwladyka: justin_smith because code after some time is unnecessary complex and hard to understand.

18:33 is has to be clean from time to time, but when you change something on the bottom you don't clean everything higher all the time.

18:33 justin_smith: kwladyka: right, and exactly the same thing happens with methods on objects, and fields on objects, and entire interfaces - when people lose track of the design, things stick around because nobody knows what is needed and what isn't

18:34 kwladyka: amalloy it can be some kind of solution

18:34 justin_smith: there's nothing special about using explicit args to pass values that is more likely to have that problem than any other factor of design

18:34 hell, I regularly find namespaces that just have no reason to exist any more

18:36 kwladyka: amalloy but from other hand you don't know what to pass then if there is only one big argument

18:36 justin_smith: kwladyka: sure you do - you pass that argument

18:37 kwladyka: what amalloy describes assumes that every function does this, all the way down to where you actually care about the values and pull them out of the map and use them

18:38 it leads to all of your "top level" functions that introduce major functionality always taking this one arg, and passing it along

18:38 kwladyka: justin_smith but if function on level 10 has arg called one-big-arg you don't what what this function really expect there.

18:39 amalloy: kwladyka: compare this to, eg, clojure.java.jdb

18:39 justin_smith: kwladyka: welcome to shitty design

18:39 amalloy: jdbc

18:39 all its interesting functions take as the first argument something called db

18:39 and you know they all take a database

18:40 what's in a database? you don't even really need to know. i certainly don't. it's something that you produce by calling (connect) or whatever, and passing it the args describing how to find a db

18:40 then later on, in its internal functions, it looks inside the db argument and finds whatever it needs

18:42 kwladyka: amalloy i am not sure it is the same. In this case db is generated by function from the same module to use in functions in the same module. But when you glue more things it is not so easy. It is not so compatible.

18:43 justin_smith: kwladyka: like I've been saying, there's nothing that will save you from bad design. But passing args explicitly solves a lot of problems caused by the other alternatives.

18:43 kwladyka: and still you pass only db connection there, it is one domain language and one part of something.

18:44 justin_smith it could be true. By "explicity" you mean more smaller arguments? Not one big?

18:45 ridcully: but isn't the same true in the upper levels? e.g. take some "create-order" fn, that takes a customer to create the order for. the customer there most likely is some map with internal stuff, that allows that

18:45 justin_smith: kwladyka: by explicitly I mean using arguments and not using anything global or implicit

18:45 kwladyka: whether it's one arg or a bunch in a hash-map doesn't matter

18:46 teepark: I'm going through @aphyr's "clojure from the ground up" and working on prblem 5 from https://aphyr.com/posts/305-clojure-from-the-ground-up-macros. this is where I am: https://gist.github.com/teepark/320c547d7fbd86ff8a8a

18:46 I'm pretty sure my exactify is working the way I want

18:46 but can't figure out how to alias those operators

18:47 justin_smith: and all these objections about losing track of what the args are for apply equally to interfaces, classes, methods, namespaces, literally every aspect of code - if you have a bad design and forget what things are for, every single one of these is capable of being a mess, I don't know why you are picking on function arguments specifically

18:48 kwladyka: justin_smith i am thinking more about rotation in project and people how don't have any idea what people before did an especially why they wrote something

18:48 teepark: the macroexpansion tries to "(let [clojure.core/+ ...]" but I think I need it to not expand to the qualified name in the binding

18:48 kwladyka: so many misspells... sorry for that

18:48 justin_smith: kwladyka: name one thing, one abstraction concept or level of organization that wouldn't have that problem

18:49 teepark: ` always fully qualifies symbols

18:50 teepark: you can avoid this by not using ` or by escaping the symbols to prevent ` from qualifying them

18:51 tomjack: hmm, when I remove a couple dependencies, the startup time for `LEIN_OFFLINE=1 lein trampoline repl :headless` goes from absolutely fucking ridiculous to normal...

18:53 justin_smith: ,(macroexpand `(let [~'+ -] (~'+ 1 1)))

18:53 clojurebot: (let* [+ clojure.core/-] (+ 1 1))

18:53 amalloy: tomjack: what about LEIN_FAST_TRAMPOLINE=1? afaik that's still not a default option, although there was some talk of it

18:53 of course that doesn't address your implicit question about why these deps slow things down, but maybe that speeds stuff up enough that it's fine

18:53 justin_smith: ,(eval `(let [~'+ -] (~'+ 1 1)))

18:53 clojurebot: 0

18:53 tomjack: oh, hmm, I didn't think to ablate trampoline

18:54 justin_smith: tomjack: I've found heavy macro usage can make a difference - the difference in startup with and without core.async is noticible for example

18:54 teepark: justin_smith: thanks. the ~'+ quoting was what I was missing

18:55 justin_smith: teepark: yup - the reason ` does that qualifying thing is this kind of macro is considered messy and is historically a huge source of bugs

18:55 teepark: yeah I'd expect so

18:55 justin_smith: spooky action at a distance, code on the outside can change what code inside it means

18:55 teepark: not something I'd expect to do outside of an exercise

18:55 justin_smith: :)

18:56 tomjack: LEIN_FAST_TRAMPOLINE does not appear to help, and `lein repl` appears to have the same problem. guess I will do the obvious thing and slap yourkit on it

18:56 justin_smith: tomjack: if fast trampoline doesn't help it's not the dep resolution that is the time sink

18:57 after that I would suspect deep dep trees pulling up huge amounts of code to compile, or crazy macros that demand a lot from the compiler

18:57 but yeah, yourkit will probably help

18:57 tomjack: I don't understand 'code to compile' or 'crazy macros'

18:58 I've just got deps, I'm not loading any of the code in them, afaik

18:58 justin_smith: tomjack: oh, your repl starts in user?

18:58 tomjack: the dep trees are crazy though

18:58 yeah

18:58 amalloy: IME running yourkit while clojure starts up will not give you anything very useful

18:58 what are the deps that slow stuff down?

18:58 justin_smith: most people have their repls set to start up loading their main ns

18:58 amalloy: i dunno about "most people"

18:58 tomjack: deps into projects in my company's java monorepo

18:59 maybe lein takes linear time in the craziness of my dep tree, and it's just the dep tree which is absolutely fucking ridiculous

19:01 justin_smith: tomjack: but with FAST_TRAMPOLINE it isn't recalculating your deps

19:01 it just uses the cached deps after the first time

19:02 it literally puts classpath in a file, and if your project.clj has not changed since the last startup, it reuses that classpath from the file

19:03 unless you do something that would slow down lein in the process of even deciding if your project has changed, but that seems super weird...

19:03 tomjack: so to be clear did you run LEIN_FAST_TRAMPOLINE=truthy lein trampoline repl at least twice in a row before deciding it was starting slowly?

19:04 because if repl boots to user, that should start about as fast as a simple clojure.jar startup

19:04 kwladyka: Thank you all guys for good discussion. It is 1 am so i am going sleep. Goodnight!

19:07 tomjack: ah, twice, no

19:07 thanks, I didn't wait for the first time to finish...

19:07 (never heard of LEIN_FAST_TRAMPOLINE)

19:10 justin_smith: tomjack: yeah, it basically sets up a cache for classpath, it works

19:11 tomjack: the one gotcha to "lein trampoline repl" is I've seen startup errors from initial namespace load (when my repl loads up to my namespace) fall through the cracks - the repl says it is in my namespace but my code isn't loaded with no error message

19:11 but if you expect to use user as your init ns, I can't think of a reason to ever not use trampoline

20:12 Kamuela: What's the preferred way to install Clojure on a Mac?

20:14 justin_smith: Kamuela: put leiningen in your ~/bin/lein

20:14 Kamuela: leiningen is a dependency manager and it will take care of everything else (it's a shell script)

20:15 Kamuela: you can also just download clojure.jar and run that via java (any jvm 1.6 or newer works)

20:16 pilne: after using lein, everything else just feels uncivilized >.< (well... rust, go, and stack (for haskell) actually feel pretty good too >.<)

20:17 justin_smith: yeah, lein is pretty amazing, pity about the startup time

20:17 but usually the startup time is worth it

20:17 pilne: fun fact, people complain about clojure startup time a lot, but usually they don't realize most of that startup time is just leiningen

20:18 pilne: yeah, but unlike the rest (i think) of the jvm langs, startup time is really only a "once per coding session" thing for clojure (:

20:18 justin_smith: it's true, clojure does dynamism pretty well

20:19 pilne: it's funny, every time i'm thrown a programming problem now, 9/10 times there's already a "good way" to do it in clojure, and if there isn't, someone far more capable than I is "almost there" lol

20:19 i feel like clojure is extremely pragmatic, like.. ridiculously so (:

20:20 justin_smith: a very special mix of pragmatic while being unafraid to be unconventional (if there is an unconventional solution that is simpler than the normal thing)

20:20 xyh: why when I copy my code into the REPL it runs fine,

20:20 but when I use 'lein run' to run it, or use 'clojure <file>' to run it,

20:20 it says 'StackOverflowError'

20:20 justin_smith: so you might need to spend some time learning some new concepts, but there's always a payoff

20:21 xyh: how is this possible ...

20:21 justin_smith: xyh: interesting, I'm wondering if maybe realizing things early due to printing in the repl might be preventing a concat bomb

20:21 pilne: eh, for me at least, lisp/scheme just felt like coming home, i've been mentally fighting OOP stuff in c++/java/python for years (as in, struggling to compose things elegantly in those langauges)

20:21 justin_smith: xyh: when nested concat calls get deep enough, it can blow the stack when you first read the value

20:22 xyh: but in a repl, it's common to realize things due to printing values

20:22 xyh: this might not be it, but it's the first thing I think of that would be different in a repl and lein run and cause a stack overflow

20:22 pilne: is there a way to tweak my default jvm (or the one for *any* clojure repl) to have massive stack/heap, just for... science?

20:23 justin_smith: pilne: yes, when you start the jvm you can tell it how big the stack and heap should go

20:23 pilne: :jvm-opts in a leiningen project.clj will be passed along

20:23 pilne: beautiful, tyvm

20:23 i should probably google more honestly though

20:23 justin_smith: :)

20:24 pilne: this nightcode/nightmode standalone clojure ide looks like something i should throw on a puppylinux usb stick... you know... again for science (:

20:25 Kamuela: pilne: I’m using that

20:26 and yeah I think I did do that lein thing, only problem is I think I used brew

20:26 Maybe I shouldn’t?

20:26 Only reason I ask is because I think clojure is still 1.6.0 for me and I’ve been trying to figure out how to upgrade

20:26 justin_smith: Kamuela: brew is good too, it's just newer and lein has more users

20:26 Kamuela: in each project you can decide what clojure version it uses

20:26 this is true if you use lein, boot, or even just clojure.jar

20:27 Kamuela: interesting, so 1.6.0 is probably just a target in a config file then

20:27 justin_smith: right

20:27 xyh: would you please try this :: https://www.refheap.com/113972

20:27 it should print the following two lines :

20:27 pilne: since it seems like i'm starting a collection of clojures, how far back should one go (i've got 1.7 and 1.8 now)

20:27 xyh: 16

20:27 bye bye ^-^/

20:28 try copy (1) into REPL (2) run by 'clojure <file>'

20:28 * try (1) copy into REPL (2) run by 'clojure <file>'

20:30 Kamuela: ah i see, dependencies

20:31 justin_smith: xyh: it's getting a stack overflow error while compiling

20:32 xyh: ah!~

20:32 justin_smith: oh right, because it calls that thing at the top level, never mind

20:32 xyh: it says "compiling" but it is really in that bottom line

20:32 xyh: yes maybe due to JIT

20:33 justin_smith: no, there's no JIT here

20:33 xyh: it's true, if I run clojure.jar and give it that file, it blows up, but if I start a clojure.jar repl, then paste in the contents of the file into the terminal, it is fine

20:33 xyh: oh! have you tryed copy the code into REPL ?

20:33 yes

20:34 justin_smith: right, it works if you paste into a repl, and breaks when loading from the file

20:34 but it is definitely not a laziness issue

20:34 because you are not doing anything lazy here

20:36 xyh: one thing I am very suspicious of is your call to (recur) on line 67 - there is literally nothing other than an exception that will make that thing stop looping, right?

20:36 xyh: yes

20:37 because it is an interpreter

20:37 justin_smith: so that's your interpreter loop?

20:38 xyh: yes, one can view it this loop as 'return-stack interpreter'

20:38 * view this loop

20:43 justin_smith: xyh: change map tomapv on line 108 and it works

20:43 *to mapv

20:45 xyh: map is lazy, if you do not use the result it does not calculate a result, in a repl its result is getting realized as a side effect, when running the file directly the side effect does not happen, the laziness is not forced, and thus you have a lazy-bomb where you have too many layers of lazy ops to realize at once and your blow the stack

20:45 xyh: thank you justin_smith

20:45 justin_smith: xyh: mapv is not lazy, and thus you do some of the work ahead of time and don't blow the stack

20:45 xyh: np, laziness is weird and hard

20:46 xyh: it took a while to find your problem - that's seemingly the only place you are using laziness in the entire codebase, if you had used lazy functions in two places I wouldn't even know which one was the problem

20:46 haha

20:47 xyh: I will go learn more about map and mapv in the doc

20:48 justin_smith: xyh: it's not specific to map at all

20:48 xyh: it's about how lazy-seq works

20:49 xyh: oh my ... not in the doc ?

20:49 justin_smith: it is in the doc! the doc for lazy-seq

20:49 xyh: ok

20:49 justin_smith: but the specific issue is explained well in a blog from stuartsierra

20:49 one moment...

20:50 xyh: this is why I mentioned concat at first - it's the same problem, it's a thing about lazy-seq, but it's most commonly seen with usage of concat http://stuartsierra.com/2015/04/26/clojure-donts-concat

20:51 xyh: great :)

20:52 justin_smith: xyh: stuartsierra explains how concat causes this problem via lazy-seq, but map also uses lazy-seq so it's the same issue you saw, really

20:53 xyh: this is what I am doing, by the way :: https://github.com/cicada-language/threaded-code-interpreter

20:53 I have a clojure version now :: https://github.com/cicada-language/threaded-code-interpreter/tree/master/native-array-memory/clojure/interpreter

20:54 justin_smith: cool

20:54 I hope you enjoyed playing with clojure and got some hint of what you could learn from it

20:55 xyh: is there an OO framework in clojure ?

20:55 justin_smith: xyh: clojure compiles every function to jvm bytecode and you can directly access the jvm

20:56 also, yes, you can use OO features in clojure code (eg. defrecord, defprotocol)

20:56 but clojure stays pretty close to the features of the vm itself, which is implicitly OO

20:56 pilne: was the patch discussed in one of the links on that concat page ever implemented into core? or was it shrugged off?

20:56 justin_smith: xyh: I definitely understand your code much better when I read the OCaml version

20:57 xyh: yes, I like type system too

20:57 justin_smith: pilne: no idea, but as he mentions, any usage of lazy-seq can hit this problem

20:57 xyh: yeah, ml family is the platonic ideal of the type system for sure :)

20:59 pilne: true justin_smith, i guess it is just smarter to explicitly not mix a lazy-seq into an eager context

20:59 justin_smith: xyh: you use hash tables in the OCaml version, but don't use them in clojure where we even have a syntax literal for them

21:00 pilne: well, we at least have to be smart about the eager / lazy boundary, yes.

21:00 xyh: you mean primitive-function-record ?

21:01 justin_smith: xyh: in_host_name_record is the hash table in the OCaml version

21:01 Kamuela: the reason I’m liking clojure is because it’s so incredibly consistent with its syntax

21:02 xyh: justin_smith: in clojure it is (def name-jo-map (atom (hash-map)))

21:02 justin_smith: ahh, - the idiomatic version of (hash-map) is just {}

21:02 ,(= (hash-map) {})

21:02 clojurebot: true

21:03 justin_smith: xyh: the hash-map function is only really used when the keys and vals are all in order in a collection and are not yet partitioned into two-element vectors

21:03 then we do (apply hash-map coll)

21:04 otherwise there is pretty much always a more straightforward alternative to calling hash-map

21:04 devn: im spacing out: is there a built-in for getting the value of the max key (assume keys are numbers) in a map?

21:04 xyh: I see

21:05 justin_smith: devn: (max-key key m)

21:05 ,(apply max-key key {1 0 3 2 22 7})

21:05 clojurebot: [22 7]

21:05 justin_smith: well, clearly I forgot apply the first itme there

21:06 devn: justin_smith: lol, i think it's time i step away from the keyword

21:06 keyboard* (see?)

21:06 I was messing with max/min-key, and that usage pattern totally escaped me

21:06 didn't think to use clojure.core/key

21:07 justin_smith: devn: now I want to find some useful one-line that uses max-key, key, and max

21:07 haha

21:07 ,(apply max (apply max-key key {1 0 3 2 22 7}))

21:07 clojurebot: 22

21:07 devn: justin_smith: yeah, it feels i dunno, weird

21:08 justin_smith: ,(apply max (apply max-key key {1 0 3 2 22 420}))

21:08 clojurebot: 420

21:08 justin_smith: lol, time to go home

21:08 devn: i think you might be able to make it worse...

21:09 pilne: Kamuela:: that is because of the whole "code is data" concept it brought from the lisp world, the syntax has to be consistent to enable easy parsing to make the magics happen (:

21:09 justin_smith: devn: hmm, how many clojure.core functions have the form x-y where x and y are also core functions?

21:10 devn: justin_smith: probably easy enough to discover with ns-publics

21:11 Kamuela: pilne: it’s great and my first lisp, the closest to functional I’ve experienced is JS with the new immutable/functional popular paradigms

21:13 justin_smith: ,(->> 'clojure.core ns-publics keys (map name) (map #(clojure.string/split % #"-")) (filter #(> (count %) 1)) (filter #(every? (comp resolve symbol) (remove empty? %))))

21:13 clojurebot: (["chunk" "first"] ["when" "first"] ["find" "ns"] ["take" "last"] ["take" "nth"] ...)

21:13 justin_smith: devn: ^ answering my own question, lol

21:13 devn: you sonofa

21:13 i was just about there

21:14 im not peeking!

21:14 justin_smith: lol

21:14 * justin_smith makes a finger gun, goes pow, and blows away the smoke.

21:14 devn: i might be way off, but i got 268

21:14 justin_smith: devn: I looked only in clojure.core, and only for things that had hyphens in them in the first place

21:14 devn: forgot to go distinct

21:15 94

21:15 justin_smith: devn: in just clojure.core?

21:15 devn: yar

21:15 pilne: clojure wasn't the first language that really caught my eye when i got back into programming, but it is the one i keep coming back to, it and haskell have really caught my eye (although this startup little jvm language "lux" seems to be tempting me with the best of both those worlds >.<)

21:16 justin_smith: devn: my favorite ["cond" ">"] - I never read cond-> as two clojure functions separated by a hyphen before

21:18 devn: justin_smith: what about -> :D

21:18 justin_smith: haha

21:18 "" is not a clojure function

21:18 devn: my solution was so much more roundabout than yours

21:18 it's making me ill

21:20 justin_smith: devn: it's OK, I'm about to go home and get really stoned and my code will be terrible

21:20 pilne: nah man

21:20 devn: ,(let [split-up (group-by #(.contains % "-") (map (comp str first) (ns-publics 'clojure.core))) [with-hyphens without-hyphens] (map #(get split-up %) [true false])] (for [x with-hyphens :let [fs (clojure.string/split x #"-")] f fs :when (some #{f} without-hyphens)] [x f]))

21:20 clojurebot: (["restart-agent" "agent"] ["sort-by" "sort"] ["chunk-first" "chunk"] ["chunk-first" "first"] ["tree-seq" "seq"] ...)

21:20 pilne: it will just be really really really abstract

21:21 i feel like clojure offers me a lot of what i really like about haskell without the handcuffs of forced purity.

21:21 justin_smith: pilne: s/handcuffs/helmet

21:22 pilne: lol

21:22 justin_smith: (I say this as someone who never wears a helmet when riding his bicycle)

21:22 pilne: my first through was "hugging jacket"

21:22 justin_smith: but really, haskell is protecting you from somethign there

21:22 pilne: i agree it is protecting oneself, but it is also not trivial to fully grasp/apply how to "get around that protection in a safe way" (at least for me)

21:22 devn: I totally abuse clojure.core/for (for [x xs :let [ys (get x :ys)] y ys :when (some #{y} #{:a :b :c})] [x y])

21:23 haskell is pretty rad. it's not my cup'o tea though, i'm afraid

21:24 pilne: same, i enjoy haskell like i enjoy theoretical physics, from an armchair with a bong and a beer...

21:24 devn: well, one of them is closer to actual science

21:25 philip waddler in his talk at strangeloop last year said: "real sciences don't have to put 'science' in their names"

21:25 pilne: lol

21:25 justin_smith: haha, nice

21:25 devn: i've been having a lot of conversations with some knowledgable static typing enthusiasts these past few months. i've even seen a couple clojure people start to be drawn into the light

21:26 justin_smith: OK, actually leaving the office now

21:26 devn: justin_smith: come on back :)

21:28 pilne: eh, i'm more for dynamic with the option to static (via annotation or whatnot, as long as that annotation actually does some good at the compiler end...)

21:29 but with ghci and haskell, i don't mind the static requirement on types, just the whole mutable-monad-magic stuff still twists my noggin

21:49 stapler: hi! on clojars.org I don't see any spot for me to put my public key

21:49 and lein wants me to do that so i can throw stuff on clojars

22:36 justin_smith: stapler: have you created your account?

22:44 stapler: justin_smith: yes

22:50 justin_smith: stapler: wow, I can't find the public key upload in the current code...

22:50 *current site

22:50 stapler: bit broken, i know

22:55 justin_smith: stapler: yeah, looks like either a documentation bug or a functionality bug

23:30 TimMc: I wonder if that feature was disabled...

23:31 justin_smith: TimMc: they try to sign jars, so you'd think they would also host a copy of the public key that goes with it

23:33 zimablue: hey, does anyone know a good working example of boot with both a clojure backend and figwheel/browser repl?

23:34 tenzing works for me but I don't know how to connect a backend to it

Logging service provided by n01se.net