Fork me on GitHub
#clojure
<
2017-06-19
>
Alex Miller (Clojure team)00:06:51

I don't know about the talk but there are ports to Ruby and JavaScript that I'm aware of

donyorm00:06:33

What options do you to do desktop GUI programming in clojure? I've seen a couple options like clojurefx and fn-fx, but they don't seem to be very active.

yegortimoshenko02:06:18

@donyorm: you might want to check out my ui.swing library, i've done a fair share of projects with it recently. it uses Swing, and requires that you learn how to use MiGLayout. https://github.com/yegortimoshenko/ui.swing

sophiago02:06:48

Is there a way to have one field of a record refer to another one of its own fields? Dare I say, like this or self?

joshjones02:06:25

@sophiago what's the use case?

sophiago02:06:44

Complicated... but I have three fields in my record: one that stores a function, one a list of arguments, and the third that function applied to the list of arguments

joshjones02:06:44

so where does the field referring to the other come in?

sophiago02:06:57

Well, when I want one of the fields to be like #(apply f (:args this))

joshjones02:06:25

when do you set the function and arguments? once, at record creation?

sophiago02:06:51

The function at record creation. The argument field is intended to be modified

joshjones02:06:41

so just have a function that sets the arguments, and modify your third field when you set them ..?

sophiago02:06:01

I'm confused about what you're asking

joshjones02:06:29

(defn set-func-args
  [your-record args]
  (-> your-record
      (assoc :args args)
      (assoc :weird-field #(apply (:f your-record) args))))

sophiago02:06:29

That implies it's already been interned

joshjones02:06:55

yes, you're giving it a record which already exists. which you create with something like:

(defn my-record-constructor
  [f args]
  (->SophiaRecord f args #(apply f args)))

joshjones02:06:05

where SophiaRecord is (defrecord SophiaRecord [f args func])

sophiago02:06:09

I'm confused as to how either of those examples access one field from another

sophiago02:06:27

After you create that record it won't update the third field when the second one is updated...

joshjones02:06:52

records are like maps; immutable data -- if you "update" the second field via the function designed to update it (`set-func-args`), then the third one will be updated. essentially, you're creating your own interface to the data.

joshjones02:06:42

I guess you could also use watches

sophiago03:06:23

Yes, if I update one field then another one that references it will be updated. But you examples don't reference other fields. They just take the same initial arguments...

joshjones03:06:41

what's the advantage of adding state, instead of immutable data, for your case?

qqq04:06:11

with buddy-auth, how do you revoke JWT tokens ?

thedavidmeister05:06:50

@qqq what do you mean "revoke JWT tokens"?

qqq05:06:37

when the user logouts

qqq05:06:39

all tokens should be revoked

qqq05:06:45

and we issue new tokens when the log in again

thedavidmeister05:06:47

long story short

qqq05:06:55

however, with these signed / encrypted tokens, I don't see how to revoke

thedavidmeister05:06:58

JWT tokens are immutable so they aren't revokable directly, they only expire

thedavidmeister05:06:11

you can maintain a blacklist if you like

thedavidmeister05:06:17

but that introduces state into your app

thedavidmeister05:06:56

recommendations i've seen from ppl like auth0 is to set a shortish expiry time and periodically renew tokens silently in the background to keep users logged in

qqq05:06:15

alright, thanks for confirming

qqq05:06:20

that's what I thought: if you want to revoke, you need to maintia a map

qqq05:06:22

==> stateful

qqq05:06:30

if you don't maintain state, the best you can do is expiration based

thedavidmeister05:06:32

yes, the whole idea of "revoke" is state

thedavidmeister05:06:08

i don't see how you express the idea of "revoking" something without state

qqq05:06:23

it's kind of funny how you can 'grant without state' (by providing a new piece of info to the client), but youcan't revoke w/o state

qqq05:06:41

what's a reasonable token life time? 1 minute? 10 minutes?

thedavidmeister05:06:05

i suppose that the "info available to the client" is state in a sense

thedavidmeister05:06:27

the problem is more that you cannot trust the client to change that particular state in the way you want

thedavidmeister05:06:58

you can ask them nicely to forget the token, but what about people they gave it to, and so on?

thedavidmeister05:06:32

i think auth0 suggest like an hour or so

qqq05:06:36

right, therefore only option is expiration

thedavidmeister05:06:40

they have an article somewhere that goes through all this

thedavidmeister05:06:53

their system does maintain a blacklist when you call logout

thedavidmeister06:06:03

but they also have a "renew" endpoint

thedavidmeister06:06:06

they give you both options

qqq06:06:28

alright; I think IK understand the auth tradeoffs now; thanks for the discussion

thedavidmeister06:06:45

it basically has to be short enough that you feel comfortable that it is "too hard" for maliciousness to occur

thedavidmeister06:06:03

but not so short that basic network/downtime issues are going to suddenly log users out without notice when they fail to renew

thedavidmeister06:06:41

and i think that really comes down to what you're trying to build

qqq06:06:31

I can set it at 10 mins

qqq06:06:39

and have the client re-new whenever it has < 2 mins left

qqq06:06:29

so a soken ends up being Encrypt(Key, {:logged-in-as "thedavidmeister" :expires-on "timestamp"})

qqq06:06:50

and anytime the client wants, if the timestamp hasn't expired, I'll add 10 minutes from the current time

thedavidmeister06:06:01

well, you get a new token

qqq06:06:07

right, new token

qqq06:06:20

thanks for working this through with me; very helpful

thedavidmeister06:06:02

hah, i have all the same problems

thedavidmeister06:06:14

worked through some of it, still have some things outstanding to sort out "one day"

stathissideris14:06:45

is there any (easy) way to read 1.9-style EDN (with #: in front of maps) in 1.8?

bronsa14:06:16

use tools.reader

shader15:06:29

hello all; what's the right way to iterate through a sequence for side-effects, while using an index counter? I'm trying to make a macro that defines a set of related functions given an array of their names and argument types, injecting a sequential number based on the index of the pair in the array

potetm15:06:23

lol one word

potetm16:06:20

Something like (doseq [[idx val] (map-indexed vector my-super-list-of-stuff)] (do-stuff idx val))

noisesmith16:06:44

if it’s actually an array, dotimes is a good option too

lvh16:06:07

If you use Docker + Clojure, you might be interested in the new upcoming (currently beta) Docker feature called multi-stage builds, which let you easily run your uberjars in a tiny, JRE-only container. I wrote a blog post about it here: https://www.lvh.io/posts/smaller-clojure-docker-builds-with-multi-stage-builds.html

okwori16:06:29

Is there any easy work-around when facing dependency cycle issue or it has to be a one way traffic.

okwori17:06:13

For example: Say the ns: somepj.googlemap.core is using somepj.helper.core and some fn in helper.core now needs to be use some fn in googlemap.core. You will get Dependency Cycle problem every-time after you :import the namespace googlemap.core. A workaround would be to use a fully qualified namespace where you needed to call a fn in the helper.core... Am I right by this assumption?

madstap17:06:49

One solution is to just dump everything in one big namespace, then if necessary use declare if you have two fns that depend on each other. Another is to factor the shared stuff out into it's own namespace and have the other namespaces depend on that. AFAIK your workaround won't work.

madstap17:06:26

It indeed needs to be one-way traffic between namespaces, inside one you can use declare.

okwori17:06:20

@madstap Well, I did try and it works. The work-around I mean. e.g calling somepj.googlemap.core/somefn works within some function in helper.core

madstap17:06:57

@simon huh, ok, that is surprising to me

noisesmith17:06:42

using fully qualified names works if someone else ensured the thing would be defined, but it’s definitely a code smell

noisesmith17:06:26

the pattern I often end up with is a protocols namespace that everyone uses, an implementation namespace that makes functions that implement the protocols / multimethods / whatever and a client namespace that uses the functions defined in the protocols namespace

noisesmith17:06:12

there is no reference to client in implementation, and the only reference of implementation in client is to instantiate something that implements the protocols / multimethods

noisesmith17:06:59

what this turns out to be concretely is that every implementation can safely use the abstractions of every protocol without circularity issues, and the client can freely intermix those implementations.

pradyumna17:06:32

Is there a way to create a uberjar containing all dependencies, but not the current project?

integralist17:06:34

Hi, I'm trying to understand whether a failed agent can be automatically restarted. It doesn't appear so from my code example:

(def a (agent 0))

(defn h [a e]
  (restart-agent a 0))

(set-error-handler! a h)

(send a inc) 
;; 1

(send a #(/ % 0)) 
;; error handler h will be triggered

(send a inc) 
;; ArithmeticException Divide by zero (agent didn't restart)
Am I missing something?

noisesmith17:06:59

@pradyumna the simple but slightly hacky way would be to make a new project with the same deps but no source code

tanzoniteblack17:06:04

“hacky” in a different way would be to have something modify the project.clj to have empty vectors for both the src and test directories

pradyumna17:06:43

Interesting..

noisesmith17:06:45

oh yeah, you would need the ^:replace metadata for that

pradyumna17:06:00

is it also possible to override some of this using env vars

pradyumna17:06:48

Otherwise I can keeps two copies of project.clj

gaverhae17:06:59

What about a profile that ^:replaces the src and test vectors?

pradyumna17:06:25

Oh ok. I got it. I can choose the profile in command line. Yes. Thanks

gaverhae17:06:55

Something along the lines of:

:profiles {:shell {:source-paths ^:replace []
                   :test-paths ^:replace []}}
then lein with-profile +shell uberjar? (completely untested)

tanzoniteblack17:06:37

also…why do you want this? (out of curiousity)

gaverhae17:06:04

Also, if you got hat route you'll probably want to add a :uberjar-name entry to that profile, to avoid confusion

pradyumna17:06:30

I have to deploy to Azure cloud the complete uberjar using git.

pradyumna17:06:07

And it takes up too much space after many revisions

pradyumna17:06:43

Majority of this is dependencies

pradyumna17:06:56

Actual change is small

gaverhae17:06:24

If you're using git to deploy binaries (which doesn't seem like a great fit), you can also just have a branch with just that one version that you force-push, as an alternative

hiredman17:06:49

stop using git for that, use something that actually can do binary diffs http://www.daemonology.net/bsdiff/

gaverhae17:06:37

That may be a constraint of the environment you can't change, but yeah, I would also urge investigating that first

pradyumna17:06:44

Well that's the only with Azure for my case

gaverhae17:06:46

git is definitely not suited to holding changing binary files

pradyumna17:06:10

the other option is ftp, but I haven't tried that

ghadi17:06:28

take a sha512 of the binary, push it to Azure Blob Storage, commit the sha512 or url to the repo

pradyumna17:06:09

wow, I need to check that out

gaverhae17:06:55

I have zero experience with Azure, but it feels unlikely there would be absolutely no way to push your source git repo and have it build the uberjar itself? Presumably it has Java installed anyway so it should be able to run leiningen?

hiredman17:06:33

using git for deploys, building artifacts when deploying, everything is terrible

pradyumna18:06:28

I know. But I am trying to sneak in clojure wherever possible to my office. I have make it work to show them that clojure is a viable and good alternative

gaverhae18:06:37

Are the rest of the projects using the JVM?

gaverhae18:06:46

If so, how do they deploy?

pradyumna18:06:07

No they have node js

spei18:06:23

wouldn't clojurescript be a better alternative?

pradyumna18:06:31

I have built one of the service

gaverhae18:06:39

cljs compiled for node seems like a better approach then?

gaverhae18:06:03

You could even convince them they can bring over all of their knowledge of libraries and stuff around node

tanzoniteblack18:06:15

@pradyumna is the node.js code checking in npm_modules?

gaverhae18:06:43

I guess having the compiled js code in git would still not be ideal, but at least it's text and git should be able to make some sense of it

tanzoniteblack18:06:02

it’s just relying on a grunt task, or similar, to do a yarn/npm install, package, and then push it to Azure?

pradyumna18:06:57

yes, the npm run is done by the Azure deployment step

pradyumna18:06:16

You just push the project

tanzoniteblack18:06:31

and the resuling .zip that includes all the libraries and code isn’t checked into git, right? So why do that for the clojure version if that’s already not something they’re used to?

tanzoniteblack18:06:16

(I mean…yes, ideally you’d build these uber-jars and push to s3, or some other place, to store the built code with fetched libraries for repeatable deploys…but I’m trying to be realistic here 🙂 )

pradyumna18:06:27

That can be next step. I would definitely like to improve the build and deploy process

pradyumna18:06:54

so far this was what I could think of and get going

hiredman18:06:13

if you don't want to single handedly go in and fight that battle, you might want to look at something like https://github.com/technomancy/lein-tar (not sure if the plugin still works)

hiredman18:06:41

or even instead of checking in the uberjar, check in the exploded uberjar

hiredman18:06:48

java -cp foo.jar whatever and unzip foo.jar && java -cp . whatever are more or less equivalent

pradyumna18:06:14

Sure I'll try it out

hiredman18:06:21

and git would likely be happier with the diffs from the exploded uberjar

pradyumna18:06:49

Thanks a lot for all your ideas and showing so many options. Tomorrow I 'll check them out set the deployment steps in a better way.

gaverhae18:06:47

If you have npm working in Azure, what about a custom library? If you can currently use custom JS libs through npm, it may be a much easier sell to compile your cljs code down to a node.js library that you just package and put on some private npm repo, and have a very small js shim that you deploy normally

pradyumna18:06:56

I haven't yet tried clojurescript for node

pradyumna18:06:30

Only done some reagent

gaverhae18:06:58

I haven't done that either, but if you're trying to introduce Clojure to a node.js shop I think a ClojureScript lib packaged for npm is going to be a much easier sell than making them use the JVM

pradyumna18:06:28

Actually nodejs itself is new here. First time going for cloud

gaverhae18:06:07

Well, you definitely know more about the environment than I do 🙂 Just putting this out there as yet another option to consider: if your current deployment pipeline supports node.js projects with npm, packaging your clojure code as a cljs lib for npm might be the easiest route, ops-wise

pradyumna18:06:58

sure, I just need to explore more on that avenue.

hoff21:06:42

is there any simple library support for 3d plotting as in matlab?

bradford22:06:12

Is there an int that works on strings, but returns the value if it's already an int? I don't want to have to write logic around Integer.parseInt

bradford22:06:26

'cuz that seems like that should already be solved. otherwise I gotta check types and it feels non-clojuric. (I have to do this for a java API)

ghadi22:06:12

it's non-clojurey to have magic functions that do two things instead of one (at least in the core library). write the conditional and keep going simple_smile

bfabry22:06:42

it might be a pointer that you're doing something else un clojurey too btw. generally you want to separate things that are different, not treat things that are different as the same, if you get my meaning. so it might be an indication that two things that are actually different have been put together prematurely

ghadi22:06:43

there's not even a function in the core library that does one of things (parseInt)

hiredman22:06:17

user=> (bigint "45")
45N
user=> (bigint 45)
45N
user=> 

ghadi22:06:14

wow that reflects?

hiredman22:06:20

The docstring says coerce and not cast, so is that undefined behavior or not

bfabry22:06:29

that's not a clojure decision fwiw, that's just the java BigInteger constructor

hiredman22:06:56

one wonder more

hiredman22:06:00

user=> (type (bigint 45))
clojure.lang.BigInt
user=>

bfabry22:06:38

isn't that expected?

hiredman22:06:09

it is, just one way to read what you said implies expectation of a java BigInteger

hiredman22:06:47

at some point, we (as an industry? a discipline) really lost a handle on the lexicon of different ways to interpret a value as some other value

bfabry22:06:01

well... it is, it's just clojure wraps java BigInteger's in BigInt 🙂

hiredman22:06:03

casting, coercing, parsing, interpreting

hiredman22:06:23

somewhere between php and js

bbqbaron22:06:11

the answer makes sense

bbqbaron22:06:11

i think the trick is that without a static type system, you can’t really cast the normal way. you can either coerce or convert, right?

hiredman22:06:36

see, to me, casting means reinterpreting the bit pattern, and that is it, which is not what that stackoverflow says

bbqbaron22:06:10

FWIW i had the same intuitive reaction: casting keeps the memory the same but changes the mapping over it, while conversion uses a different memory representation

hiredman22:06:21

but the most common casting related question I see is "how do I cast this string to some number type"

noisesmith23:06:40

isn'tit the case that in c, cast is "host to interpret these bits" while in java, it's more like "which superclass or subclass of this nominal class should we use for method lookup"

noisesmith23:06:36

I mean, by the official language definition of cast (and ignoring obviously wrong things like cast "5" to int when you really mean mapping or something)

bbqbaron23:06:02

i think that fits the SO answer, since the java cast is still a directive to “just change its type”

bbqbaron23:06:42

“no, i didn’t call a conversion function; it’s just different now.”