2016-04-14
| 00: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. |
| 00:29 | zv | Could clojure apps on android achieve parity in any sensible future universe? |
| 00: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 |
| 00:36 | scottj | zv: parity with java apps in startup time? |
| 00:36 | scottj | 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 |
| 00:37 | scottj | s/tiny bit/somewhat |
| 00:38 | scottj | zv: btw you've seen Skummet right? |
| 00:38 | zv | I have |
| 03:17 | pythys | Hello everyone. Complete noob here with some basic questions. Thank you in advance for your help. |
| 03:17 | pythys | 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? |
| 03:23 | ben_vulpes | pythys: what do you mean "lack of domain objects"? |
| 03:24 | ben_vulpes | there are various OOP-sy things in clojure like records and protocols |
| 03:24 | ben_vulpes | one can also model "the domain" if i understand you correctly with simple, named data structures. |
| 03:24 | ben_vulpes | there's also stuff like plumatic/schema for stronger typing. |
| 03:25 | egli`` | pythys: the book clojure applied deals with exact this issue |
| 03:25 | pythys | ben_vulpes: Ahh, so you replace objects with data structures |
| 03:25 | egli`` | https://pragprog.com/book/vmclojeco/clojure-applied |
| 03:25 | egli`` | I can highly recommend it. Maybe not a total beginner book though |
| 03:26 | ben_vulpes | pythys: in the immortal words of swizz beats |
| 03:26 | ben_vulpes | "i got a million ways to get it" |
| 03:26 | ben_vulpes | "choose one" |
| 03:26 | pythys | ben_vulpes: yeah, I'm overwhelmed by choice |
| 03:26 | pythys | that's why I'm trying to make sense of things in here |
| 03:26 | ben_vulpes | glhf |
| 03:27 | ben_vulpes | i typically start with functions that take args and abstract lazily |
| 03:27 | ben_vulpes | 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" |
| 03:27 | pythys | I see |
| 03:28 | pythys | and for complex domains, you just make data structures with data structures inside them |
| 03:28 | pythys | but then how do people make sense of your domain? How do you communicate the design? |
| 03:29 | pythys | For example, If I have a complex object with a builder inside of it, then everyone understands it |
| 03:29 | ben_vulpes | no, no they don't. |
| 03:29 | pythys | but If I declare a map, with some vectors and other maps inside, wouldn't that be confusing? |
| 03:29 | pythys | oh, sorry, please elaborate |
| 03:29 | ben_vulpes | oop people labor under the delusion that the abstractions are inherently more understandable |
| 03:30 | ben_vulpes | fundamentally, it's a communication problem that doesn't get solved with code. |
| 03:30 | pythys | ben_vulpes: I see, so it's raw data structures all the way? |
| 03:30 | ben_vulpes | it's clear code and well-chosen abstractions all the way. |
| 03:30 | ben_vulpes | no one right solution or design methodology. |
| 03:30 | ben_vulpes | life is ambiguous and hard like that. |
| 03:31 | TEttinger | yeah, clojure has some really really good tools for working with data |
| 03:31 | ben_vulpes | i get rather a lot of mileage out of simple functions that do one thing, with well-named arguments. |
| 03: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? |
| 03:32 | ben_vulpes | tests are nearly imperative, given the paucity of compile-time enforcement. |
| 03:32 | pythys | excuse me for the noob questions, but I come from a domain driven design frame of mind, trying to shift |
| 03:32 | ben_vulpes | pyths for example |
| 03:32 | ben_vulpes | (defn create-ddb-table [client-id] ... ) |
| 03:32 | ben_vulpes | creates a dynamo db table |
| 03:32 | ben_vulpes | and takes a client id |
| 03: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 |
| 03:33 | TEttinger | (or open within an organization) |
| 03:33 | ben_vulpes | yeah destructuring is neat as well, complemented with, say schema. |
| 03: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 |
| 03:35 | clojurebot | #'sandbox/complex-data |
| 03: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. |
| 03:37 | pythys | I see, so naming sub-structures through destructuring would achieve a sort of design by naming conventions I think |
| 03:37 | TEttinger | ,(let [[_ not-concerned num-we-like nah [x y z]] complex-data] (* num-we-like (+ x y z))) |
| 03:37 | clojurebot | 60 |
| 03:37 | TEttinger | yeah, even though there were no names inthe complex-data vector... |
| 03:37 | TEttinger | it isn't hard to provide context where it's used |
| 03: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 ...) |
| 03:38 | ben_vulpes | pythys: https://github.com/plumatic/schema << the schema i keep nattering around |
| 03:38 | TEttinger | maps have names that typically matter more |
| 03:39 | ben_vulpes | pythys: also dig http://clojure.org/reference/datatypes |
| 03:40 | ben_vulpes | and here are your class methods, if i might be so rude as to call them that: http://clojure.org/reference/protocols |
| 03:40 | ben_vulpes | if you squint it kinda looks like clos |
| 03: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 |
| 03:40 | ben_vulpes | without the dooooope dispatch system |
| 03:41 | TEttinger | yeah, CLOS is kinda crazy |
| 03:41 | TEttinger | in a good way,mostly |
| 03:41 | ben_vulpes | dude clos broke me of ever wanting to work with modern OOP ever again |
| 03:41 | TEttinger | I've struggled to wrap my head around some code using it |
| 03:42 | ben_vulpes | the "HOLY SHIT THIS IS SO RIGHT" moments i had... |
| 03:42 | pythys | okay, this is starting to make sense. Clojure has a sort of much more loose type system |
| 03:42 | ben_vulpes | heh |
| 03:42 | ben_vulpes | loose |
| 03: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 |
| 03:43 | ben_vulpes | TEttinger: i found cl with the sbcl compiler to be exquisitely well typed |
| 03:44 | ben_vulpes | 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. |
| 03:44 | ben_vulpes | but no, no Hindley Milner as far as i could tell. |
| 03: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 |
| 03:45 | TEttinger | in different ways, I haven't used either |
| 03: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. |
| 03:45 | TEttinger | nice |
| 03:45 | ben_vulpes | glorious |
| 03:45 | TEttinger | isn't SBCL's compiler also rather slow (I suppose like lein could be) |
| 03:46 | ben_vulpes | i dont really write performance-oriented code, or big cl projects |
| 03:46 | pythys | Thank you everyone for the reference links and tips. Much appreciated |
| 03:46 | ben_vulpes | and i can asdf:load-project fast enough that it's not a concern on the things i've built |
| 03:46 | ben_vulpes | later, pythys |
| 03:46 | TEttinger | I do recall a Standard ML compiler that took 10 minutes to compile hello world. whole program optimization |
| 03:47 | ben_vulpes | myeah |
| 03:47 | ben_vulpes | optimization's not my bag |
| 03:47 | ben_vulpes | augmenting my intelligence, though... |
| 03:47 | TEttinger | it was a pretty odd thing for it to do |
| 03: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. |
| 03:48 | ben_vulpes | just because i *can* do this does not mean that i think it a good use of my mind. |
| 03:48 | ben_vulpes | gimme squigglies, yo. |
| 03:49 | TEttinger | is ~ used in CLOS? I can't really remember |
| 03:49 | ben_vulpes | haha no, i mean under the text in my editor |
| 03: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" |
| 03:50 | ben_vulpes | no no no |
| 03:50 | ben_vulpes | mistakes in code that the compiler can catch and relay to the editor for displaying to my dumb self |
| 03:50 | TEttinger | heh yes |
| 03:51 | ben_vulpes | bleee unary bitwise negation operator |
| 03:51 | TEttinger | ,(bit-not -2) |
| 03:51 | clojurebot | 1 |
| 03:54 | ben_vulpes | ,(defn lol [da-str] (format "z%s")) |
| 03:54 | clojurebot | #'sandbox/lol |
| 03:54 | ben_vulpes | like come onnnnnnnn |
| 03:54 | ben_vulpes | (lol "hi") |
| 03:54 | ben_vulpes | ,(lol "hi") |
| 03: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... |
| 03:54 | ben_vulpes | anyways. |
| 03:55 | ben_vulpes | fwiw clojure's a better tool for most jobs that come my way than anything else. |
| 03:55 | ben_vulpes | "a gun to fire today" |
| 03:55 | ben_vulpes | "the army we have today" |
| 03:55 | ben_vulpes | or what was it |
| 03:55 | TEttinger | ,(defn lol [da-str] (format "z%s" da-str)) |
| 03:55 | clojurebot | #'sandbox/lol |
| 03:55 | TEttinger | ,(lol "yay") |
| 03:55 | clojurebot | "zyay" |
| 03:55 | ben_vulpes | no i know! |
| 03:56 | TEttinger | was it the compile error thing? |
| 03:56 | ben_vulpes | runtime error |
| 03:56 | TEttinger | ah ok |
| 03:56 | TEttinger | I mean you wanted a compile error |
| 03:56 | ben_vulpes | mhm. |
| 03:57 | ben_vulpes | now i have to go trash a bunch of aws resources by hand. |
| 03:58 | ben_vulpes | 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. |
| 04:19 | ben_vulpes | whaddaya know, there were only three! |
| 04:19 | ben_vulpes | one of which was apparently a race condition in the consumed api. |
| 04:55 | jonathanj | Is it possible to change where the .m2 cache directory is created and searched? |
| 04:55 | jonathanj | In particular when running lein tasks. |
| 05:11 | wink | you could always just symlink it before running |
| 05: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? |
| 07:43 | asdf12z_ | the parens have me tripping balls in clojure heh |
| 08:06 | ben_vulpes | turned on rainbow-delimeters-mode, did we? |
| 09:59 | someone1 | hi |
| 10:00 | someone1 | 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 | russellw | 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 | justin_smith | :b2 |
| 11:52 | justin_smith | 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 | dorian | er at least in the context of a predicate test |
| 11:56 | dorian | 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 | ToxicFrog | 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 | dorian | 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 | sdegutis | ,(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 | sdegutis | ,(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 | russellw | 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 | sdegutis | russellw: this way, whenever I do something that reflects poorly, cider highlights it in yellow for me when I eval it |
| 12:47 | sdegutis | I mean when I eval/define the function it's in. |
| 12:47 | sdegutis | 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 | russellw | I imagine that should improve performance? |
| 12:47 | Glenjamin | yeah, reflection is slow |
| 12:48 | Glenjamin | ,(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 | russellw | 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 | russellw | 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 | @amalloy | 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 | {blake} | 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 | rasmusto | 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 | rasmusto | 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 | hyperhopper | and passing 2 arguments |
| 15:10 | hyperhopper | but getting an ArityException for only passing one argument |
| 15:11 | hyperhopper | here is the call: (histogram-distance h (histogram "./input/coast_test2.jpg")) |
| 15:11 | hyperhopper | what could I be doing wrong? |
| 15:11 | hyperhopper | Also happens with (histogram-distance h h) |
| 15:12 | ridcully | are you recuring etc on itself with wrong arity? |
| 15:13 | ridcully | could you share the code and the error on some copy-and-paste-site? |
| 15:19 | hyperhopper | sure |
| 15:19 | hyperhopper | and no im not doing recursion |
| 15:20 | {blake} | hyperhopper: Is the error for histogram, and nto histogram-distance? |
| 15:20 | {blake} | 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 | hyperhopper | one sec lemme upload it |
| 15:21 | hyperhopper | The code |
| 15:21 | hyperhopper | http://pastebin.com/jLW4RjQa |
| 15:23 | hyperhopper | 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 | hyperhopper | I can create histograms fine |
| 15:23 | @amalloy | nm |
| 15:23 | @amalloy | your lambda in (defn histogram-distance gets too few args |
| 15:27 | hyperhopper | oh you're right, thanks! |
| 15:28 | hyperhopper | whats would be the cleanest way to do what I'm trying to do in clojure? |
| 15:28 | hyperhopper | I zip and map |
| 15:28 | hyperhopper | 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 | hyperhopper | 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 | hyperhopper | In what case could (min-key) return the entire array passed to it? |
| 16:16 | hyperhopper | 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 | hiredman | ,(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 | hyperhopper | 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 |