#clojure log - Apr 14 2016

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

0:28 zv: I've read a bit about clojure -> android and I understand it's limitations, but I've never heard anyone express an opinion on the *future* of such an enterprise.

0:29 Could clojure apps on android achieve parity in any sensible future universe?

0:35 TEttinger: zv, I think so, but via clojurescript in particular. in one benchmark on early Android phones people found V8 (Chrome's JS engine also used on Android) was outperforming Dalvik quite abit

0:36 scottj: zv: parity with java apps in startup time?

0:36 zv: idk details, but I think there are some areas dalvik wasn't very optimized for aspects of clojure, perhaps the Android N switch to openjdk might help a tiny bit

0:37 s/tiny bit/somewhat

0:38 zv: btw you've seen Skummet right?

0:38 zv: I have

3:17 pythys: Hello everyone. Complete noob here with some basic questions. Thank you in advance for your help.

3:17 Given the lack of domain objects in a functional language, how do you model the domain in clojure? or do you just access the database?

3:23 ben_vulpes: pythys: what do you mean "lack of domain objects"?

3:24 there are various OOP-sy things in clojure like records and protocols

3:24 one can also model "the domain" if i understand you correctly with simple, named data structures.

3:24 there's also stuff like plumatic/schema for stronger typing.

3:25 egli``: pythys: the book clojure applied deals with exact this issue

3:25 pythys: ben_vulpes: Ahh, so you replace objects with data structures

3:25 egli``: https://pragprog.com/book/vmclojeco/clojure-applied

3:25 I can highly recommend it. Maybe not a total beginner book though

3:26 ben_vulpes: pythys: in the immortal words of swizz beats

3:26 "i got a million ways to get it"

3:26 "choose one"

3:26 pythys: ben_vulpes: yeah, I'm overwhelmed by choice

3:26 that's why I'm trying to make sense of things in here

3:26 ben_vulpes: glhf

3:27 i typically start with functions that take args and abstract lazily

3:27 plumatic's schema can be nice in that it provides types for "well it's a string but it's a specific /kind/ of string"

3:27 pythys: I see

3:28 and for complex domains, you just make data structures with data structures inside them

3:28 but then how do people make sense of your domain? How do you communicate the design?

3:29 For example, If I have a complex object with a builder inside of it, then everyone understands it

3:29 ben_vulpes: no, no they don't.

3:29 pythys: but If I declare a map, with some vectors and other maps inside, wouldn't that be confusing?

3:29 oh, sorry, please elaborate

3:29 ben_vulpes: oop people labor under the delusion that the abstractions are inherently more understandable

3:30 fundamentally, it's a communication problem that doesn't get solved with code.

3:30 pythys: ben_vulpes: I see, so it's raw data structures all the way?

3:30 * ben_vulpes shrugs

3:30 ben_vulpes: it's clear code and well-chosen abstractions all the way.

3:30 no one right solution or design methodology.

3:30 life is ambiguous and hard like that.

3:31 TEttinger: yeah, clojure has some really really good tools for working with data

3:31 ben_vulpes: i get rather a lot of mileage out of simple functions that do one thing, with well-named arguments.

3:31 pythys: ben_vulpes: ok. So do you communicate the design through the names of the data structures? do you document? how do you convey what is it that your domain is about?

3:32 ben_vulpes: tests are nearly imperative, given the paucity of compile-time enforcement.

3:32 pythys: excuse me for the noob questions, but I come from a domain driven design frame of mind, trying to shift

3:32 ben_vulpes: pyths for example

3:32 (defn create-ddb-table [client-id] ... )

3:32 creates a dynamo db table

3:32 and takes a client id

3:32 TEttinger: stuff like destructuring is much more handy than it seems on the surface, especially when the code is open source and people are expecting to read it

3:33 (or open within an organization)

3:33 ben_vulpes: yeah destructuring is neat as well, complemented with, say schema.

3:33 * ben_vulpes just discovered schema, is loving it

3:33 * ben_vulpes will hate it in three months for some personal reason, no doubt

3:35 TEttinger: ,(def complex-data ["this is a vector" "the next element can be something other than a string" 10 "then some nesting" [1 2 3]]) ; destructuring this in the next line

3:35 clojurebot: #'sandbox/complex-data

3:36 ben_vulpes: pythys: i don't really have any experience with "domain driven design", so i might not understand your background well enough to answer your questions.

3:37 pythys: I see, so naming sub-structures through destructuring would achieve a sort of design by naming conventions I think

3:37 TEttinger: ,(let [[_ not-concerned num-we-like nah [x y z]] complex-data] (* num-we-like (+ x y z)))

3:37 clojurebot: 60

3:37 TEttinger: yeah, even though there were no names inthe complex-data vector...

3:37 it isn't hard to provide context where it's used

3:37 pythys: ben_vulpes: that's just a fancy word for designing the domain through a class structure (you know .. Person, Employee, Account, Order etc ...)

3:38 ben_vulpes: pythys: https://github.com/plumatic/schema << the schema i keep nattering around

3:38 TEttinger: maps have names that typically matter more

3:39 ben_vulpes: pythys: also dig http://clojure.org/reference/datatypes

3:40 and here are your class methods, if i might be so rude as to call them that: http://clojure.org/reference/protocols

3:40 if you squint it kinda looks like clos

3:40 TEttinger: heh, protocols aren't super commonly necessary, but I think they can be handy in the same cases where domain driven design would be useful

3:40 ben_vulpes: without the dooooope dispatch system

3:41 TEttinger: yeah, CLOS is kinda crazy

3:41 in a good way,mostly

3:41 ben_vulpes: dude clos broke me of ever wanting to work with modern OOP ever again

3:41 TEttinger: I've struggled to wrap my head around some code using it

3:42 ben_vulpes: the "HOLY SHIT THIS IS SO RIGHT" moments i had...

3:42 pythys: okay, this is starting to make sense. Clojure has a sort of much more loose type system

3:42 ben_vulpes: heh

3:42 loose

3:42 TEttinger: yeah, most lisps are pretty much non-typed; clojure has type hints but they're really just suggestions for the compiler, not enforcements

3:43 ben_vulpes: TEttinger: i found cl with the sbcl compiler to be exquisitely well typed

3:44 in that if i bothered to provide type declarations as to what my functions accepted and what they returned (from their various return points, yes it handled that), it would go so far as to refuse to load code that had incorrect funcalls in it.

3:44 but no, no Hindley Milner as far as i could tell.

3:45 TEttinger: like in clojure you could type hint an argument to an fn as being a String, and give it a number, and it will compile but maybe act in a way you didn't expect from a String (it could throw an exception if you call .charAt on it). Typed Clojure and I believe Schema both provide validation for arguments I think

3:45 in different ways, I haven't used either

3:45 ben_vulpes: at one particularly memorable moment, i declared that a function would only ever receive a string and was politely informed that the web server would be calling it with a null value and i should provide for that.

3:45 TEttinger: nice

3:45 ben_vulpes: glorious

3:45 TEttinger: isn't SBCL's compiler also rather slow (I suppose like lein could be)

3:45 * ben_vulpes shrugs

3:46 ben_vulpes: i dont really write performance-oriented code, or big cl projects

3:46 pythys: Thank you everyone for the reference links and tips. Much appreciated

3:46 ben_vulpes: and i can asdf:load-project fast enough that it's not a concern on the things i've built

3:46 later, pythys

3:46 TEttinger: I do recall a Standard ML compiler that took 10 minutes to compile hello world. whole program optimization

3:47 ben_vulpes: myeah

3:47 optimization's not my bag

3:47 augmenting my intelligence, though...

3:47 TEttinger: it was a pretty odd thing for it to do

3:47 ben_vulpes: i have occupied so many cycles the past two weeks manually ensuring that my java-in-clojure was written correctly because the clojure compiler doesn't, and i don't care to wait for runtime explosions.

3:48 just because i *can* do this does not mean that i think it a good use of my mind.

3:48 gimme squigglies, yo.

3:49 TEttinger: is ~ used in CLOS? I can't really remember

3:49 ben_vulpes: haha no, i mean under the text in my editor

3:50 TEttinger: I mean I see a ~ now and the first thing I think is "oh, unary bitwise negation operator". the second thing I think is "man, using ~~ to coerce to number in JS is silly"

3:50 ben_vulpes: no no no

3:50 mistakes in code that the compiler can catch and relay to the editor for displaying to my dumb self

3:50 TEttinger: heh yes

3:51 ben_vulpes: bleee unary bitwise negation operator

3:51 TEttinger: ,(bit-not -2)

3:51 clojurebot: 1

3:54 ben_vulpes: ,(defn lol [da-str] (format "z%s"))

3:54 clojurebot: #'sandbox/lol

3:54 ben_vulpes: like come onnnnnnnn

3:54 (lol "hi")

3:54 ,(lol "hi")

3:54 clojurebot: #error {\n :cause "Format specifier 's'"\n :via\n [{:type java.util.MissingFormatArgumentException\n :message "Format specifier 's'"\n :at [java.util.Formatter format "Formatter.java" 2487]}]\n :trace\n [[java.util.Formatter format "Formatter.java" 2487]\n [java.util.Formatter format "Formatter.java" 2423]\n [java.lang.String format "String.java" 2790]\n [clojure.core$format invokeStatic "c...

3:54 ben_vulpes: anyways.

3:55 fwiw clojure's a better tool for most jobs that come my way than anything else.

3:55 "a gun to fire today"

3:55 "the army we have today"

3:55 or what was it

3:55 TEttinger: ,(defn lol [da-str] (format "z%s" da-str))

3:55 clojurebot: #'sandbox/lol

3:55 TEttinger: ,(lol "yay")

3:55 clojurebot: "zyay"

3:55 ben_vulpes: no i know!

3:56 TEttinger: was it the compile error thing?

3:56 ben_vulpes: runtime error

3:56 TEttinger: ah ok

3:56 I mean you wanted a compile error

3:56 ben_vulpes: mhm.

3:57 now i have to go trash a bunch of aws resources by hand.

3:58 which is fine, i wrote this thing. but imagine the hurt the poor sod i'm going to foist this codebase will be in for when this nearly-purely-side-effecting-codebase needs tweaking on.

3:59 * ben_vulpes off to work through the rest of these runtime errors

4:19 ben_vulpes: whaddaya know, there were only three!

4:19 one of which was apparently a race condition in the consumed api.

4:55 jonathanj: Is it possible to change where the .m2 cache directory is created and searched?

4:55 In particular when running lein tasks.

5:11 wink: you could always just symlink it before running

5:12 Russell-: I just tried running 'lein check' for the first time, and got a bunch of reflection warnings about calls to Java methods like substring. What am I doing wrong?

7:43 asdf12z_: the parens have me tripping balls in clojure heh

8:06 ben_vulpes: turned on rainbow-delimeters-mode, did we?

9:59 someone1: hi

10:00 is there a ring channel?

10:11 ben_vulpes: you're in it

10:14 rcassidy: asdf12z_: rainbow parens plugin for your editor :)

10:23 someone1: does jvm class updating work with clojure?

10:34 russellw: Is there a built-in function or idiom for 'save this value for a moment, do something else, then return the saved value'? It can be done with let, of course, just wondering whether there's some shorter idiom

10:37 hyPiRion: russellw: Closest I know about is doto, don't think there's anything equivalent to common lisp's prog1

10:38 russellw: hyPiRion, doto looks interesting anyway, thanks

11:02 Is there a way to write a literal symbol with a non-standard name, e.g. the equivalent of |0| in other dialects of Lisp? Or do you just have to write (symbol "0")?

11:23 rplaca: russellw: I've missed prog1 too. It's a trivial macro to write, but I usually just go with (let [foo first-expr] other-exprs... foo)

11:23 russellw: rplaca, fair enough

11:47 justin_smith: yay, clojure/west

11:48 :b2

11:52 russellw: we don't tend to use them, but I think (symbol "0") is the best you can do

11:55 dorian: i need an idiot check: foo and (not (nil? foo)) are identical semantics yes?

11:55 er at least in the context of a predicate test

11:56 eg (when foo (...))

11:59 ToxicFrog: ,(let [foo nil] (if foo "truthy" "falsy"))

11:59 clojurebot: "falsy"

11:59 ToxicFrog: ,(let [foo false] (if foo "truthy" "falsy"))

11:59 clojurebot: "falsy"

12:00 ToxicFrog: ,(let [foo false] (if (not (nil? foo)) "truthy" "falsy"))

12:00 clojurebot: "truthy"

12:00 ToxicFrog: dorian: not identical; see above

12:00 In particular, false is boolean-false but is not nil?

12:01 dorian: ah right i guess i was thinking in the context of things that return either some data object or nil

12:01 but yeah good point

12:16 rplaca: on my way from SF - see everyone at Clojure/West!

12:27 russellw: justin_smith, okay, thanks

12:31 dorian: by chance is the author of pantomime in here?

12:41 sdegutis: Good day.

12:41 ,(symbol "0")

12:41 clojurebot: 0

12:42 Glenjamin: ,'0

12:42 clojurebot: 0

12:42 Glenjamin: ,(type '0)

12:42 clojurebot: java.lang.Long

12:43 sdegutis: Hello.

12:43 ,(type (symbol "0"))

12:43 clojurebot: clojure.lang.Symbol

12:43 sdegutis: Where can you buy real life Jedi clothing, which are comfortable, and will not wear down quickly like a costume?

12:45 russellw: I'm still trying to make sense of the output of 'lein check' - it's mostly reflection warnings about how it can't resolve method calls, even static methods on java.lang.Character - that's always available at compile time, right? And I've tried putting in require's for things like java.io and it makes no difference.

12:45 I'm kind of at a loss for things to try - what does everyone else do? Just not use 'lein check' or is there a trick I'm missing?

12:46 sdegutis: russellw: I just use cider and enable the reflection warning global var in project.clj and that's sufficient for me.

12:46 russellw: this way, whenever I do something that reflects poorly, cider highlights it in yellow for me when I eval it

12:47 I mean when I eval/define the function it's in.

12:47 Works 100% great so far.

12:47 Glenjamin: russellw: when doing java interop clojure has to use reflection to evaluate unless you add type hints

12:47 sdegutis: Yeah then I just add ^String or whatever.

12:47 russellw: Glenjamin, type hints! That sounds like the thing I'm missing

12:47 I imagine that should improve performance?

12:47 Glenjamin: yeah, reflection is slow

12:48 ,(let [a "123"] (pr (.isEmpty a))) ; should emit a warning

12:48 clojurebot: false

12:48 sdegutis: yeah use cider

12:48 russellw: ah, I see the syntax now

12:49 I should probably try timing tests before and after to see if it did improve performance

12:49 Glenjamin: you can also set *warn-on-reflection* to true in the leiningen project

12:50 russellw: What will that do, the equivalent of lein check when I type lein run?

12:50 Glenjamin: yeah

12:50 russellw: Makes sense, thanks

12:52 The documentation gives the type hint syntax for function names and local variables, how do you specify type hints for global variables?

12:57 ak5: hi, I have been using ring recently and it seems sooo much saner than the stuff I am used to. I am new to jvm based stacks for the web though - can someone link me to the definite resource for hosting stuff? I usually run some scripting language behind nginx... thanks!

12:58 russellw: Oh, seems to be the same, just put the type before the name

13:05 mgaare_: ak5: there's not a definitive guide per se, however the convention is to have the app run its own web server that binds on an internal-facing interface, and use nginx/apache/some other dedicated web server as a reverse proxy

13:06 mgaare: ak5: good options for the app web server include jetty, httpkit, immutant

13:11 sdegutis: I use jetty because it's included by "ring/ring"

13:24 russellw: Okay, I've cleared most of the reflection warnings. One I'm still puzzled by is http://pastebin.com/ZjYKTXpM line 2, the call to getProperty - anyone know what type hint would clear that one?

13:40 {blake}: Is there a split-with that works as a comlpement to filter/remove? (As opposed to "take-while"/"drop-while"?)

13:43 amalloy: split-at

13:44 tolstoy: Oh, cool. If you just "extend-protocol" your records, instead of having them directly implement a protocol, you can change implementation functions, send them to the repl, and they change without having to reload all the code.

13:44 amalloy: er

13:44 {blake}: wut?

13:44 amalloy: i guess i don't understand. split-with is the answer to your question

13:44 but you used split-with as part of your question

13:44 {blake}: heh

13:45 amalloy: no, i'm just bleary in the morning i think

13:45 {blake}: ,(split-with (fn[[k v]] (#{\a \b \c \d} (first k))) {"apple" 1 "banana" 2 "eggplant" 3 "grape" 4})

13:45 amalloy: there isn't. it's just (juxt filter remove)

13:45 clojurebot: [(["apple" 1] ["banana" 2]) (["eggplant" 3] ["grape" 4])]

13:45 {blake}: oh, juxt will do...once again had forgotten it.

13:45 tx

14:01 rasmusto: I'm a common lisp newbie, how do I use destructuring-bind so it takes care of nested lists like clojure's vector destructuring? (or should I direct this at a different channel?)

14:05 oh maybe its the same, nvm :p

14:13 amashi: Three used to be a pretty active cl irc channel- been quite a while since I have lurked there, so I don;t know how healthy it is these days. But between http://www.gigamonkeys.com/book/beyond-lists-other-uses-for-cons-cells.html (scroll to the bottom) http://asymmetrical-view.com/2008/09/18/destructuring-bind.html and http://clhs.lisp.se/Body/03_de.htm it should be pretty much covered.

14:18 rasmusto: amashi: sweet, thanks. I was going in circles on the clhs.lisp.se docs and not finding anything :P

14:18 there's like one trivial example on the actual destructuring-bind page

15:10 hyperhopper: I'm calling a function that takes 2 arguments

15:10 and passing 2 arguments

15:10 but getting an ArityException for only passing one argument

15:11 here is the call: (histogram-distance h (histogram "./input/coast_test2.jpg"))

15:11 what could I be doing wrong?

15:11 Also happens with (histogram-distance h h)

15:12 ridcully: are you recuring etc on itself with wrong arity?

15:13 could you share the code and the error on some copy-and-paste-site?

15:19 hyperhopper: sure

15:19 and no im not doing recursion

15:20 {blake}: hyperhopper: Is the error for histogram, and nto histogram-distance?

15:20 er, not

15:20 amalloy: we'll find out once we have a stacktrace

15:20 hyperhopper: The error is for histogram-distance

15:20 one sec lemme upload it

15:21 The code

15:21 http://pastebin.com/jLW4RjQa

15:23 classifier.core=> (histogram-distance h h) ArityException Wrong number of args (1) passed to: core/histogram-distance/fn--485 clojure.lang.AFn.throwArity (AFn.java:429 )

15:23 amalloy: i bet either line 32 or line 33 returns an empty seq

15:23 hyperhopper: It doesnt

15:23 I can create histograms fine

15:23 amalloy: nm

15:23 your lambda in (defn histogram-distance gets too few args

15:27 hyperhopper: oh you're right, thanks!

15:28 whats would be the cleanest way to do what I'm trying to do in clojure?

15:28 I zip and map

15:28 but If I zip and map like that then I have to deconstruct the zipped list

15:30 ridcully: can't you just put that anon fn instead the list and get rid of the outer map?

15:36 hyperhopper: ridcully: probably but I dont understand how clojure map works with more than 2 arguments yet

15:36 This is like the first time using clojure

15:36 ridcully: ,(map vector (range 3) (range))

15:37 clojurebot: ([0 0] [1 1] [2 2])

15:41 hyperhopper: thats super convenient

16:15 In what case could (min-key) return the entire array passed to it?

16:16 I'm manually verifying that the function returns ints for the values in the array

16:19 hiredman: read the docs for min-key

16:19 ,(doc min-key)

16:19 clojurebot: "([k x] [k x y] [k x y & more]); Returns the x for which (k x), a number, is least."

16:24 hyperhopper: My mistake I was passing a list

16:24 is apply extremely common in clojure? I seem to be using it a lot. Is this bad style?

16:26 arcatan: it is quite common

Logging service provided by n01se.net