#clojure log - Feb 22 2017

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

11:06 Ardx: what does the @ symbol mean in macros?

11:11 wink: that feeling when you read such a question and first have to check what language channel you're in. :P

11:11 mavbozo: @ is a shorthand for deref function

11:12 Ardx: how is it different from ~

11:12 ?

11:12 mavbozo: is the @ symbol you see has ~ in front of it?

11:12 like ~@

11:12 Ardx: well I'm trying to use it

11:13 ~@ seems to make it worse :D

11:13 clojurebot: Gabh mo leithscéal?

11:13 mavbozo: ~please listen clojurebot

11:13 clojurebot: Excuse me?

11:14 mavbozo: ,(def three-and-four (list 3 4))

11:14 clojurebot: #error {\n :cause "SANBOX DENIED"\n :via\n [{:type java.lang.Exception\n :message "SANBOX DENIED"\n :at [clojure.core$eval3$fn__4$fn__17 invoke "NO_SOURCE_FILE" -1]}]\n :trace\n [[clojure.core$eval3$fn__4$fn__17 invoke "NO_SOURCE_FILE" -1]\n [clojure.core$eval3$fn__4 invoke "NO_SOURCE_FILE" 0]\n [clojure.core$eval3 invokeStatic "NO_SOURCE_FILE" 0]\n [clojure.core$eval3 invoke "NO_SOURCE_FIL...

11:14 mavbozo: ,(def a 1)

11:14 clojurebot: #error {\n :cause "SANBOX DENIED"\n :via\n [{:type java.lang.Exception\n :message "SANBOX DENIED"\n :at [clojure.core$eval29$fn__30$fn__43 invoke "NO_SOURCE_FILE" -1]}]\n :trace\n [[clojure.core$eval29$fn__30$fn__43 invoke "NO_SOURCE_FILE" -1]\n [clojure.core$eval29$fn__30 invoke "NO_SOURCE_FILE" 0]\n [clojure.core$eval29 invokeStatic "NO_SOURCE_FILE" 0]\n [clojure.core$eval29 invoke "NO_SO...

11:14 mavbozo: ~aaargh

11:14 clojurebot: Gabh mo leithscéal?

11:16 Ardx: mavbozo this is my code http://pastebin.com/tUKyrd8a

11:16 see it produces nil a lot

11:16 mavbozo: ,(let [tf (list 3 4)] `(1 ~@tf))

11:16 clojurebot: (1 3 4)

11:17 mavbozo: the ~@ unquote-splicing removes the parentheses from a list

11:17 ,(let [tf (list 3 4)] `(1 ~tf))

11:17 clojurebot: (1 (3 4))

11:18 Ardx: ah ok dont think that helps then

11:25 Hmm are macros expanded before defs are initialised?

11:25 that would explain why I get nil, as what I pass in is empty

11:38 ,(= 2 3)

11:38 clojurebot: false

11:38 Ardx: hmm how do I actually set values in clojure

11:46 mavbozo: Ardx, in a namespace you can bind value to a var using def

11:46 ,(def x 1)

11:46 clojurebot: #error {\n :cause "SANBOX DENIED"\n :via\n [{:type java.lang.Exception\n :message "SANBOX DENIED"\n :at [clojure.core$eval31$fn__32$fn__45 invoke "NO_SOURCE_FILE" -1]}]\n :trace\n [[clojure.core$eval31$fn__32$fn__45 invoke "NO_SOURCE_FILE" -1]\n [clojure.core$eval31$fn__32 invoke "NO_SOURCE_FILE" 0]\n [clojure.core$eval31 invokeStatic "NO_SOURCE_FILE" 0]\n [clojure.core$eval31 invoke "NO_SO...

11:46 mavbozo: ~darn

11:46 clojurebot: No entiendo

11:47 Ardx: Yeah I may as well figure out the clojure fnctional way of doing it though

11:48 scriptor: Ardx: you use (let) for local bindings, but try to think in terms of transformations and flows of data

11:48 rather than setting values at each step

12:05 osfabibisi: Ardx: do you need a macro?

12:06 if you are both trying to single-step through because it's complicated *and* asking about the syntax, then you may be biting off more than you can chew? ;-P

12:06 (I feel I can say this, because I was doing exactly the same thing a month ago...)

12:15 Ardx: Yeah I started clojure yesterday

12:16 But I fixed the macro now

12:17 Now I'm just wondering, if I have a tree structure of hashmap, and I update a leaf node, how do I then add that lea node back onto the tee?

12:18 Because it's all immutable, I can't just update one value. I guess I have to go back up the chain and recrate every hashmap along the way

12:18 technomancy: you would use update-in

12:19 ,(update-in {:a {:b [45 88 {:c 5}]}} [:a :b 2 :c] inc)

12:20 clojurebot: {:a {:b [45 88 {:c 6}]}}

12:20 Ardx: hmmm

12:23 that would update any :a :b :c it finds though

12:23 technomancy: no, the second arg is a linear path to follow

12:24 Ardx: ahh

12:24 technomancy: ,(update-in {:a {:b [45 88 {:c 5}]}} [:b 2 :c] inc)

12:24 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [clojure.lang.Numbers ops "Numbers.java" 1013]}]\n :trace\n [[clojure.lang.Numbers ops "Numbers.java" 1013]\n [clojure.lang.Numbers inc "Numbers.java" 112]\n [clojure.core$inc invokeStatic "core.clj" 919]\n [clojure.core$inc invoke "core.clj" 914]\n [clojure.lang.AFn applyToHelper "AFn.java" 154]\n ...

12:24 osfabibisi: or you can use zippers

12:24 technomancy: osfabibisi: hush you; he's on his second day

12:24 osfabibisi: technomancy: then he shouldn't be playing with macros :D

12:24 technomancy: true

12:24 Ardx: \o/

12:25 justin_smith: macros are for absolute beginners (so you know what they hell they are about) and for people of advanced expertise who are redefining the language in their code, in between you'll rarely need macros

12:26 osfabibisi: justin_smith: ooo, good point ;-)

12:26 justin_smith: I'm barely at the point where making my own macros is a good idea myself

12:26 technomancy: day 2 of learning clojure: write three macros, understand how they work, and throw them immediately away

12:26 justin_smith: right

12:27 there's an optional "make a semi useful lib and fill it with domain specific macros with a cute syntax" - just skip that idea and throw it away

12:28 osfabibisi: ;-)

12:29 one day, there will be a `git diff` that isn't rendered crazy by the reordering of functions...

12:29 justin_smith: osfabibisi: it's possible to make diff plugins for git that are smarter about individual languages

12:30 osfabibisi: justin_smith: is there one for clojure that you can recommend?

12:30 justin_smith: it would be cool to make a diff plugin for clojure using planck (since it starts up fast and knows about clojure syntax...)

12:30 osfabibisi: not that I know of, but I think it would be an awesome idea

12:30 diffing by form/sexp rather than line...

12:30 osfabibisi: that said, diffing by sexp isn't my problem here

12:31 it's 2 forms changing order e.g. (defn foo ......) (defn bar ......) getting swapped around

12:31 which always results in one hunk being deleted from origin point and added to new point, because diff algos only work on things as sequences

12:32 justin_smith: osfabibisi: that's what I mean, if it was looking at balanced forms / subforms, it would know not to do weird splitting in the middle like that

12:32 it's diffing by line, which gives the weirdness

12:32 osfabibisi: no no, I've explained badly, sorry

12:33 e.g. the definition of (defn foo ...) moves from line 15 to line 100

12:33 justin_smith: osfabibisi: I think we just disagree about why git is misbehaving

12:33 I know the behavior

12:33 osfabibisi: the forms are still balanced

12:33 amalloy: i think osfabibisi is complaining about even more benign behavior than you're thinking of

12:42 osfabibisi: yes, I think I understand what justin_smith is talking about - when 2 forms share common features

12:43 but in this case they're not incorrectly misidentified, they've just moved

12:45 amalloy: there's not really a lot you can do about that in the unix diff model, since it's line based. there are sexp-based diff tools out there, though i don't know how good they are or whether you can get them involved in git diff at all

12:45 Ardx: so if I have a tree, made of hash maps, and then I have a list [:area :top], is there a function that does something like (get-leaf root-map [:area :top]), and iterates that list and goes down through the tree?

12:47 amalloy: actually i bet you could configure diff.tool to point to a shell script that launches your sexp differ for .clj files and a standard diff otherwise

12:47 Ardx: or I could use a macro to turn it into "(-> :area :top)" I guess

12:47 amalloy: (doc get-in)

12:47 clojurebot: "([m ks] [m ks not-found]); Returns the value in a nested associative structure, where ks is a sequence of keys. Returns nil if the key is not present, or the not-found value if supplied."

12:47 osfabibisi: probably. but again if it's sequence-based that won't really help for this case

12:47 instead, I'm just going to give colleagues a hard time about their commit being impossible to review :D

12:47 Ardx: amalloy cheers!

13:04 justin_smith: amalloy: yeah- a sexp based diff for sexp languages was kind of what I had in mind

13:55 osfameron: what's the minimum I need to do to set a classpath in a boot repl?

13:55 e.g. I have a project template I know works, if I have src/project/foo.repl and a namespace project.foo

13:56 and a boot.build and so on

13:56 but if I just want to edit scratch.clj to play around then my editor complains " Could not locate scratch/scratch__init.class or scratch/s

13:56 cratch.clj on classpath"

14:05 justin_smith: osfameron: for super basic stuff I just use load-file

14:05 eg. $ vim /tmp/scratch.clj then (load-file "/tmp/scratch.clj")

14:05 I leave require and such for things that are defined parts of my project

14:06 (I did find the annoying fact that I can't do macros in planck this way - it only allows macros via classpath... but that's the only hiccup I've had for this workflow)

14:07 osfameron: justin_smith: you mean from the repl itself?

14:07 ah yes, that works

14:08 and then fireplace stops complaining

14:08 ta

14:08 justin_smith: osfameron: yes, I call load-file from the repl - though most editors with clojure integration have a simple keypress that invokes load-file

14:09 osfameron: fireplace has the odd thing that it's supposed to be namespace aware, but it can't seem to resolve the location of a file it actually has open...

14:09 it all works with a properly set up project of course

14:10 justin_smith: aha - I use fireplace but only in a very rudimentary way - I think I just assumed that rando .clj file would not play nicely so I should use blunt tools like load-file

14:10 but that was based on hunches, not expertise

14:11 osfameron: if you open a project with a proper boot (or I imagine leiningen) setup, then everything Just Works

14:11 justin_smith: yeah, all my work since I started using fireplace is in a library that doesn't have its own repl / process, so I have not been so lucky

14:12 osfameron: and you can't use clojure's builtin repl?

14:12 justin_smith: osfameron: I have an app, the app runs from two repls, this library is used by each of the repl based apps

14:12 point being that the code I am editing is not on the classpath of either repl - they are using the version that was put in cache by lein install

14:13 osfameron: ah. sounds complicated

14:13 justin_smith: and I refuse to muck with the whole symlink nonsense

14:13 osfameron: it would be super complicated if I tried to have convenient tooling, but all I need is a repl plus load-file and things work

14:14 osfameron: :D

14:14 justin_smith: eg. there are two different repls that both want the new version of foo.clj - doing this via the editor would be silly

14:16 since editor tooling that allows multiple repls wants to map a file to a single repl in my experience

14:22 Ardx: ended up using assoc-in

14:22 and an atom for the tree root :D

14:23 and turned the macro into a function, so I could actually step throguh and debug the many problems the code had

14:23 god dang are clojure errors cryptic though

14:24 justin_smith: Ardx: a good design strategy is to use a function for all your logic, and if you need a custom syntax, make a minimal macro where the function is doing the real work

14:24 I think you've learned already how much easier that is to debug (also if you need to build more functionality, a function is a much easier starting point than a macro usually)

14:25 machinewar: do you think clojure.spec would be good solution for masking data? pretty much need to restore data from one db to another, but obfuscate some of the data (but it needs to still resemble valid data)

14:25 so I'm thinking you could for example describe the shape of a postal code, a first name, last name, etc

14:25 and use it at runtime to generate fake data

14:25 justin_smith: that doesn't sound like what spec is for at all...

14:25 I mean I guess it plugs into generators for testing purposes...

14:26 machinewar: yea that's what I'm thinking

14:26 Ardx: justin_smith yeah keeping macros small sounds like a good plan

14:27 justin_smith: Ardx: of course there's special cases like core.match and core.async which build whole languages (very useful languages!) that can't just be summed up with a bunch of functions, but those are very special

15:46 * osfameron wonders why refs "cannot be cast to clojure.lang.Named"

15:46 justin_smith: why would a ref have a name?

15:47 dysfun: did you call name on it?

15:47 osfameron: hmm, maybe I don't mean refs then? "stuff that you've def'd" ?

15:47 dysfun: vars!

15:47 justin_smith: vars?

15:47 osfameron: dysfun: yes!

15:47 clojurebot: vars are a linking construct

15:47 dysfun: vars are not refs

15:47 osfameron: right, so vars then.

15:47 they have names don't they?

15:48 justin_smith: ,(:name (meta #'+))

15:48 clojurebot: +

15:48 osfameron: that doesn't seem to work for things I've def'd or defn'd myself though

15:49 justin_smith: def and defn both attach :name

15:49 (as a metadata)

15:49 osfameron: ah, I missed the #' bit... what does that do?

15:50 justin_smith: accesses the var

15:50 + points to the function pointed at by the var

15:50 osfameron: ah... instead of the value?

15:50 justin_smith: #'+ gets the var itself

15:50 osfameron: ok

15:50 amalloy: osfameron: imagine (def x 1)

15:50 you want x to eval to 1, not to a var

15:50 justin_smith: ,#'+

15:50 clojurebot: #'clojure.core/+

15:50 justin_smith: err

15:50 ,'#'+

15:50 clojurebot: (var +)

15:50 amalloy: but sometimes, you want to get at the var anyway, and that's what #'x does

15:50 osfameron: ok

15:51 justin_smith: #' is a reader macro, shorthand for (var )

15:51 amalloy: the name can't be stored on the value 1, and is instead stored on the var

15:51 osfameron: so why doesn't (name #'+) work?

15:51 justin_smith: well that's a more controversial decision

15:51 amalloy: so, name is for getting the "name" part of a name+namespace pair thingy

15:51 justin_smith: but regardless of reasons, at least the :name key on the metadata will help

15:51 osfameron: true

15:51 thanks!

15:51 amalloy: and a var is not one of those; it is a lot more things than just a name

15:52 osfameron: ah

15:52 dysfun: a var *has* a named thing, but it isn't one

15:52 amalloy: ,(keys (meta #'inc))

15:52 clojurebot: (:arglists :doc :inline :added :line ...)

15:53 osfameron: well, that was all so exciting, I've now forgotten why I thought I wanted to call (name) on a var in the first place...

15:56 justin_smith: osfameron: my assumptions is shenanigans of some sort

15:56 osfameron: consider that given a symbol, you can get a var and a name from it

15:56 ,((juxt name resolve) '+)

15:56 clojurebot: ["+" #'clojure.core/+]

15:56 justin_smith: maybe that's what you wanted? resolve is good for shenanigans

15:56 amalloy: a symbol and a namespace

15:57 justin_smith: amalloy: well, symbols can be namespaced, and resolve will use your namespace's lookup rules to find a namespace

15:57 amalloy: yes, "your namespace" is the namespace here that you need

15:58 calling resolve at runtime outside of a repl without specifying a namespace is going to give you trouble

15:58 justin_smith: right, because your thing likely isn't available by any shorthand in user

15:58 osfameron: justin_smith: ooo, thanks

15:59 amalloy: (because *ns* is bound to the current namespace while in a repl, but it's not when running an actual program via -main)

15:59 justin_smith: amalloy: in my experience it's always bound to user, unless someone made some effort to switch it

15:59 I've never seen it unbound

16:00 amalloy: what i mean is, it's not bound to any useful value that you might think of as "the current namespace"

16:00 justin_smith: fair

16:01 technomancy: doesn't resolve DTRT when passed a qualified symbol?

16:01 osfameron: if I want to go the other way - e.g. I have a map of {name function, ...} what's the best way to get those defn'd together?

16:01 justin_smith: technomancy: if it's fully qualified, yes

16:01 technomancy: oh justin said that already

16:01 justin_smith: osfameron: intern

16:02 osfameron: the tricky part is that intern doesn't add the nice metadata that def/defn do

16:02 in my experience intern is a good sign you are being too clever for your own good (moreso than resolve is even)

16:03 osfameron: yes, probably

16:03 it's quite a common ask in e.g. Perl though

16:03 justin_smith: osfameron: consider that looking something up in a hashmap and calling it is perfectly acceptable

16:03 osfameron: where you can define exporters custom exporters for functions

16:03 justin_smith: sure, and perl is known for tricky business as a common programming style, right?

16:04 I'm not saying intern is never valid, just that it indicates you are likely adding complexity, which is a good moment to ask what you are getting in return for that cost

16:04 osfameron: well, that's part of doing hard work *behind the scenes* to get a nice API for the user of a library

16:04 but yes, point taken, and I'll see if I can avoid it :D

16:05 justin_smith: osfameron: but clojure is a very introspective and reflective language, and libraries that make it hard to find definitions or map definitions back to some form are really annoying

16:05 osfameron: is that a problem if I set the metadata politely?

16:05 justin_smith: we have a lot of tools to find the code that generated a thing, but tricks like intern undermine them

16:06 osfameron: hmm, I wonder how hard it would be to set the right file/line metadata automatically...

16:07 osfameron: so the thing I'm thinking about is a logging library

16:08 (info "hello") might write to stdout or it might send a message to a queue or whatever

16:08 and I want to avoid a singleton global

16:08 (info my-logger "hello") is ok, and doesn't need any cleverness

16:09 justin_smith: aside - (but don't most clients of logging libraries expect a global behavior?)

16:11 osfameron: hmm, maybe?

16:11 I think dysfun mentioned that being something he didn't like about timbre

16:12 and it chimed with whatever I was thinking

16:12 anyway, you could always (info *global-logger* "hello") if you wanted it :D

16:12 justin_smith: I don't fully agree, but I've seen it argued that logging config should be global and static and hard to modify dynamically because security

16:13 osfameron: static sure, but why does global help there?

16:14 I kinda understand why people want the dynamic behaviour, but I've found that confusing far more often than actually useful

16:16 justin_smith: I guess less complexity means less possibility for corner cases or unexpected combinations of behaviors

16:16 it wasn't my argument so I'm not sure :)

16:17 I mean, once someone can change a var in my clojure program, that machine is hosed, messing with logging is the least of it

16:20 jonathanj: Where do you get the logger from that you want to log to?

16:23 Is it okay if your library uses a different logger than the user calling your library?

16:24 It seems (but perhaps I don't fully understand) like it would be annoying if a library logged stuff somewhere else when I don't want it to.

16:28 justin_smith: jonathanj: I don't really get logging but/and I find "annoying" a good description for all my interactions with things related to logging

16:29 jonathanj: I'm probing because I'm on the brink of porting a logger library to Clojure and I'd like a nice API.

16:30 osfameron: yeah, logging tends to be overcomplicated, overengineered and badly documented

16:30 jonathanj: I thought of having something like `(with-logger a-logger some forms)` rebind `*logger*`.

16:31 dysfun: i hope you didn't want some async with that because dynamic bindings are thread local

16:31 jonathanj: I was wondering about that.

16:32 justin_smith: I've been briefly enticed with ideas of software friendly logging (eg. every log is a json record including level and namespace etc. and the one reading the logs uses a client to filter and format)

16:32 dysfun: (in fact i use them in my single threaded cljs refs implementation)

16:32 jonathanj: So if any of those forms are async then I guess you need to wrap the logger at another level.

16:32 technomancy: justin_smith: how about https://brandur.org/logfmt

16:32 dysfun: justin_smith: i think riemann is a good base for that sort of thing

16:33 jonathanj: justin_smith: the library I intend on porting is http://eliot.readthedocs.io/ which might be an inspirational read then

16:33 justin_smith: technomancy: I've never seen that, interesting

16:33 technomancy: justin_smith: we used it heavily at heroku and it was <3

16:34 justin_smith: see, all these things are great, but they are improvements to a thing I find very unpleasant so my likelyhood of taking them on is lower

16:35 technomancy: the team I was on at heroku was literally the logging team =)

16:36 it was an island of erlang in a sea of ruby/golang so I wasn't complaining

16:36 justin_smith: hah, nice

16:36 jonathanj: After having used Eiot for some complex logging, being able to visualise the hierarchy seems like a can't-go-back experience.

16:36 patchwork: justin_smith: I like your vision of logging. That is all it needs to be

16:37 dysfun: always fun to play with things like erlang

16:37 patchwork: (tears out swaths of logging code from project)

16:37 technomancy: Are you anti-golang? Is golang the devil? I haven't tried it yet

16:37 You used it in the same sentence as ruby so....

16:37 technomancy: patchwork: it's ... not a good programming language

16:38 patchwork: I have a coworker who is an evangelist of golang right now

16:38 since I don't have any experience with it I don't really have a good response for the guy

16:38 dysfun: technomancy: diplomacy, you has it. i would be less polite about it than that

16:38 technomancy: we use it some at work and the only reason I can live with it is that no one is evangelistic about it

16:39 patchwork: What are the issues? I thought the goal towards concurrency and minimalism coincides with why I love clojure

16:39 Like I said though, haven't tried it

16:39 technomancy: patchwork: it's very clearly designed by someone who hasn't done their homework around type systems, to say the least

16:40 dysfun: or on many other areas critical to it, like garbage collection

16:40 patchwork: Ah okay.... after working in scala for the past year I am starting to resent heavy type systems ; )

16:40 technomancy: like ... what's the most common type error by at least an order of magnitude? null references. so you would think then if you were designing a type system, handling null references would be the first thing you would encode into it? not in golang. =(

16:40 patchwork: but maybe that is just because of implicits

16:41 technomancy: scala at least has the interop excuse; golang has no excuse.

16:41 patchwork: Ah yes, null references

16:41 technomancy: "this is how we did it in the 1970s so it's probably the best way to do it"

16:41 patchwork: Something I have been very happy to do away with in scala

16:41 haven't had one of those in a long time

16:41 I see, funny!

16:41 dysfun: and whoever thought it was a good idea to make all the containers non-threadsafe in a highly concurrent language, well that's just a stroke of genius

16:41 l1x: golang is amazing i think interface{} is just a pretty nice way of saying go and fuck yourself and your types

16:41 patchwork: You think the google people would put someone more thoughtful on their signature language design team

16:42 technomancy: also "pass by value semantics" aka we are going to implicitly copy all values for every function call unless you opt out of it

16:42 dysfun: signature language? perhaps you mean dart?

16:42 technomancy: patchwork: famous is apparently an acceptable replacement for thoughtful

16:42 l1x: yeah that too

16:42 dysfun: technomancy: oh yes, it's *definitely* a replacement for C!

16:42 patchwork: Ah, I thought golang was their flagship

16:42 l1x: the lack of proper types bothers me more though

16:43 patchwork: Cool, so it is better than C

16:43 Progress is good

16:43 l1x: like we did not have ocaml or any good languages with decent type systems

16:43 dysfun: patchwork: that was sarcasm

16:43 patchwork: Thanks for the summary!

16:43 l1x: patchwork: it is good for a single reason: CSP

16:43 technomancy: patchwork: my favorite way to describe golang's type system is it's like wearing a bulletproof vest with a big gaping hole over the heart. it's bulky and impedes your movement, but it doesn't actually protect your most vital organs.

16:43 l1x: :D

16:44 patchwork: dysfun: I don't know what sarcasm is anymore

16:44 dysfun: there isn't a hole to get into it because they don't support generic vests

16:44 l1x: well go is pretty good if you are a python programmer

16:44 hey look ma, i can ship a single binary!

16:44 dysfun: l1x: so one of my friends is currently writing cgo and FFIing from python...

16:44 l1x: there you go! :)

16:45 technomancy: l1x: it's funny how ruby and python people are so impressed by such a simple thing

16:45 dysfun: tbf it's a cool thing

16:45 single artifact deployments are ace

16:45 osfameron: uberjars!

16:45 l1x: technomancy: yeah, they havent seen ocaml this is why

16:45 technomancy: dysfun: yeah but racket, ocaml, lua... this is not exactly a high bar

16:46 dysfun: sure

16:46 technomancy: it's just the jvm/python/ruby go out of their way to make things difficult

16:46 patchwork: It is for people who've never seen it before ; )

16:46 l1x: do you want a single binary? or do you want byte code? do you want union types? do you have Some(x) or None? Please be my gues

16:46 osfameron: is Rust more interesting?

16:46 l1x: guest*

16:46 technomancy: osfameron: by a long shot

16:46 l1x: yeah

16:47 it has almost all the great features of ml languages

16:47 technomancy: osfameron: the original rust compiler was written in ocaml, so you know it's designed by someone who hasn't been ignoring the last couple decades of research

16:47 l1x: yep

16:47 patchwork: I mean, right now the heavyweight nature of the JVM is a pretty big strike against it

16:48 I am shipping a 300MB uberjar.... it raises some eyebrows

16:48 l1x: sure

16:48 osfameron: for some applications yeah

16:48 patchwork: Mostly of code I did not write

16:48 l1x: this is because many of the Java devs are morons

16:49 technomancy: it's a great fit for server-side code but not a one-size-fits-all by any means

16:49 l1x: http://mail-archives.apache.org/mod_mbox/orc-user/201702.mbox/%3CCAB25XEXALvkPWcG1mf6VRS-C0ZXvfdZGww-Bf-mgYiFo%2BhObaw%40mail.gmail.com%3E

16:49 story of today

16:50 dysfun: but rust has some horriblenesses

16:50 like a constant deprecation cycle

16:51 l1x: yeah, i am not going to use it before it turns 10 years old

16:51 that is the qualifier for a programming language

16:51 dysfun: and the libraries are way too immature. they're trying to get the type safety and doing it at the cost of the flexibility you need from a systems language

16:51 like don't even get me started about things like raw files last time i tried

16:51 * technomancy glances at l1x, glances at the channel title

16:51 technomancy: wait a minute...

16:51 l1x: :D

16:51 dysfun: wasn't clojure 2006?

16:52 dxtr: It takes 30 seconds to start the jvm on my other laptop. Just food for thought :p

16:52 technomancy: dysfun: I guess it depends on if you're counting from first commit or first public commit

16:52 l1x: First appeared 2007; 10 years ago

16:52 dysfun: dxtr: over a minute on a shitty box i borrowed last year when i was down on my luck

16:52 l1x: what?! :D

16:52 dxtr: dysfun: :D

16:52 dysfun: technomancy: close enough then :)

16:53 l1x: dxtr: well it is slow but once it is up!!

16:53 dysfun: yes and no

16:53 dxtr: l1x: Once the help text shows it shows it lightning fast!

16:53 patchwork: Well luckily you don't ever need to modify your code

16:53 dysfun: i swear too many silicon valley people think we're all running supercomputers

16:53 dxtr: dysfun: Are we not?

16:54 dysfun: "i write my shell scripts in clojure" "i don't have a minute to wait for them to start"

16:54 l1x: hahaha

16:54 actually ocaml is much better for "shell scripts"

16:54 justin_smith: dysfun: did you meantion you were working on a lumo fork at some point?

16:54 dysfun: yeah, there are some good libs for that

16:54 l1x: dxtr: have you tried a neutered jvm?

16:54 technomancy: dysfun: my personal laptop is a core 2 duo

16:54 justin_smith: l1x: yeah - you can even compile ocaml to machine code from source, then run it, fast enough :)

16:54 dxtr: Remember that time when you parallelized some stuff in ocaml?

16:55 l1x: justin_smith: yep exactly that

16:55 patchwork: Just wrote a script in planck a few days ago.... that is my new paradigm

16:55 technomancy: have been enjoying mostly writing luajit on that

16:55 dysfun: justin_smith: no. i am working on a build tool that uses lumo

16:55 dxtr: l1x: I have not

16:55 justin_smith: aha, now I get it - that's smart

16:55 technomancy: dxtr: the best thing about ocaml is it's like the mirror world of the jvm. low memory usage, terrible at concurrency, no %$@& nils, spock has a beard, etc

16:56 patchwork: Ah sigh.... so 2017, we still don't have the perfect programming environment

16:56 dxtr: technomancy: It can do concurrency fine

16:56 patchwork: Someone told me we would have this down by now

16:56 dxtr: technomancy: Parallelism on the other hand :)

16:56 patchwork: dxtr: Oh yeah? Just by spawning a new process and communicating over sockets?

16:56 l1x: technomancy: hahaha this is a perfect explanation

16:56 technomancy: dxtr: well I mean literal concurrency

16:56 justin_smith: patchwork: we might not have the perfect programming language, or flying cars, but you can get "croc martens" boots

16:56 l1x: but hey, concurrency is coming! :)

16:57 patchwork: Based on the way most people I see drive, I am super glad we don't have flying cars yet

16:57 l1x: well self driving flying cars

16:57 technomancy: patchwork: maybe we could wait till decent type systems become a bit more widespread before coding self-driving flying cars

16:58 dxtr: patchwork: Either that or you could just use the async package, for example.

16:58 l1x: btw. clojure got really fast over the years, lein repl is much faster to start up, lein uberjar is also more performant

16:58 technomancy: you put wings on that sucker and it better be written in Ada or an ML spinoff

16:58 l1x: i remember when lein repl took a decent amount of time

16:58 technomancy: lein repl is fast now? cool!

16:58 l1x: maybe because of java 1.8

16:59 technomancy: what do you use instead?

16:59 patchwork: Just started lein repl.... 5 seconds

16:59 l1x: since you wrote it, i bet you use lein :)

16:59 dysfun: 3s here, but this is a nice machine

16:59 technomancy: l1x: I use lein inside docker-compose where it takes like five minutes to bring up the whole cluster

16:59 l1x: nice

17:00 dysfun: boot repl took 20s!

17:00 dxtr: Also, I started with clojure las week! Yay me, or something

17:00 l1x: dxtr: \o/

17:00 dxtr: I've been putting it off for years because jvm

17:01 l1x: dxtr: the best part is the community

17:01 like seriously

17:01 dysfun: dxtr: you learn to live with it. i was a massive java hater when i started with clojure

17:01 l1x: dxtr: the reason i started to use clojure because i could not even read java at the time

17:01 dxtr: dysfun: I have actually done Java professionally :p

17:01 l1x: dysfun: highfive

17:01 justin_smith: $ time java -jar ~/bin/clojure.jar -e '(System/exit 0)' => real 0m2.866s

17:02 dysfun: clojure is truly a breakthrough: it enables me to tolerate writing code that runs on the jvm

17:02 dxtr: I don't mind the jvm in itself. It's the bulkyness I dread

17:02 dysfun: i don't mind the jvm either, but the traditional way of programming it was java, which i do mind

17:02 l1x: dxtr: once in production this does not matter really

17:03 dysfun: even the java standard libraries aren't so bad driven with clojure

17:03 dxtr: What clojure needs is more templating, amirite?

17:03 l1x: most of our projects are 10-50MB uberjars where 95% is libraries not even needed but Java devs just add dependencies like trump outputs executive orders

17:04 dxtr: not sure

17:04 dxtr: :p

17:04 dysfun: (in particular i have to say AWT is a really nice API - transformation steps return new data rather than modifying in place)

17:04 l1x: i do not use too much templating

17:04 technomancy: if you can get over the horrid name http://docs.racket-lang.org/rackjure/index.html is a great way to write clojurey code without the huge jvm overhead

17:04 dxtr: l1x: I made a funny Java joke

17:05 dysfun: technomancy: they made ~> and ~>> more powerful than clojure's -> and ->> didn't they?

17:05 l1x: dxtr: no java jokes are funny :D

17:05 technomancy: racket does not have the libraries i need for my work

17:05 technomancy: dysfun: I hadn't heard that

17:05 dysfun: libraries are why i ended up sticking with clojure

17:05 l1x: this is why clojure is winning, there is a (shitty) java lib for everything

17:06 dxtr: l1x: Also, the worst part about Java stuff is the XML that surrounds it. I learned to hate a lot of things when I coded java at the job :p

17:06 l1x: dxtr: edn ftw

17:06 technomancy: l1x: well it's good to have options anyway

17:06 dxtr: Mainly XML and factory patterns

17:06 l1x: technomancy: true that

17:06 dysfun: i think most professional java devs know how to drive IDEs that generate boilerplate for them

17:06 l1x: how is CSP/concurrency in racket?

17:07 dxtr: dysfun: Which sucks when things break

17:07 technomancy: l1x: you get real threads, but the GC is stop-the-world. I would be surprised if there weren't a good CSP implementation but I don't know if it ships in the stdlib

17:08 l1x: i see

17:08 dxtr: well, Racket isn't really made to be performant, is it?

17:08 l1x: this is why i think lfe is a better direction

17:08 the erlang no global vm stop is just amazing

17:08 technomancy: dxtr: it's made serious strides in the past few years (especially on ARM) but nothing like the JVM

17:09 l1x: dxtr: last time i checked it was up in the same bracket with clojure in terms of http-hello-world-micro-benchmark-e-penis

17:09 technomancy: actually there was a brief window when racket could beat clojure on ARM performance

17:09 when most of hotspot's jit smarts were x86-only

17:09 l1x: and it does not require a 160MB JVM

17:10 dysfun: l1x: i lost faith in lfe

17:10 dxtr: I just go with erlang

17:10 l1x: dysfun: how about joxa? :)

17:10 technomancy: joxa's design is great

17:10 l1x: dxtr: alright, erlang than! :)

17:11 dysfun: partially i think erlang is a nicer language, partially i'm not happy with some fundamental qualities of the erlang vm

17:11 l1x: i like erlang but i cannot find developers who i could work with

17:11 dysfun: like?

17:11 i really like beam

17:11 dysfun: for example the atom table

17:11 we wrote some generative tests for lfe and it would exhaust the atom table and crash the BEAM

17:12 and the fact that the builtins can't spawn processes and reliably recover if they close (they expect an EOF character!)

17:12 l1x: even when you configure it right?

17:12 dxtr: Well, to be fair, if you're generating that many atoms you should consider another data structure

17:12 dysfun: OS processes i mean, not erlang processes

17:12 dxtr: hard to do generative tests involving atoms without generating lots of atoms

17:13 l1x: dysfun: these are sort of issues that either i dont care or if i had to care i could solve them

17:13 dxtr: dysfun: Just seems like a weird thing to do :p

17:13 dysfun: generative testing? yeah it is but it's great

17:14 l1x: By default, the maximum number of atoms is 1,048,576. This limit can be raised or lowered using the +t option.

17:14 there, easy to fix for a real world use case

17:14 dysfun: l1x: of course, but the solutions here involve reserving memory for a large atom table and shipping extra C

17:15 dxtr: Also, the vm is pretty slow

17:15 dysfun: compared to the jvm, sure

17:15 dxtr: Compared to most things?

17:15 dysfun: nah

17:16 l1x: dysfun: what is the usecase when 1,048,576 atoms are not enough?

17:16 dysfun: erlang compares favourably with dynamic langs

17:16 l1x: also erlang beats almost everything with template rendering

17:17 might not be true anymore

17:21 dysfun: templatewise, everyone uses erydtl

17:26 technomancy: do you prefer racket or clojure?

17:27 technomancy: dysfun: depends on what I'm doing I guess. I wouldn't do server-side stuff in racket, and I wouldn't do guis and CLI tools in clojure (with the obvious exception of lein)

17:28 dysfun: i saw they're moving to chez scheme because it's faster

17:28 technomancy: dysfun: I feel like Racket has historically had the edge on "prevent flexibility from becoming an unmaintainable mess over time" but now that Racket contracts are becoming part of Clojure that advantage is likely to lessen.

17:28 I'm one of the weird ones who has never cared about speed

17:30 justin_smith: technomancy: "slow code" - hammock developed artisinal quality algorithms

17:30 technomancy: apart from leiningen startup I have only once had to profile Clojure code because it was too slow

17:30 justin_smith: on a thinkpad from 2008!

17:30 justin_smith: sounds like a pitch

17:34 technomancy: dysfun: just for the record when I was hanging out in the #racket channel I frequently brought up how silly it was that hash-tables aren't callable and how their "just get the latest version of that lib lol" dependency system worked was ill-advised, etc

17:35 I bring it up here more to avoid the echo chamber effect than to convince people to stop using clojure =)

17:35 dysfun: heh

17:35 we tend to be free with our criticism of clojure in here too

17:36 racket ~> tries to fix that, btw

17:37 technomancy: dysfun: racket or rackjure?

17:37 dysfun: (~> foo 'a 'b) -> (dict-ref (dict-ref foo 'a) 'b)

17:37 rackjure, sorry

17:37 technomancy: IIRC rackjure fixes callable hash tables in a way that is not related to ~>

17:37 dysfun: that also

17:38 of course you pay a performance penalty for those checks

17:39 technomancy: which is why regexes still aren't IFn in clojure =(

17:39 l1x: i was profiling clojure several times and rewrote parts that were slow

17:39 dysfun: well, if we moved to protocols for everything like cljs did, we *could*

17:39 l1x: just to beat java devs like 100x

17:40 10x was not good enough for me :)

17:40 threading is a bitch :(

17:40 dysfun: but that's not particularly likely, i think

17:40 technomancy: dysfun: how do you implement protocols if you can't define functions yet?

17:41 dysfun: fall back to Runnable

17:42 l1x: one guy was trying to convince our ceo that the bottleneck was our network (10G/s) and i was surprised to figure out he used a single thread to do network IO to a remote datacenter

17:42 technomancy: then you can't declare any protocol functions that take args though, right?

17:42 dysfun: okay, Callable then

17:43 technomancy: IIUC the only reason you don't have circularity issues on JS is that you can change your initial protocol implementation once you've bootstrapped enough of the language

17:44 dysfun: i haven't looked into it. i can see there are difficulties, but i think it's a bit moot because it would be a huge compatibility-breaking change at this point

17:46 technomancy: some day I'll be able to (filter #"correct horse battery staple" passwords)

17:46 dysfun: that would be pretty neat

17:46 * dysfun steals for his toy lisp

17:50 justin_smith: technomancy: I knew someone once who called this "exampling" - where a concept is sound but someone takes an example of the concept's usage and follows literally, and remains ignorant of the concept itself

17:51 technomancy: justin_smith: sounds like a useful term but I'm not seeing the connection

17:51 justin_smith: technomancy: "here is how you can create a high entropy string that is straightforward to remember"

17:51 technomancy: oh haha right

17:51 justin_smith: "oh, OK, I will always remember that one high entropy string you used!

17:51 "

17:52 which is like, pathologically against the original point :)

17:52 technomancy: https://xkcd.com/221/

17:52 justin_smith: that's another good example of exampling actually

17:52 clojurebot: I don't understand.

17:52 justin_smith: clojurebot: you wouldn't, dummy

17:52 clojurebot: Pardon?

18:06 fifi-v: how can I play sound in reagent? Need something equivalent to js `new Audio("...")' and `.play()' as demonstrated here http://stackoverflow.com/a/23395136

18:08 justin_smith: fifi-v: that's not reagent specific is it?

18:10 fifi-v: (js/Audio. "data.....")

18:10 (.play ...)

18:10 fifi-v: this will all use standard interop syntax, it's pretty simple and well documented and worth learning

18:14 dxtr: Is korma a good choice for postgresql stuff?

18:16 dysfun: depends what you need

18:16 it doesn't have json operator niceties

18:16 it's very good for bread and butter traditional queries

18:17 amalloy: korma is more of a naan and curry thing than bread and butter

18:18 dysfun: har har

18:18 technomancy: did someone pick up the development of korma? I thought it was abandonware for some time

18:19 amalloy: abandonware doesn't have to be brokenware

18:19 dysfun: it still works. it hasn't seen much action, but it's not total abandonware i think

18:19 amalloy: (i have no opinion about korma personally, i just don't really go for the "x hasn't been committed to in two months, therefore it must be garbage" attitude i see sometimes)

18:20 technomancy: amalloy: I was thinking more like 4 years but sure

18:20 dysfun: korma is okay for the 90%

18:20 the limitations it puts on the remaining 10% triggered me to start building something more powerful though

18:24 dxtr: technomancy: Last commit was 11 days go, apparently

18:24 technomancy: cool

18:26 dxtr: So what do other people use?

18:27 Ardx: what does ! mean in clojure? Like if I had (set! ) does it denote that it will execute immediately (not lazy), or that it is a macro?

18:27 dxtr: side effects, if I'm not mistaken

18:28 dysfun: not safe inside dosync

18:28 Ardx: oh

18:28 dxtr: I was mistaken

18:28 dysfun: but that's only clojure core and some functions do not have the ! when they're not safe (it's presumed e.g. println is obvious)

18:33 Ardx: ugh emacs keeps puttign all my comment lines in the middle of the screen when I press return

18:34 technomancy: Ardx: use two semicolons for beginning-of-line comments

18:36 Ardx: oh yeah

18:36 nice

18:48 justin_smith: dxtr: well, most things not safe in dosync are not safe because of a side effect

18:48 dxtr: dosync retries on conflict, and your side-effecting functions could be called N times

18:48 so, bigger picture, still mostly right :)

18:49 dxtr: Well, you've gotta *really* make sure your sides are affected

18:50 technomancy: I get the feeling "let's mark side-effects with a !" was something that seemed like a good idea early on but eventually was considered too much

18:51 dysfun: is that like "let's sprinkle io! in our code"?

18:55 justin_smith: at night, when I should sleep, I am haunted by the visions of all the code I should have wrapped in io!

18:56 dysfun: i believe you. millions wouldn't.

18:56 technomancy: early on a lot of the buzz around clojure was due to its STM

18:57 which is quite remarkably good, but it's just not that frequently used

18:57 justin_smith: indeed

18:58 dysfun: well most of us build webapps which talk to a database. we just don't have much call for it

19:07 fifi-v: justin_smith: thanks

19:26 dysfun: so i'm reading an olde english book and all the 's' are 'f'. it's surprisingly demanding to parse

19:27 justin_smith: it's a separate ss that looks like an f but it has a tail on the lower left that an f doesn't have

19:27 iirc

19:27 TimMc: technomancy: Come for the STM, stay for the PDSs.

19:27 dysfun: justin_smith: nope

19:27 https://archive.org/details/firstsixbooksofe00eucl

19:28 flick to the introduction

19:29 there is a less pronounced horizontal bar to the 's' than the 'f', but they're not double s because 'ssciences' in the first sentence

19:29 justin_smith: dysfun: https://en.wikipedia.org/wiki/Long_s

19:30 it is used for doubles, including if the second s is in the middle of the word

19:30 yes, super weird rule

19:31 wait, not doubles - just any lower case s not at the end of the word

19:32 technomancy: I remember on classic Mac they used to use that as shorthand for "folder"

19:32 justin_smith: technomancy: solder - it's a secret message

19:32 dysfun: what, a long s?

19:33 justin_smith: ſſſſſſſ

19:34 dysfun: https://ia800204.us.archive.org/BookReader/BookReaderImages.php?zip=/14/items/firstsixbooksofe00eucl/firstsixbooksofe00eucl_jp2.zip&file=firstsixbooksofe00eucl_jp2/firstsixbooksofe00eucl_0015.jp2&scale=2&rotate=0 # look at how beautiful this book is though

19:34 despite the long ssssssss

19:35 justin_smith: yes, very nice

19:36 ſyſtem took me a moment

19:36 dysfun: fquare just looks so wrong

19:36 justin_smith: ſupercallifragiliſticexpealidocious

19:36 dysfun: "Befides the fuperior fimplicity"

19:38 "lefs" is a tedious one

19:38 justin_smith: for fucks ſake

19:39 dysfun: but yeah, it surprised me how much effort it was to parse

19:40 i suspect "correcting" that probably involves OCRing it and then spellchecking the OCR results because the OCR doesn't speak long S

19:52 Ardx: hah so cool you can do "lein new play-clj hello-world" and it downloads play-clj

19:53 dysfun: did your last language not have that?

19:54 Ardx: I'm used to c# and viual studio where there is a GUI on everything. I'm used to command line things never working quite right :>

19:54 dysfun: heh

19:55 justin_smith: Ardx: btw you can use clojure with CLR - it's even up to date and everything

19:55 dysfun: yeah, i was really surprised to see how well they've kept up to date

19:56 Ardx: Yeah I know, meaning to try out at some point

19:56 justin_smith: it doesn't have a clojure-centric tool like leiningen though

19:57 dysfun: yeah, i should add clr support to my lumo build tool when i get more time to hack on it

19:58 justin_smith: that would be awesome

19:58 dysfun: well the idea for me was that it shouldn't just build cljs

19:58 because that would be lame

19:58 justin_smith: and putting the build tool in something that starts up fast (eg. lumo) is a great idea

19:58 dysfun: i want it to build all sorts of things so i can take my build tool wherever i go

19:59 justin_smith: dysfun: in this room, 10 years from now "hey I want to try clojure, does it have a lumo build plugin?"

22:58 iannnn: hiiiiiii

Logging service provided by n01se.net