Fork me on GitHub
#clojure
<
2017-02-14
>
nuo.li07:02:07

Can I ask a question about clojure.spec? I am now using multi-spec, considering different ways to categorise pills, the spec growing exponentially. Is there something like interface in clojure.spec? So that I can define a spec which implements several interfaces.

qqq07:02:08

1) I think most people are asleep. 2) Can you give a concrete example? three backticks = pastes code

lmergen07:02:00

Europe is awake already :)

ponelat07:02:16

and Africa* 🙂

qqq08:02:12

2/8631 🙂

qqq08:02:19

I do have a question -- perhaps you guys can help me

qqq08:02:11

what I love about emacs is C-h f , writing elisp code, then C-x C-e. I now want to switch to a full cljs solution and I'm looking at nightlight, nightcode, lighttable, and atom -- and I'm curious which one gives me the most "ability to be configured/programmed/extended in cljs" ?

qqq08:02:21

that's basically the single, unique metric which I"m picking my next editor on

qqq08:02:26

^^ going to sleep now; for anyone answering the above "what editor/ide is most extensible in cljs", please feel free to direct-message me, I want to make sure I read your response and might miss it in the log

qqq08:02:40

poking around at the sources, it seems like nightlight = clj + cljs, lighttable = cljs, atom = coffeescript?

aleksanders09:02:42

qqq: I don't think it's very actively developed for some time

qqq09:02:48

@U071E81KK: that is my impression indeed, I think I'll go atom -- which is too bad, I'd really like cljs all the way down instead of coffeescript

aleksanders09:02:38

It might sound like heresy but you can also take a look at Visual Studio Code. If I wasn't using Vim thats where I would look.

sbauer10:02:03

For what it is worth, light table is still being developed but atom would be a better choice for your needs at the moment

qqq11:02:20

@U071E81KK: I currently have ~ 1K LOC emacs config; nothing but "replace elisp with cljs" would get me to switch

qqq11:02:54

@U08CH3K54: any idea what the roadmap is? I took a look at it, and it seems to be "we're in a shitty state; we need better docs, or else no one else would contrib" -- this amkes me sad, as I'd really prefer to do pure cljs instead of atom/coffeescript

sbauer12:02:25

That's about it, light table needs docs and some dependencies updated otherwise it won't be attractive for new people to contribute to

sbauer12:02:36

Docs are ongoing, as well as updating dependencies, but it all takes time to do

qqq12:02:11

I think the thing that concerns me most

qqq12:02:43

is that the Eve blog post is basically "the future of programming is something that clojure can't do" so we're off to build a new IDE / language at this point, I can't see how there'd be time for clojure at all

sbauer12:02:42

Oh, the project was open sourced and Chris granger has little to no involvement at this point... It is now community managed

qqq12:02:28

right, saw the code, which is what got me excited at first since it was cljs all the way down

qqq12:02:53

but given atom has more ppl and lighttable lost it's lead dev, it's hard to see it compete, just on man power

sbauer12:02:44

Completely valid point

sveri09:02:03

Hi, does someone know about a helper library that has if-empty? that works like if-let but checks for empty instead of nil?

stijn09:02:53

@sveri: what about (if-let [a (seq the-thing-that-should-not-be-empty)] ...) ?

sveri09:02:47

@stijn Cool, I did not know that. Although I would prefer an if-empty? as it is more clear in its intent. Converting into a seq first seems a bit "hacky".

qqq09:02:31

@sveri: I'm not a fan of code that pulls in an entire jar for a single function. 🙂

sveri09:02:06

Hehe, I am not a fan of rewriting stuff again and again 🙂

qqq09:02:24

I was going to make an argument about how pulling in a new library in CLJS slows down the load time, and multipled by millions of users / day = # of human lives wasted --- but then I realized, closure agressively elimiinates dead code

sveri09:02:14

Hehe, I hear you talking about flash here 😄 If you are concerned about load times and stuff I would argue to not start with cljs / javascript at all and add it only if there is a real need for it.

qqq09:02:44

I started caring about # of jars since # jars greatly afected my "gae deploy" time, and as it turns out, for my server side I've even ripped out ring -- right now, for my gae apps, on server side, only dependency = clojure itself 🙂

sveri09:02:15

Hm, I wonder how GAE works in that regards. What exactly is deploy time for you? Upload + restart of the application?

bfabry09:02:03

@qqq is there no way to specify files that GAE instances always have access to?

qqq09:02:06

@svrei @bfabry: a gae deploy is: 1) create a giant WAR 2) google uploads it 3) if you app has no request for past 10 mins, it dies; and on new request, GAE has to fire up a new JVM + load all your ajrs

qqq09:02:48

and for whatever reason, cutting down to depending only on clojure (ripping out ring, compojure, and whatever else) has reduced my "create this war and upload it" time from tens of seconds down to seconds

qqq09:02:09

btw, atom is beautiful; I think I'm switching

sveri09:02:31

Hm, I see. One more reason not to use GAE. Although from an economic point of view it surely makes more sense to shutdown instances that are not used.

bfabry09:02:46

yeah what I meant was can you put your dependencies in a gcs bucket and manipulate the classpath or something. anyway sounds like you have a solution

sveri09:02:02

Btw. how did you rip out ring and compojure? Just remove the jars and code everything yourself?

qqq09:02:37

so Im reading this book on GAE dev with java

qqq09:02:51

that book doesn't use ring or compojure; it just extends javax.servlet.HttpServelet or something

qqq09:02:57

and I just converted the code line by line into clojure

qqq09:02:05

so now I know about things like doGet and doPost

sveri09:02:16

I see. I liked to do this kind of stuf too, years ago. Today I am more concerned about developer productivity. Which is raised by well designed and tested libraries and readability. There are like several million edge cases I will not think of myself. But by using libraries that are used by many other devs, chances are a lot more edge cases have been covered already. Btw. I am not talking about the npm ecosystem that might have taken this to the extreme 😄

qqq09:02:04

@sveri: for anything besides AWS Lambda and GAE, I would agree with you; for these two, I think as small a footprint the better

qqq09:02:48

IIRC, your hosting on some 16-core 1TB RAM monster machine; so having a few extra jar lying around doesn't matter; whereas for me, these jars for some stupid reason, slow down both (1) deploy to gae and (2) firing up JVMs

ponelat09:02:06

@qqq take a look at proto-repl ( an atom plugin )... lots of fun

sveri09:02:13

🙂 We agree, basically. Maybe you want to look into clojurescript on npm:https://yogthos.net/posts/2016-11-30-Macchiato.html @yogthos started working on that

sveri09:02:22

Not sure if that works on GAE.

sveri09:02:06

Also nice: https://code.google.com/p/googleappengine/issues/detail?id=7706 > Hi #42. It doesn't seem that this will be ever fixed, as this post is from 2012 and affects ALSO the python instances. If they can't make python to boot fast, it won't ever work for java as well.

qqq11:02:31

@sveri: nice to know they still havne't fixed it in 2017, 5 %&#* years later

qqq11:02:14

someone needs to find who thought it was a good idea to have a jvm run in 512 MB RAM, and fire that person 🙂

bfabry12:02:41

my guess if you were to ask that person the answer would be "it wasn't designed with loads low enough that warmup time mattered in mind"

qqq12:02:44

"if your app can go for 10 minutes without anyone making a request, you don't need google scale"

qqq12:02:28

I don't know how big the JVM is, but if it takes up 256 out of the 512 MB, it's as if the machines are operating at half effiiency (compared to say, one beefy machine)

sveri12:02:11

I would assume its not the the RAMs fault. RAM access should be fast enough and you can fit a lot of stuff into 256 MB, also in the Java world. From the ticket it reads like they transfer data over the wire and this is what makes the class loading take so long. But I am just guessing here. Also, after reading half of it, I just cannot see why I would use GAE for small scale java projects that are "large" enough to take more than 60s to load on GAE, which means, it does not start at all. So I am picking a cheap instance just to have it not work, which forces me to take multiple small instances and hope enough are up or pick fewer large instances and pay more. I mean, any VPS for a few bucks will just hold your service in memory and you have no startup time at all, except on redeploys of course.

sveri12:02:16

Although, even transferring a few 100 classes over the wire should be done in a few seconds and not minutes

gfredericks12:02:53

@genec are you sure the class name syntax you're using is supposed to work? my guess is that core.match thinks Zero is just a local name you want to use; e.g., if you replace "Zero" with ["I'm in this part of the code and the Zero is" Zero], what do you get?

genec12:02:01

@gfredericks ["I'm in this part of the code and the Zero is" brave_and_true.utils.Zero] hmmm, I see what you mean. Are you using something else for pattern matching?

gfredericks12:02:33

no, I just don't need it much; destructuring covers most of the use cases

genec12:02:04

I've implemented everyting with cond, but thought pattern matching would be nicer (coming from F#/OCaml)

mpenet12:02:27

if you only test for one thing cond(p) is probably a better choice anyway

mpenet12:02:52

(condp (type x) = ...)

genec13:02:30

@gfredericks @mpenet i agree, but i'm matching on a whole set of contract records with different fields. thanks for your help, really appreciate it. i'll stick with cond for now though, since it works fine

mpenet13:02:52

then it would make sense yes

genec13:02:58

@mpenet i didn't know about condp though, thank you for that!

mpenet13:02:27

I guess that would be it. It's actually very similar to the ocaml syntax

genec13:02:33

yes, i think i was leaving out the :or keyword

plins13:02:38

hi everyone, im having trouble while generating an uber for my compojure application

plins13:02:01

everything works normally with lein ring server

plins13:02:26

but when i try to lein do clean, ring uberjar

plins13:02:40

it complains docjure cant be found

Compiling excel-service.error
Compiling excel-service.handler
java.io.FileNotFoundException: Could not locate dk/ative/docjure/spreadsheet__init.class or dk/ative/docjure/spreadsheet.clj on classpath., compiling:(xlsx.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate dk/ative/docjure/spreadsheet__init.class or dk/ative/docjure/spreadsheet.clj on classpath., compiling:(xlsx.clj:1:1)

danielgrosse14:02:58

Is it possible to define a function in a def which is called, eveytime the def is referenced?

danielgrosse14:02:19

e.g.

(def id (rand-int 1000))

arttuka14:02:59

well, that’s called a function and you define those with defn 😉

danielgrosse14:02:08

@arttuka I assumed so. Thank you

rickmoynihan15:02:30

@plins: could be a profile issue - check for differences between profiles

plins15:02:42

@rickmoynihan , thanks, they were declared inside the dev dependencies

rickmoynihan15:02:50

cool glad it worked

john.carnell16:02:50

hey guys I have a map data structure with maps within it and I need to replace any nil values with empty-strings. Any suggestions

joshjones16:02:19

are the nested maps infinitely nested, or just one level?

john.carnell16:02:18

Can be multiple levels of netsting

nathanmarz16:02:34

@john.carnell can brute force it with Specter with: (setval (walker nil?) "" my-map)

john.carnell16:02:53

Cool thank you

joshjones16:02:25

(defn nil->string
  [m]
  (f/fmap #(if (map? %)
             (nil->string %)
             (if (nil? %)
               ""
               %))
          m))

nathanmarz16:02:34

can do it more precisely and more efficiently by defining your own recursive navigator

joshjones16:02:38

where f/fmap is clojure.algo.generic.functor/fmap

joshjones16:02:21

just require [clojure.algo.generic.functor :as f :only [fmap]] @john.carnell

john.carnell16:02:44

Will give it a try

joshjones16:02:53

(nil->string {:a nil :b {:x 42 :y nil}})
=> {:a "", :b {:x 42, :y ""}}

joshjones16:02:16

and fmap is defined simply as: (defn fmap [f m] (into (empty m) (for [[k v] m] [k (f v)])))) in https://github.com/clojure/algo.generic/blob/master/src/main/clojure/clojure/algo/generic/functor.clj#L33 , a very useful function

Sam H16:02:44

you could use clojure.walk/stringify-keys and modify to your problem:


(defn nil->empty [m] (let [f (fn [[k v]] (if (nil? v) [k ""] [k v]))] (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
^^ seems to work, only did a quick test

schmee17:02:47

shan your nil->empty example is the reason specter exists 🙂

Sam H17:02:54

schmee: I see, I've only heard specter mentioned but never read/looked into it. I should have a look at it

schmee17:02:38

yeah, it makes functions like that much easier to deal with

adamkowalski18:02:14

Does anybody use docker to containerize their development environment with clojure?

pesterhazy18:02:53

IMO there's little reason to do that normally, because Jars are already containers and the JVM runs everywhere

adamkowalski18:02:51

Well I am hoping to create an environment that has all the tools I need to be productive and allows me to sit down on any machine and have access to them

adamkowalski18:02:10

I was thinking that with docker I could package up emacs in one container, and then jvm + boot in another

adamkowalski18:02:28

then run the boot repl with some port exposed on the container, and connect to it in the emacs container

adamkowalski18:02:06

Then I could regulate the versions of everything, and make sure that things are not different on dev then they are in qa or prod

pesterhazy18:02:08

you can already do that

adamkowalski18:02:08

But for whatever reason, when I tried to do it getting the repl open in one container and connecting it to another isn’t working out to well

pesterhazy18:02:17

you can specify the boot version in boot.properties

pesterhazy18:02:43

the only variable left would be the JVM version used

pesterhazy18:02:04

and the JVM is a mighty ship of compatibility

adamkowalski18:02:11

what do you think about the micro service architecture? where you can mix many different languages, and want to have a uniform strategy for deploying code into the wild regardless of what stack that developer decided to use.

adamkowalski18:02:09

I feel like there is something to gain by dockerizing your workflow, as tools like kubernetes, or docker swarm let you handle the dev ops part of your system in a way running raw on the machine seems really difficult. But i’m curious if you’ve had a different experience?

tbaldridge18:02:39

Mixing "many different languages" is a recipe for failure, imo.

tbaldridge18:02:08

Microservices in general however seem to be a good idea depending on the situation.

adamkowalski18:02:22

Well if every service just agrees to a standard data format like edn or json why does the implementation matter?

adamkowalski18:02:52

At that point they are just swappable components as long as they maintain faithful to the previous api

hiredman18:02:53

I think the way I would put it is, people have a hard enough time getting stuff to work correctly using a single language

schmee18:02:14

arguing against using multiple languages seems like arguing against clojure to me

schmee18:02:36

noone is going to switch their entire stack to clojure if they’re using something else, the only way to make headway is to do it in steps

hiredman18:02:14

plenty have

adamkowalski18:02:06

I feel like it is a lot easier to convince the team to just write one component in a new language rather then rewrite the entire app in clojure

adamkowalski18:02:24

then if things go well you can slowly bring it in more places

adamkowalski18:02:41

convincing the devops guys to learn new build tools is a hard sell

hiredman18:02:49

but "hey aren't we all so cool, lets just write everything in whatever language" is very different from "lets look at language X"

adamkowalski18:02:07

well sure you can evaluate many different languages

adamkowalski18:02:20

but unless you are greenfielding a new project, you have legacy code

plins19:02:50

just did that, implemented a new microservice using clojure instead of java, and I'm never going back 😛

tbaldridge19:02:53

And I can sit here and tell you horror stories of people that use: Ruby, Python, Elm, Scala, Go, Rust, Java, Clojure all in one project.

tbaldridge19:02:19

A few languages is fine, more than 2-3 and I think it's time to have a intervention.

tbaldridge19:02:51

Even more so if the languages overlap. So IMO, a codebase in Java, Clojure, and Python isn't nearly as bad as Elm, Dart, and ClojureScript 😉

sgerguri19:02:58

These days it's easy to get 2 automatically - JavaScript on front-end and whatever you're using on backend.

sgerguri19:02:58

That said I think my place is currently in a situation where a previous monolith used Erlang but having finished a first-pass splitting into services we'd be better served with Clojure.

hiredman19:02:26

you almost always have a frontend team, which is js+otherlang and a backend team which may user otherlang but may use otherlang'

qqq19:02:28

perhaps we could invent a Universal Machine, say, let's call it a "Turing Machine" -- then we (1) make sure Turing Machines run on every existing language (2) all existing languages can . emade to run on this "Turing Machines" problem solved //sarcasm

dpsutton19:02:53

since there isn't infinite tape, i say we all just go to the beach

sgerguri19:02:08

Now there's an idea, @dpsutton!

tbaldridge19:02:32

This slack needs a place to put out-of-context quotes, and I nominate that one as the first one.

arrdem19:02:13

I’ve been maintaining a couple fortune files of quotes, could be pursuaded to throw up a git repo 😛

mobileink23:02:58

@qqq: except that Turing Machines are useless, since they cannot do IO. Actual useful programming languages would just befuddle them.

mobileink23:02:30

TM computability is special case

mobileink23:02:43

I suspect no existing (useful) programming language could be run on a TM.

mobileink23:02:01

@tbaldridge : ok, tell us some horror stories! simple_smile Seriously, it strikes me as a mgmt problem not a technial one. if you can manage 10 different teams programming microservices in 10 different languages, you win.

mobileink23:02:45

i would not want to try it, but microservices do open up possibilities for staffing. i might hate php, but if it's a lot easier to find php programmers than clojure programmers, why not give them a microservice to implement?

tbaldridge23:02:52

Sure, if the teams were completely isolated, but that's not the case most of the time. A single team may be responsible for a dozen microservices, and have a different language for each would be an nightmare

qqq23:02:30

isn't that precisely how amazon is run?

qqq23:02:38

"you only get to expose an API", everything else is hidden

tbaldridge23:02:39

Not only do devs have to context switch more often, but it further narrows your talent pool by requiring that you hire devs that share the intersection of all the teams you have in place.

tbaldridge23:02:55

@qqq never assume what works for a mega-corp will work well for a startup.

mobileink23:02:07

ah, reality rears its ugly head!

tbaldridge23:02:14

And once again, they probably have a few dozen engineers for each service

qqq23:02:10

lol, I heard the GOOG solution to "the cpu doesn't do this is" (1) call up intel (2) tell them if they don't add this instruciton, we're ordering from AMD

timgilbert23:02:48

Hi all, I feel like I must be missing something obvious in the standard library. I find myself doing this a lot:

(into {}
      (for [{:keys [:product-manufacturer/slug] :as m} manufacturers]
        [slug m]))
...so I've got a seq of maps, and I'm pulling out a single field of each map to construct a map from that one identifying field to the whole map that was in the seq. Is there a more elegant / concise way to express this?

mobileink23:02:24

tried that, they won't take my phone calls.

qqq23:02:13

well, for phone calks, you probably want a waterproof case

qqq23:02:19

@timgilbert: so you want a map where key = (:foo m) and value = m ?

qqq23:02:10

(into {} (map (fn [x] [(:foo x) x]) manufactuerers))

qqq23:02:14

eh, not sure is that's better

qqq23:02:50

for my persona use, I have a function m-map, where (m-map f lst) = (into {} (map f lst))

bfabry23:02:12

@timgilbert assuming I have specter I would (s/transform sp/MAP-VALS first (group-by :product-manufacturer/slug manufacturers))

bfabry23:02:36

you could also (into {} (map (juxt :product-manufacturer/slug identity) manufacturers))

qqq23:02:42

bfabry++ , the use of juxt is brilliant

qqq23:02:13

I've always been angry I can't write #([f1 %, f2 %]) -- and (juxt f1 f2) is precisely the solution ot that problem

mobileink23:02:34

(map #({(:foo %) %}) m)? untested. never mind, that'll teach me.

bfabry23:02:53

that won't work, trying to use a map as a function with zero arguments

bfabry23:02:07

yeah qqq juxt is a nice one to remember. there's a few higher order functions like that that are easy to forget. juxt, constantly, complement, fnil, every-pred, some-fn. all super generally useful

timgilbert23:02:41

I feel like I always forget precisely what juxt does about 3 minutes after I read its documentation

bfabry23:02:37

personally I forget fnil, I always confuse (fnil f foo) with #(or (f %) foo)

timgilbert23:02:33

Hmm, thanks for the advice. I'll think about the juxt one, not sure I like it better though

timgilbert23:02:00

I really like the idea of specter, but the all-caps conventions make me think it's always SHOUTING AT ME

arrdem23:02:10

hummmmm I wanna say there’s a (map-by :product-managers/slug manufactureres) that’s equivalent, but it may be in one util library or another not core