#clojure logs

2016-02-11

00:18tolstoyjustin_smith: Remember that "node.js sockets on windows" discussion a few days back? Turns out (™), I had to execute those sorts of things in the "main" process, not in the "render" process. Why it worked great on OSX and Win7, I've no idea.
01:30renlHi may i ask for gen-class, can the class be compiled into .java instead of bytecodes so I can check what code did the gen-class create?
01:43MasseRrenl: you can always decompile the class
01:43renlk thanks :)
01:44renlis :state in gen-class fields in a java class?
02:25renlanyone used Coinor Ipopt on clojure? or for that matter are there any nonlinear programming library for clojure out there?
02:38Voxnihili1618hey
04:07python476hi, I get stack overflow with a function of two signature http://pastie.org/10717536
04:07python476calling (f) overflow, calling (f <default>) runs fine
04:08python476is it misguided to define a fun (defn f ([] (f <default>)) ([a] <real-logic>)) ?
04:09opqdonutno that's normal
04:10opqdonutthe problem is you're calling "(rl [i 32])"
04:10opqdonutbut you meant "(rl i 32)"
04:10opqdonutdo you get the differences?
04:11python476wtf do I
04:11python476I did
04:12python476opqdonut: I often do this typo .. I need to rest
04:14python476thanks a lot donut
04:37CStormBuilding a very small api in clojure. I grab some data from an API and saves/replace it to a db ever x hour. Then an app can get that data from my API. I am new to clojure, so which database should i use for this simple project?
04:42schmirCStorm: sqlite or H2 may be suitable.
04:42schmiror just keep it in memory
04:43hiredmanthe sqlite options for the jvm are not very good, h2 is very odd about multithreading, use derby
04:43CStormmaybe i should start doing it en memory and then just move it to a db after
04:45CStormand what about deployment, which should i go for? heroku, digitalocean? were do most deploy their clojure?
04:45schmirI didn't run into any problems with sqlite.
04:45CStormif i dont wanna roll my own.
04:45CStormwrote all three possiblities down, schmir and hiredman.
04:52qsysCStorm: I usually use H2 for that kind of apps
04:52CStormthanks.
04:52qsysI used to think to store it as plain datastructures (compressing with nippy)
04:53qsysbut I don't see the point of not using a db
04:53qsysand I would use 'lightweight datomic' if available :p
04:53qsysdatascript might be a kind of an option, but that's very browser-oriented
04:53qsysso I prefer H2 so far...
04:59CStormthanks.
05:01hiredmanhttp://www.h2database.com/html/features.html#multiple_connections explains that h2 synchronizes (serializes via locks) access to databases by default, and if you read further the setting to change that is considered experimental (and has been for I think years now)
05:04CStormWhere should i deploy it all if i just want to get something going quickly?
05:05qsystrue, but never had any issues with it so far, with H2 for small applications. Since v >1.4, it uses MVCC, so no locking
05:05hiredmanqsys: that is, as far as I know, not true
05:11WickedShellis there a way to change where lein is using for scratch space? it keeps filling up disk C (on windows atm sadly) which causes all sorts of problems. I have tons of scratch space on other drives, but C: optimistically has 500mb at the start of the day...
05:12wmealingWickedShell: good question, does it put it in temp ?
05:14WickedShellwmealing, no clue, I'm assuming, although I'm looking, this is the error I see: http://pastebin.com/cw2ZRSy1
05:14WickedShelland of course the fact that there are now 0 bytes free...
05:14wmealingok, lets have a look
05:15wmealingi assume its https://github.com/technomancy/leiningen/blob/master/src/leiningen/javac.clj
05:15wmealingline 12 makes me think that
05:15wmealingits probably
05:15wmealing (let [options-file (File/createTempFile ".leiningen-cmdline" nil)]
05:15wmealingline 64
05:16WickedShellseems reasonable, although I'm working off a different disk
05:16wmealingok
05:16wmealingyep
05:16wmealingit seems to call javas interpretation
05:16wmealingjava.io.File
05:16wmealingi'm thinking, and i haven't confirmed yet
05:17wmealingis that java looks at the windows environment variables
05:17wmealingto find where to store tmp files
05:17wmealingso, stackoverflow suggests its %TEMP%
05:18wmealingstart->run->%TEMP%
05:18WickedShellhmm yeah that's on C
05:18wmealingok
05:18wmealingso, again windows isnt my thing.. i think you can set that
05:18wmealinghttp://answers.microsoft.com/en-us/windows/forum/windows_7-files/change-location-of-temp-files-folder-to-another/19f13330-dde1-404c-aa27-a76c0b450818?auth=1
05:18wmealingsee the answer given there
05:19wmealingstarting with "hi mike"
05:19WickedShellyeah I can change that, (ironically my temp is only 70 megs :P)
05:19wmealingrighto !
05:19wmealingbtw, might be time to clean up C
05:19wmealingif you're using a modern windows partition
05:19wmealingsorry, not partition
05:19wmealingversion
05:19WickedShell64GB SSD was not enough....
05:19wmealingdo you realise that symlinks work ?
05:19WickedShellthe whole windows side by side store thing is awful :P
05:19wmealingie, to make a directory on another disk appear on another drive
05:20WickedShellYeah I have a fair amount of the My Documents etc pointed elsewhere, didn't realize it had proper symlinks
05:20wmealingyeah, me neither till not long ago
05:20WickedShella couple of programs (pcb design tools etc) require ~2GB's a pop on C and wouldnt install anywhere else...
05:20WickedShellwas really annoying
05:21wmealingwhat i did, was install it… then copy it to another disk
05:21wmealingthen make the symlink
05:21wmealingto that new disk
05:21wmealingthis doesn't work for system things though
05:21wmealingonly for non core.. stuff
05:25wmealingWickedShell: do you need to reboot for that to work ?
05:26WickedShellno, usually need to reload any command prompts/enviroments there but otherwise no
05:26wmealingoh ok
05:28WickedShellthanks
05:28wmealingWickedShell: working ?
05:29WickedShellyeah
05:29wmealingWickedShell: awesome ! have bucketloads of fun
05:30wmealingthankyou for flying clojure airlines.
08:18jweisswhat's the recommended way to factor out common code from a defn where the different arities share code? private function in the same ns?
08:22opqdonutjweiss: if you can't just delegate to the more specific arity, then yeah private function seems apropos
08:29KamuelaPrivate functions are achieved how?
08:30opqdonut(defn- foo ...)
08:30opqdonutwhich just does (defn ^:private foo ...)
08:30luma(defn ^:private foo ...) is the preferred way
08:31opqdonutis it?
08:31opqdonutwhy?
08:31clojurebotwhy is Why
08:32ridcullyWhy?
08:32clojurebotWhy is the ram gone
08:32ridcullyso true
11:10sdegutisIs there a name for this kind of transformation? [[:a] [:b :c] [:d]] => [[:a :b :d] [:a :c :d]]
11:11lumacartesian product
11:17sdegutisThanks luma.
11:17Kah0onaquick question about testing with Midje. when i (use 'midje.repl), and then run some test, it seems my test environment variables (using environ.core) aren't picked up, instead it picks the 'dev' environment vars
11:18Kah0onaanyone any idea where I should specify it? I do `lein repl` -> `(use 'midje.repl)` -> `(autotest)`
11:23Kah0onaah start the repl with-profile +test...
11:23Kah0onaduh. :)
11:48benjyz1hello. I have a question about protocols and methods
11:48benjyz1I have what in Java would be an Interface. I have several of them, and a wrapper around it, i.e. a facade pattern
11:49benjyz1what would this be in Clojure? I would define the interface as a protocol?
11:50benjyz1it is not a protocol, but it doesn't apply to different types.. perhaps someone has an idea
11:55justin_smithbenjyz1: in clojure protocols are needed in order to have methods, even if only one type implements it (unless you use gen-class or an existing interface)
11:59justin_smithbenjyz1: what you want is precisely a protocol - that is how we do facades in clojure
12:01benjyz1any different between records and types? I guess in OO everything being a class mixes many different things together
12:02benjyz1*difference
12:02justin_smithbenjyz1: defrecord and deftypes both create classes
12:02justin_smithbenjyz1: clojure doesn't hide the jvm class system, it just provides opinionated tools that simplify it
12:03rhg135A record is merely a class with some implementations
12:03benjyz1yes. so far I've taken the approach to avoid types and classes altogether. which works well on a small scale
12:03justin_smithbenjyz1: there are no types
12:03rhg135Importantly, Associative
12:03justin_smithdeftype and defrecord create classes.
12:03justin_smithdefrecord automatically implements clojure's hash-map methods
12:04justin_smith(in the generated class)
12:04benjyz1ok, I see. I think generally class and object and type are now very precise concepts
12:04benjyz1*not
12:04justin_smithbenjyz1: the jvm has classes and primitives
12:04justin_smithbenjyz1: we do not implement anything in clojure that isn't a class
12:05justin_smithbenjyz1: contrast to scala which enforces abstractions that don't exist in the bare vm, we don't attempt this
12:05benjyz1ah, that's where the mess in scala comes from ^^
12:06justin_smithhaha
12:07Glenjaminwouldn't protocols fall into that category?
12:08benjyz1is it a bad idea to have deftypes with the same name as a namespace?
12:08justin_smithbenjyz1: deftypes should use CamelCase like you would use for Classes
12:08justin_smith(as should defrecords)
12:23rhg135Not really, Glenjamin, the builtin nashorn engine does it too,
12:23justin_smithGlenjamin: do protocols enforce any restrictions their underlying Interface would not?
12:23justin_smithGlenjamin: we add functionality but not restrictions, is my impression
12:26Glenjamini see, they're effectively liskov substitutable for interfaces
12:27justin_smithI think so
12:28rhg135Not exactly. If you pass one extended dynamically the method calls fail
12:33justin_smithrhg135: wait, since you can't dynamically extend Interfaces, doesn't this still fit liskov?
12:33justin_smithmaybe I'm confused
12:34rhg135you may be right.
12:34rhg135I thought it meant b must work where a does.
12:35justin_smithmy intent was that protocols can do all things interfaces do, while offering other features as well
12:36rhg135Yeah, they're nice.
12:36justin_smithunder the umbrella of clojure adding functionality but not adding extra restrictions to what the vm offers (unlike eg. scala)
12:36justin_smithagreed!
12:37justin_smithor would a scala expert counter that the jvm level features will all work and the restrictions are only on scala specific extensions in the same way? I don't know scala well enough to address that, but I wonder.
12:38rhg135I think #scala exists
12:39justin_smithyes, I might just have to go ask that question
12:39rhg135Good luck!
12:51justin_smith#scala says "using scala from other langs is a pain in the ass, but can be possible if you are careful to implement all features as java interfaces in the scala code"
12:51justin_smithso there we go
12:51justin_smithno attempt at the liskov thing there
12:59rhg135I guess by pita they mean more than RT.resolve(...).invoke()
13:01justin_smithright, they mean it isn't even safe unless the scala is restricted to a java interface
13:01rhg135Oh dear. That's bad
13:01rhg135Really bad
13:02justin_smiththere are certain constraints that the scala compiler understands that aren't even represented at the vm level
13:02yuungi'm writing a small blog application with clojure. coming from a rails background, i'm very used to the MVC pattern. i was wondering what your thoughts are regarding how I should implement models with clojure/how to handle db interactions?
13:02justin_smithso you can try it outside scala if you want but who knows what you get? haa
13:03yuungor if i should even stick with the MVC paradigm with a functional language
13:03yuungthe only library i'm using is ring, and handlers sound a lot like controllers to me
13:04rhg135Isn't that like protocols? You get java features but if you use more it won't work
13:04justin_smithyuung: well, the typical preference in clojure is to use vanilla clojure data like hash-maps and lists and vectors, and even something as simple as clojure.java.jdbc will easily extend that to the db
13:04yuungjustin_smith, yeah; i've got jdbc working. just wondering if there was an established pattern
13:05yuungjustin_smith however i'm happy to use poco :)
13:05sdegutisI don't think that's what it's really called.
13:05yuungi guess plain old clojure objects is kind of a contradiction... let's say pocd
13:05sdegutisIt's almost like transposing.
13:07rhg135pod
13:08justin_smithdata :)
13:09rhg135But, acronyms are cool
13:09yuungikr ;p
13:10justin_smithyuung: you can get pretty far with a record in db becoming a hash-map in clojure, and we have existing tools to put hash-maps into classes when we need to attach custom behaviors for OO (via defrecord).
13:10yuung justin_smith what should i google for the hash-map -> classes thing? also doesn't that kind of break the philosophy of fp?
13:11rhg135Isn't that a subset of ORM?
13:11justin_smithyuung: we use OO unashamedly
13:11clojurebotPardon?
13:12stoopkidhi is clojure a total functional programming language?
13:12justin_smithstoopkid: no
13:12rhg135I don't think of records as OO
13:12rhg135More like optimization
13:13justin_smithyuung: when you do (defrecord Foo [field field2 ...] SomeInterface (someMethod [this ...] ...)) it creates a function map->Foo which turns a hashmap into a Foo
13:13justin_smithrhg135: they tie behaviors to data, that's OO
13:13rhg135You could always use anonymous classes
13:13justin_smithit's not the shitty part of OO
13:13justin_smithbut still OO
13:13rhg135True
13:14rhg135They're hardly OO though
13:17justin_smithrhg135: I consider inheritance a parasite on programming that primarily latched onto OO
13:18rhg135Lol
13:19rhg135But lately I've found that I get many code-induced nightmares due to things other than inheritance
13:24rhg135When's that?
13:26justin_smithapril 15-16 but I am going a day early for the datomic training
13:26justin_smithalso they billed my opportunity grant donation as if it was a ticket which is slightly odd
13:27rhg135That's not too far off
13:27rhg135I'm so excited
13:28justin_smithwell they asked me who the opportunity grant was for so I clicked "I don't know yet" so they said it was snoozed or something
13:30rhg135I wonder what the talks will be about
13:31justin_smithan ex-coworker of mine got the official approval for a talk about learning clojure as a junior programmer, so her talk is probably just going to be about how I'm a huge jerk.
13:32rhg135Lmao, I need to watch that one
13:39sdegutisDoes this make sense? (= [[:a :b :d :e] [:a :c :d :e] [:a :b :d :f] [:a :c :d :f]] (f [[:a] [:b :c] [:d] [:e :f]]))
13:40sdegutisOr https://gist.github.com/sdegutis/6bcbafa56cebb07a9da3 for pretty-printed version.
13:40sdegutisI have no idea what this kind of transformation is called.
13:44sdegutisOh yeah cartesian-product does look right actually.
13:46rhg135A deduplicated one
13:47amalloysdegutis: in haskell that function is called sequence. in clojure we don't really have it built in, but it's not too ahrd to write with a (for ...) that calls itself recursively
13:47binjuredasked my wife we could name our first child amalloy, she said no and also we don't want children remember. i tried man!
13:47amalloyhaha
13:47sdegutisamalloy: apparently it's clojure.math.combinatorics/cartesian-product
13:48amalloyyes, that too
13:48sdegutisExcept it results in the middle two collections being swapped.
13:48sdegutisamalloy: Hmm thanks for the idea of recursive (for)s. I would like to do it that way preferably.
13:48sdegutisHowever I don't know how to implement it. I never took any CS classes or went to university.
13:49sdegutisI went to junior college and all I learned there was Visual Basic .NET
13:49binjuredthat's basically lisp *ducks*
13:50sdegutisHmm the implementation of clojure.math.combinatorics/cartesian-product uses (loop).
13:51amalloy,((fn cart [coll] (lazy-seq (if (empty? coll) '(()) (for [more (cart (rest coll)), x (first coll)] (cons x more))))) '((a b) (c) (d e) (f)))
13:51clojurebot((a c d f) (b c d f) (a c e f) (b c e f))
13:51amalloyrecursive for is an important pattern to get the hang of. it's everywhere, if you start viewing more things as trees
13:51sdegutisHmm neat implementation.
13:51rcassidyamalloy: doesn't one use of 'for' get you what you want?
13:51rcassidyor am I missing something
13:52amalloytry it and see
13:52sdegutisamalloy: why is this a lazy collection?
13:52amalloywhy wouldn't it be?
13:52rcassidy,(for [w [:a] x [:b :c] y [:d] z [:e :f]] [w x y z])
13:52sdegutisIt seems like an optimization, right?
13:52clojurebot([:a :b :d :e] [:a :b :d :f] [:a :c :d :e] [:a :c :d :f])
13:53sdegutisrcassidy: yeah that was my initial solution, but I couldn't figure out how to do it with a variable number of sequences.
13:53amalloyrcassidy: that's fine if you have four different collections
13:53rcassidyahhhhhh OK
13:53justin_smithrhg135: but that only works if you know ahead of time how many args
13:53amalloytry it with one list of lists
13:53rcassidymacros, maybe?
13:53rcassidy:p
13:53justin_smitherr
13:53amalloysure, get back to me when your macro can know at compile-time what data you get at runtime
13:53rcassidyhence the maybe. lol.
13:54sdegutisMaybe I can macro-expand the for-loop though and use the same logic in that but with variable number of sequences.
13:55sdegutisWHOA, never mind!
13:55rcassidythat's what I was thinking
13:55rcassidybut I'm not familiar with clojure macros yet
13:55sdegutishttps://gist.github.com/sdegutis/953cf7cee228b755fd97
13:56rhg135Oh my.
13:56rhg135That's a lot of code
13:57rcassidylol
13:57rcassidyyikes
13:57amalloyfor does a ton of stuff that's either (a) for performance, or (b) for handling weirdo keywords like :let or :when in the middle
13:57sdegutisahh
13:57amalloyif you wrote for yourself it would be slower and less expressive, but much shorter
13:58amalloy(exercise: implement for)
13:58rcassidyfound some implementations with for and recur but oh man that's weird
14:01rhg135,(macroexpand '(defrecord X [field]))
14:01clojurebot(let* [] (clojure.core/declare ->X) (clojure.core/declare map->X) (deftype* sandbox/X sandbox.X [field __meta __extmap] :implements ...) ...)
14:01WorldsEndlessCan anyone verify that you CANNOT provide contingent definitions in an :or portion of an arguments definition? (unlike let, which allows you to draw on earlier-defined values)
14:02rhg135Macros are awesome
14:04WorldsEndlessHere's code that's not working; I'm probably breaking more than one Clojure rule
14:04WorldsEndlesshttps://www.refheap.com/114716
14:05WorldsEndlessContingent :or definitions, and nested -> statements
14:06amalloymaps aren't ordered, sot he :or clause could get reordered
14:06amalloynothing wrong with nested -> in principle, if used tastefully
14:06WorldsEndlessThanks for the verification. I figured
14:09WorldsEndlessAnd if I don't provide an :or for some the :keys, and they go un-provided, I'll get an error?
14:15amalloynil
14:16justin_smith~amalloy |is| basically a repl.
14:16clojurebotAck. Ack.
14:28sdegutis~amalloy
14:28clojurebotThat's *the* amalloy to you
14:28sdegutishey *the* amalloy how's it going
14:29rhg135Is it just me, or is partial too long a name
14:29sdegutisrhg135: it's 7 chars longer than Haskell's version
14:30sdegutisAbout once a year I find myself thinking Haskell looks way super awesome, and then not caring anymore and going back to being productive in Clojure.
14:30rhg135I'm starting to think we need to reinstate the rule about haskell
14:31rhg135It'd be nice to have a shorter name, it'd delay the #() explosion
14:33rhg135It's not like having a clear name makes the meaning obvious
14:37justin_smithrhg135: I think if partial, identity, and constantly had shorter names we'd get complaints from newcomers and much cleaner code thanks to actually using those things more often
14:37justin_smithof course it's easy enough to make ones own shorter name for all of them but it's not the same is it
14:38rhg135(def P partial)
14:42rhg135There's something like that in flatland/useful
14:44justin_smithrhg135: regarding your earlier "wondering what the clojure/west talks will be out" the clojure/west account has been tweeting about the speakers https://twitter.com/Clojurewest
14:45mikerodSomeone who feels strong with compiler/jvm semantics perhaps
14:45mikerodhttps://github.com/clojure/clojure/blob/master/src/clj/clojure/core_deftype.clj#L35-L36
14:45mikerodis this guaranteed that the class dynamically generated by `gen-interface` won't get GC'ed before the `import` happens?
14:45hiredmanyes
14:45mikerodfrom what I can tell, only a SoftReference to that class exists
14:45mikerodfor a very short time
14:46mikerod(non-AOT)
14:46mikerodwe actually had a very hacky situation where we un-imported a Class that was created via definterface, and it actually got GC'ed on us before a JIT loaded namespace tried to import that class later
14:46mikerodadmittedly this is not a good or common use-case. my question is specifically these 2 lines though
14:47mikerodTo me, for these to be safe, you'd hvae to hold a local reference to the Class returned from `gen-interface` until the `import` is complete
14:47hiredmanspecifically, it is a let instead of do there to avoid the class being gc'ed
14:47mikerodhiredman: I was suspicious of that!
14:48mikerodbut I have no idea why the `let` is causing a reference to be held still
14:48mikerodI guess I need to explore that more
14:48WorldsEndlessI find myself writing something like, (topic-keywords :file file :model model ...) for a bunch of values. I seem to remember hearing, isn't there an easier way
14:48mikerodI would have expected it to need to be `(let [cl (gen-interface :name ~cname :methods ~(vec (map psig sigs)))] (import ~cname))
14:48WorldsEndless?
14:49mikerodWorldsEndless: do you mean destructruing a map?
14:49hiredmanif it was a do, it would be a top level do, so each expression within the do would be hoisted in to its own top level form
14:49mikerod(let [{:keys[file model]} my-map] <etc>)
14:49justin_smithWorldsEndless: the solution is to never write functions that take & {:keys ...} args
14:49justin_smithand just use hash-maps instead
14:49mikerodjustin_smith: good one :)
14:49mikerod(inc justin_smith)
14:49hiredmanand each toplevel form, when it is compiled, basically ends up in its own function like ((fn [] form)) for reasons
14:49mikerodhiredman: ok, fair enough on top-level forms. However, what if GC stops the world between `gen-interface` and `import`
14:50mikerodcan it not do that?
14:50mikerodmaybe that is where i don't understand well enough
14:50mikerodperhaps there is some safety in unused return value references as long as it happens on within the same call stack frame or something
14:50mikerodhappens within*
14:51mikerodI am aware that do's hoist into top-level forms though
14:51hiredmanexactly
14:51mikerodinteresting
14:51hiredmanthe let means it all happens within the same method
14:51hiredmanso you have a live reference on the method stack
14:51mikerodyes, I was thinking the return value of `gen-interface` would still have pushed that value to the stack
14:52mikerodso then I thought - maybe it is still "live" from a GC point of view
14:52mikerodI just wasn't sure of the guarantees there
14:54hiredmanif the gen-interace and the import where both top level forms, the return value of gen-interface would be thrown away, between forms, and that return value is the reference to the class
14:54mikerodyep, that makes sense
14:55mikerodI just didn't know that return values are safe to rely on when you don't have any reference to them right away. however, I guess that wouldn't make sense from a JVM-level since you have to push the reference to a local after it has been created
14:55mikerodlocal or global etc
14:57mikerod(inc hiredman)
14:58mikerodI guess that doesn't work anymore - or changed :P
14:58hiredmanit is kind of precarious
14:58justin_smithmikerod: bot is off the job
14:58mikerodI see
14:58hiredmanI would do something like (let [a (gen-interface ...)] (import ...) a)
15:00binjuredis there a way to reference a function from another ns in a way that doesn't lose docstring and stuff?
15:01binjuredlike `alias` but for a particular function, i guess
15:01hiredmanyou are confused
15:02binjuredusually
15:02hiredmanso your question doesn't make much sense
15:03hiredmanwhat are you doing and why do you think you are losing docstrings?
15:03mikerodbinjured: yeah, doc strings and that sort of information is stored on the var typically if you are thinking of like (defn my-function "my docs [x] )
15:03mikerodso you get it from the var object, not the function #'my-function
15:03mikerodspecifically (meata #'my-function)
15:03mikerodugh
15:03mikerod(meta #'my-function)
15:04binjuredjust trying to provide a public api to some functions in deeper namespaces, basically
15:04mikerodif you want to transfer that, you can, but I'd probably use something more robust for it like potemkin
15:04mikerodhttps://github.com/ztellman/potemkin#import-vars
15:04mikerodLooks like Zach Tellmen had the same thoughts as you
15:05binjuredah, cool, thanks!
15:05mikerodI do like to use import-vars for a few things. mostly when we need to hide a dependency from some ns we don't want to expose publicly
15:05hiredmangross
15:05binjuredhaha
15:05mikerodhiredman: hmm, I mean you can do it yourself. however, the idea of needing to hide some of your namespaces from the public API has value
15:05hiredmannope
15:05mikerodand if you do it yourself, you'll wind up nearly at import-vars
15:06jcornelihello, I have a question about how to override global variables
15:06jcorneliThis isn't working
15:06jcorneli(set! *print-length* 10) (defmacro print-all [body] (with-redefs [*print-length* nil] `(do ~body)))
15:06jcorneli(print-all (my-function)) will only print ten items
15:06mikerodI have a great use-case. we have a library, we have a unbounded ton of consuming code that will use this library. if we want our consumers to use some other clj lib, like schema for example, we need to hide it behind a layer in case they make any api changes.
15:07mikerodotherwise we can essentially never upgrade
15:07mikerodbecause we cannot go fix every consumer of our lib
15:07mikerodso we want very minimal dependency exposure to these other projects
15:07mikerodand they are small and do not need unlimited access to the world of all clj libs
15:07mikerodthere are times you don't want to expose namespaces
15:07hiredmanmikerod: shuffling around names in namespaces doesn't do that
15:07mikerodnot to mention, just general code organization and movement breaks everything
15:08hiredmanmikerod: there is no such thing as a private namespace
15:08rhg135That just seems like a hack around documentation
15:08mikerodit isn't private, you just expose a limited view of an api that comes from elsewhere
15:08mikerodand you call it your own name, in case they have breaking changes
15:08mikerodthen you move it out of import-vars and make a pass-through that deals with the breaking change in a non-breaking way
15:08mikerodbut you have to start off with import-vars since at first, you are the same
15:09hiredmanyou are better off starting without import-vars with your own function
15:09mikerodallows a slower roll out of changes, whlie still allowing the dependencies to be uplifted
15:09mikerodthat part I don't get
15:09mikerodit mostly transfers metadata
15:09mikerodI mean, we could write it. but it is a tiny lib, so why rewrite it?
15:09rhg135So a layer of indirection
15:10hiredmandon't transfer the metadata
15:10mikerodyou can have a var point to anotehr var
15:10mikerodthen your 2 deep in calls though
15:10mikerodI guess that's fine
15:10hiredmanif you are creating an api over another api, do the work and create it
15:11mikerodCreate schema over again?
15:11mikerodhah
15:11mikerodhonestly, I see very little weirdness in what import-vars is doing
15:11hiredmanmikerod: no, you say you are carving out some specific subset
15:11hiredmanand exposing that as a new api
15:11mikerodyes, like - everyone use schema stuff that we have exposed
15:12mikerodnothing else in case they change a name or something on us in a newer release
15:12mikerod(this has happened)
15:12mikerodand not only in schema
15:12hiredmanif that is what you are doing, you should write functions that do that (which may call schema) with their own docstrings describing the semantics of your api
15:12mikerodit is identical
15:12mikerodso we are just copy/pasting
15:12mikerodimport-vars = automate that
15:12mikerodnot to mention there is an entirely different argument here
15:12mikerodto be said for the goals of import-vars
15:13mikerodthat your api structure doesn't need to be your code organization structure
15:13mikerodI haven't really went down that path, but I think there is value in that idea
15:13hiredmanwhat you have created is just a worse form of vendoring all your deps
15:13mikerodit is like vendoring, I'd agree with that part
15:13hiredmanso vendor
15:13mikerodbut I don't see the "worst" argument
15:13mikerodwe'd rather shade it in and rename all namespaces
15:14mikerodso they don't conflict with consumers versions etc
15:14mikerodbut remapping namespaces is risky in clj I'd say
15:14hiredmanbecause you don't actually have your own copy of the code that you have control over
15:14mikerodso our consumers don't have a dep on schema at all, for example
15:14mikerodis how it works to import-vars over it
15:15mikerodso we control the version, we control introduction of breaking changes regardless of the version we pick up
15:15mikerodand if we use another lib, that also uses schema, and we need to get to the same version to be compatible between our lib and theirs, we can. while still not breaking our consumers
15:15mikerodsince our consumers don't see these breaks immediately
15:16mikerodPerhaps there are other paths to fixing it. import-vars seemed pretty straight forward.
15:17mikerodand maybe it is a specialized case in general
15:17mikerodbasically though, I was going to write similar to import-vars, then I saw it was written already and used quite a bit across other projects
15:21hiredmana lot of bad things are done in a lot of projects
15:21mikerodOk, but I still haven't been very convinced of the pitfalls of this approach.
15:22mikerodI mostly gather that you don't like it and think it is weak vendoring of some sort.
15:22mikerodSo I'm always open to good suggestions that explain the pro's and con's. I just am not hearing them.
15:22hiredmanI think what you are doing is
15:22hiredman(weak vendoring)
15:22hiredmanI don't think all uses of import-vars are
15:23mikerodI said I see 2 entirely separate camps of usage of it. (1) decoupling code organization from API organization.
15:23hiredmanin generally, they seem to be the result of poor code organization, and/or the unwillingness to tackle large refactorings
15:23mikerod(2) isolating dependencies
15:23mikerodI guess you can call it unwilling, but the reality is its consumers out of "our control"
15:24mikerodold things have to keep working until some end-of-life
15:24mikerodit is always fun and nice when you can go uplift the world whenever you want, but not always practical
15:24pullodoes anyone know why, when I 'lein deploy' to a private repository (just a folder on my local drive, different from ~/.m2), the task also creates an empty (i.e. no jar) artifact in my ~/.m2 repo?
15:25mikerodand the reality is, we like schema. our consuming projects should use schema. we can't risk being in conflict of versions between us and our consuming libs on schema.
15:25pulloI currently have to delete the empty artifact in my ~/.m2 if I want to resolve dependencies from the private repo without lein crapping out.
15:25mikerodgoing with the schema theme
15:26hiredmanmikerod: sure, if you are committed to providing a compatible api to a legacy schema version, then commit and create a namespace with the set of functions you support, with the doc strings spelling out the semantics you support, and then call out to schema
15:27mikerodhiredman: so just have to do that for like 50 vars or more
15:27mikerodjust sounds like manual work, where a machine can do it just as well
15:27hiredmanif a schema docstring says "look at website example.org for how feature X works"
15:27mikerodwhen we have an exceptional case, a wrapper, we use our own new var to do it, with its own doc string
15:27mikerodwe don't import-vars if we have changed it
15:27hiredmanand a consume bookmarks that website and uses it as their reference
15:27mikerodthat wouldn't make snese
15:28mikerodOk, that is a good point on how a doc string could become misleading
15:28mikerodif it was specific to that version, then they don't realize other vars they are using are different
15:28hiredmanwhat happens when you use whatever editors "view source" on your facade?
15:28mikerodalthough they are different namespace, so you really can't just assume they aren't different
15:29mikerodwith import-vars, looks to jump to the original source
15:29mikerodI understand that your cross reference can become weird from doc strings
15:29mikerodthat is a good point on where it has a pitfall
15:30mikerod"this function uses function-name-x"
15:30mikerodhowever, we don't expose function-name-x because it was a breaking change, so we still have function-name-y instead
15:30mikerodso you'd hvae to look at function-name-y's doc string, which would say "this is a pass through to function-name-x but left for compatibility with previous versions of lib X"
15:30mikerodbut still, yes I could see some confusion
15:32hiredmanunless you are truely vendoring (copying and renaming namespaces) your consumers (and any of their dependneices) could replace the version of schema on the classpath at any time
15:36jcorneliI'm still stuck with rebinding *print-length* in a macro
15:36jcornelithe latest non-working version I've come up with is:
15:36jcorneli(defmacro print-all [& body] `(do (binding [*print-length* nil] (do ~@body))))
15:36justin_smithjcorneli: what is the outer do for?
15:36justin_smithor the inner one, even
15:36pullo~'*print-length*
15:36clojurebotI don't understand.
15:37hiredmanjonathanj: there is no call to print anything in there, why would binding print length do anything?
15:37mikerodhiredman: yes they can, and that would break things. it isn't consumers of arbitrary libraries int hat sense
15:37mikerodso yes, specialized
15:37jcornelithe call to print is in the body
15:37jcornelior in the ~@body, rather
15:37rhg135justin_smith: her tweet about the talk didn't even mention that job. I think you are safe :P
15:37justin_smithrhg135: it's just jokes, yes
15:38hiredmanjcorneli: what does it look like?
15:39jcorneliThe inner function is meant to be "any code"...
15:39jcorneliit could be '(1 2 3 4 5 6 7 8 9 10 11)
15:40hiredmanjonathanj: (def f (print-all (fn [] (prn (range 20))))
15:40hiredmanthen (f)
15:40hiredmanjcorneli: there is no call to println in that quoted list
15:40jcorneliBut *print-length* tells how many items to print from a list
15:41jcorneliGiven (set! *print-length* 10), then (print-all '(1 2 3 4 5 6 7 8 9 10 11)) returns (1 2 3 4 5 6 7 8 9 10 ...)
15:41jcornelior rather, that's what it prints to the REPL
15:41hiredmanjcorneli: yeah, but unless a call to print is in the dynamic extent of the body of the binding the binding doesn't exists
15:42hiredmanjcorneli: the repl prints results after they have been evaluated, not inside some arbitrary scope in the evaluation
15:42jcorneliok, think I see what's going on
15:43hiredmanthink of each expression you type in to a repl as a function body, that is called, and then the repl prints the result
15:43jcorneliIt's interesting because (defn save-local [] (binding [*print-length* nil] (spit "data.clj" (prn-str @node-store)))) works as expected
15:43jcorneliBut that's not printing to the REPL but rather to a file
15:43hiredmannothing "prints to the REPL"
15:43jcorneliWell, CIDER does :-)
15:43hiredmanthe repl evaluates an expression, then prints the result
15:44justin_smithjcorneli: you aren't relying on the implicit print behavior there, the implicit print of the repl happens outside any of your dynamic scope
15:44hiredmanthe repl is driving the printing
15:44jcorneliyes, this is dawning on me now
15:44justin_smithunless you started said repl inside your dynamic scope
15:45jcorneliThanks for the help guys
15:50amalloyhiredman: i would say that (print 5) is "printing to the repl", because it's printing to a *out* which is configured to go straight to the repl
15:51hiredmansemantics
15:52hiredman"printing to the same output stream as the repl"
15:54hiredmanif you embed some kind of repl in your app a common thing is you end up wanting to limit the printing, and that can often start out as creating a custom evaluator that sets the bindings, which is of course terrible, you should create a custom printer that sets them
15:54hiredmansorry, not a custom evaluator
15:54hiredmanwrapping the whole repl in the bindings
16:16sdegutisWhat's that function again that lets you count the numbers of things in a collection, assuming there are duplicates?
16:16sdegutisIt's some obscure word that I almost remember but can't quite.
16:17sdegutisoccurrences?
16:17TEttingerdistinct
16:17sdegutisTEttinger: That just removes duplicates without counting them.
16:17TEttingermaybe
16:17sdegutisTEttinger: The function I'm thinking of counts them. It's kind of like group-by in that sense.
16:17sdegutisHmm let me look for that Clojure cheat sheet, maybe that has it.
16:18sdegutisfrequencies!
16:18sdegutisPhew. Thanks TEttinger.
16:19TEttingerohhh
16:20TEttingeryeah I was about to suggest frequencies, it didn't sound like what you wanted
16:20TEttingerI thought you meant #(count (distinct %))
16:20jcornelijustin_smith hiredman: I believe I've found a simpler solution that actually works: (defn print-all [body] (let [result (do body)] (binding [*print-length* nil] (print result))))
16:20jcornelithanks again for the guidance
16:21hiredmanthat is nonsense
16:22hiredmanit is trivially made simpler and better
16:23hiredman(let [x y] x) is just x
16:26justin_smith*(let [x (do y)] x)
16:28sdegutishiredman: you mean y right?
16:38sdegutis,(let [y 2] (= y (let [x y] x)))
16:38clojurebottrue
16:38sdegutisAnyway, programming is hard.
16:38justin_smithsdegutis: you left out the do
16:38sdegutisjustin_smith: Correct.
16:39justin_smith,(do 'b (do 'b (do))) ; sinatra
16:39sdegutisMy original CSS stuff was very incorrect, I'm trying to rewrite it to be correct, and it's a *very* recursive problem to solve. So I'm struggling to think recursively right now to try to figure that out.
16:39clojurebotnil
16:39sdegutisjustin_smith: hahaha hhaha
16:39justin_smithsdegutis: I am afraid of CSS
16:40sdegutisjustin_smith: CSS itself isn't great, but what I'm struggling with isn't inherent to CSS itself. It's just a transformation of one Clojure structure into another.
16:41sdegutisThe input can either be a string, a hash-map, or a list containing any of these three things. The output needs to be a re-structured version of it that's not too dissimilar.
16:41sdegutisSo my natural idea was to create a recursive function that does a cond, with list? string? and hash-map? as its only three conditions.
16:42sdegutisBut that's where I'm stuck. When it encounters a string, it needs to "add" that to some kind of list, via a return value, which presumably appends to a collection obtained via a parameter one level up.
16:43sdegutisArghh, recursion is hard.
16:44sdegutisWhy after a decade of professional programming is recursion still so hard?
16:46amalloyunderstanding recursion is only hard because you haven't yet understood the rest of recursion
16:47pbxhttp://www.badum-tish.com/
16:48justin_smithamalloy: the hardest part is figuring out when you can escape learning recursion.
16:51lockdownsdegutis: because you didn't do "The Little Schemer"
16:51sdegutisamalloy: whoa
16:51sdegutisjustin_smith: oh man
16:51sdegutisthis is too intense
16:56rcassidywhat step of the design recipe are you on? /s
16:58rcassidy(but seriously, it helps with recursion)
17:06bendlasHi people, any news on the missing latest source packages?
17:06bendlasGET https://commondatastorage.googleapis.com/chromium-browser-official/chromium-48.0.2564.109.tar.xz 404s
17:07justin_smithbendlas: are you looking for google closure?
17:07bendlasjustin_smith: ooh sorry
17:20TimMcrcassidy: was gonna say it but didn't :-)
17:25xemdetiawhy are we writing faces
17:25xemdetiasorry my brain is broken please ignore
17:30justin_smithxemdetia: ¯\_(ツ)_/¯
17:45xemdetiajustin_smith, I have that as a macro in st
17:45xemdetiafor emergencies
18:14cortexmanwhat's the right / easy way to read an edn file off disk
18:15justin_smithcortexman: do you want the string or the clojure data?
18:16justin_smithfor just string, slurp, for clojure data (read-string (slurp f))
18:16justin_smithif you don't trust the file (maybe it came from uncertain source) use clojure.edn/read-string
18:23amalloyif you do trust the file, use clojure.end/read-string anyway
18:27justin_smithyeah, I guess edn/read-string is the better one to use all around now
18:28rhg135for edn? yeah always
18:29rhg135it's kinda like reading json with eval. it technically works but eventually it'll mess you up
18:45sdegutisIs there some simple way to copy a string to an output stream that I'm missing?
18:46justin_smithsdegutis: into an existing stream or create a new one based on that string?
18:46sdegutisInto an existing output stream.
18:46justin_smithand .getBytes isn't doing it?
18:46sdegutisThe only thing I can think of is to convert the string into a UTF-8 thing using .getBytes
18:47rhg135,(do (require 'clojure.java.io) (doc clojure.java.io/copy))
18:47clojurebot"([input output & opts]); Copies input to output. Returns nil or throws IOException. Input may be an InputStream, Reader, File, byte[], or String. Output may be an OutputStream, Writer, or File. Options are key/value pairs and may be one of :buffer-size buffer size to use, default is 1024. :encoding encoding to use if converting between byte and char streams. Does not close any streams except thos...
18:48sdegutisrhg135: when copy receives a string, it assumes it's a filename or URL.
18:48sdegutisrhg135: I'd need to convert a string into an input stream or something first to use it with copy.
18:48rhg135StringReader yo
18:48sdegutisWhich isn't a half-bad idea I guess.
18:48justin_smithor just getBytes
18:48rhg135or that
18:49sdegutisHeck yeah I just created a zip file in Clojure.
20:02jack_rabbitI'm reading core.async docs. If I use >!! or <!! in a go block, what happens?
20:03jack_rabbitI assume it blocks the thread executing the block rather than yielding?
20:04amalloyjustin_smith: getBytes :(
20:05amalloyit's fine if you need bytes, but converting from characters to bytes in order to process a string should be a sin
20:25sdegutisHow do you write an InputStream to a file?
20:25sdegutisI tried (spit "filename" istream) but no luck.
20:27rhg135io/copy
20:28rhg135(io/copy in (FileWriter. name))
20:28rhg135io/copy is the answer. always.
20:34sdegutisThanks rhg135.
20:35rhg135np
20:36rhg135I wish something like it existed for node/cljs
20:36rhg135but I'm not masochist enough to write it myself
20:38sdegutisThis is so strange.
20:39sdegutisI'm copying from a non-empty byte-array to a file, and it's turning out an empty 0-byte file.
20:39sdegutisI'm baffled.
20:57sdegutisOkay whatever it works now good enough.
20:58amalloyyou're probably not closing the writer
21:06rhg135maybe I'll write it for nashorn/cljs where it's basically a sed
21:08justin_smithamalloy: but outputstreams use bytes not strings
21:17amalloyi mean, when you have characters and you're writing to a byte-oriented stream, you need to at least consider encoding. just slapping utf-8 on it is not a solution
21:18amalloyyou need to make sure whatever's on the other end is prepared to receive your string as utf-8, or else when you get a user in asia your io code will just break
21:21noncomhi!
21:22noncomcan somebody advice a way to organize a file download in compojure?
21:22noncomor give a link to an example..
21:22noncomi can't find a working example of this
21:22noncomi have a byte array for the file
21:39rhg135if we all just used utf-8 we wouldn't have that problem, but we'd have the problem of noobs in weakly typed languages using bytes as mutable strings
21:41noncomi have found a solution
21:42noncomrhg135: huh? it's the first time i hear of that
21:43rhg135I saw it all the time in python2
21:43rhg135it had no byte type
21:44rhg135it was nightmare fuel
21:44noncomomg
21:44justin_smithmulti-byte-character? what's that? who ever heard of such a thing?
21:45wmealingnobody ever.
21:45wmealingall those chinese people.. they never heard of it
21:45rhg135it's funny how much they protested at python3's sanity
21:45wmealingif you dont do foreign languages, its pretty easy to miss
21:45wmealingie, not see the need for
21:45justin_smithwmealing: I mean, for a multi byte character to be needed, that would require more than 256 symbols
21:46justin_smithand I mean there's gotta be less than 100 symbols, total
21:46rhg135"we don't need no bytes! it's too hard!"
21:46wmealingjustin_smith: :)
21:46rhg135"now we have to be explicit"
23:19nikki93do people like "clojure in action" 2nd ed?
23:39skjljskhttps://github.com/adzerk-oss/boot-test boot test break if there is a custom source file with build tasks?
23:39skjljskclojure.lang.Compiler$CompilerException: java.io.FileNotFoundException: Could not locate boot/core__init.class or boot/core.clj on classpath., compiling:(build/tasks.clj:1:1)
23:43skjljskanyone else faced this?