Fork me on GitHub
#beginners
<
2020-05-06
>
Mario C.00:05:26

It seems to be a common problem when working with SAML and redirects

include01:05:25

hi. I need a tiny tip. I can’t find any example (or if it’s even possible) to update ~/.clojure/deps.edn dep versions like we do with lein ancient to update .lein/profiles.clj

seancorfield01:05:22

deps-ancient is based on lein ancient but I don't think it updates the deps.edn file? Depot has both a report mode and an update mode so that may be what you're looking for.

seancorfield01:05:09

find-deps will also update your deps.edn file when you ask it for a new dependency which may also be useful.

seancorfield01:05:48

(personally, I don't want any tools to touch my deps.edn file -- I prefer report-only tools, and then I can change the file myself if I want to)

include01:05:14

@seancorfield always throwing great links 🙂 thank you very much. I was searching https://github.com/clojure/tools.cli but without success. Anyways, yes your tip is important regarding the report Vs actually update deps. In fact I am just keeping some deps under ~/.clojure/deps.edn because.. n00b and I want to keep an eye on couple projects. (side note: I am sliding a little bit to the yak shaving side 😕 )

seancorfield02:05:55

@include tools.cli is a library for processing command-line arguments (that I happen to maintain). tools.deps.alpha is the core library behind the Clojure CLI and deps.edn. brew-install is the Clojure repo that contains the actual scripts (`clojure` and clj) that wrap the t.d.a. libary. And for anyone on Windows wanting to try the Clojure CLI and deps.edn on PowerShell, see https://github.com/clojure/tools.deps.alpha/wiki/clj-on-Windows and in particular the last section that talks about Scoop (which I've found to be the easiest way to install/upgrade various Clojure-related tools).

include09:05:31

@seancorfield tools.cli will be very useful in my case. I am migrating some bash scripts to clojure (babashka) and I need to read args from cmdline; but I am still fighting with the basics. (and btw thanks for maintaining it 🙂) . Yes, I am using brew-install which is very useful and clean too).

include09:05:31

“murphy” (@UBL24PLE6 just posted another deps management tool in #announcements 🙂 going to check it too.

👍 4
ryan echternacht02:05:59

repl question: if I’m in ns A, and ns A requires ns B, and ns B requires ns C. if I change something in ns C, what do I need to do to get ns B to reflect these changes correctly?

ryan echternacht02:05:52

I know I can (require :reload …) but if I (require :reload B) will this pick up the new changes? do i need to reload C? do I need to reload C then B?

ryan echternacht02:05:44

currently I just reload like a madman and restart my repl if I can’t seem to get it to stick correctly (which is becoming less frequent, but still happens more than it should)

andy.fingerhut02:05:33

One option is only re-evaluating the def and/or defn forms that changed in ns C, assuming you know which ones those are. If those changes were made by you via a text editor on a file containing ns C, then presumably you know which ones you changed as you were changing them.

seancorfield04:05:28

@ryan072 I'll echo @andy.fingerhut here: if you always eval each top-level def/`defn` form as you change it, your REPL state will stay as fresh as possible and these questions will rarely come up. That said, if a def is used in another namespace, you will have to re-eval the forms in that namespace that refer to it (or reload the whole ns). The same goes for functions that are used as plain symbols in the non-function position in other code (if you use the Var form -- #' -- then changes will automatically be picked up, because of the extra indirection that the Var introduces). Another option is to do (require 'ns-A :reload-all) which will force a recompile of ns A and everything it requires transitively.

noisesmith15:05:42

> if a `def` is used in another namespace, you will have to re-eval the forms in that namespace that refer to it this is only true for forms that use the val of the def rather than the var, if you use the def inside a defn, it is re-resolved on each call and no extra reload is required

noisesmith15:05:29

def using another def directly would have this issue, yes

seancorfield16:05:03

Yeah, it got a bit complex and nit-picky to be truly precise about that so I (over-)generalized a bit. The truth is: if you're careful and know what you're doing, you can get away with minimal reloading when a definition changes; but it's also true that if you aren't/don't, you can get into trouble 🙂

noisesmith16:05:46

that's fair - related, I saw a bug where not defining an env var during AOT led to not seeing the config during prod runs, thanks to the env being looked up in def, I thought clojure prevented this sort of error - do you know anything about this behavir?

seancorfield16:05:01

something like

(def some-config (System/getenv "SOME_VAR"))
That would be executed at compile (load) time -- which is why anything side-effect-y (including reading from external systems) is dangerous in def forms. I'd use a delay here or make it a function (and "cache" the result somewhere else -- probably via Component).

noisesmith16:05:18

yeah, I thought I had heard that the compiled init for the ns would capture the body of the def, but I guess I was wrong

noisesmith16:05:32

agreed that delay or something like component / integrant is the right fix here

seancorfield16:05:11

I try very hard to ensure my def's only ever have either completely static content or else are bound to a delay or atom. And I try to keep them private, to avoid other namespaces from depending on them directly. Like all "rules" tho', I break these patterns "when appropriate" 🙂

noisesmith16:05:40

sounds like lisp :D

ryan echternacht01:05:24

And @seancorfield I know realize you are right — if I just eval defn’s as needed I should be good to go!

seancorfield04:05:36

I work in a REPL for days (sometimes weeks) and I eval every top-level form as I change it (without even saving) and mostly just invoke load file on my test ns after that and then run those tests (all hot keys in my editor).

clumsyjedi05:05:33

Question about reflection: In my repl I do this:

clumsyjedi05:05:36

dev=> (defrecord Foo [])
dev.Foo
dev=> (def bar ->Foo)
#'dev/bar

clumsyjedi05:05:40

How do I get the namespace and the protocol name of bar?

clumsyjedi05:05:08

eg, two strings "dev" and "Foo"

ryan echternacht05:05:52

@seancorfield for your comment about Var forms, are you saying that if I do something like

(defn a [] ...)
(defn b [] (b ...))
and if I re-eval a, then b doesn’t change (still uses the original a) correct? But if instead I do
(defn a [] ...)
(defn b [] (#'b ...))
Now b does a “live” lookup on a so if I re-eval a, b will see those changes automatically? And if I have this correct, is your suggestion to largely use the var form (for this benefit)? or when do you use it?

seancorfield06:05:51

That's b in the function position (where the indirection happens anyway, I believe).

seancorfield06:05:35

I was talking about non-function positions, where you pass a function as an argument. And also where you refer to a def directly.

Jim Newton15:05:02

I would like to contact someone named joinr. Does anyone know how to contact him? He is the author of https://github.com/joinr/clclojure

Alex Miller (Clojure team)15:05:10

he's on reddit a lot, same user name (I believe this is correct pronoun, but apologies if not)

Jim Newton15:05:53

Sorry, I'm not a reddit user. If I create an account, will I be able to send a message to a particular user? Or will I have to request a contact with him, and thereafter be able to send him a message?

Alex Miller (Clojure team)15:05:24

you can send a message I'm pretty sure

Ben Sless15:05:17

chat button on rhs

Jim Newton16:05:32

ah, but I have to have an account on reddit for that button to appear. I just figured it out. now I have 10,001 accounts on various social networks.

🙃 4
papachan14:05:02

why not writing him an email ?

Jim Newton15:05:20

Maybe he no longer wishes to be contacted?

simongray15:05:18

Reddit search is not for finding users, it's for finding content. This is his profile: https://www.reddit.com/user/joinr

dpsutton15:05:11

Git commits most probably have an email associated with the user?

Jim Newton16:05:53

what does {= ...} mean?

clojure-rte.core> (methods ty/typep)
{= #function[clojure-rte.type/eval337/fn--339],
 :default #function[clojure-rte.type/eval263/fn--264],
 :sigma #function[clojure-rte.type/eval247/fn--248],
 rte #function[clojure-rte.core/eval907/fn--909],
 satisfies #function[clojure-rte.type/eval319/fn--321],
 :empty-set #function[clojure-rte.type/eval255/fn--256],
 or #function[clojure-rte.type/eval305/fn--307],
 not #function[clojure-rte.type/eval275/fn--277],
 member #function[clojure-rte.type/eval353/fn--355],
 and #function[clojure-rte.type/eval291/fn--293]}
clojure-rte.core> 

hiredman16:05:31

it is a map with a key that is the symbol =

noisesmith16:05:32

that is a hash map, I guess someone used the symbol '= as a key

✔️ 4
noisesmith16:05:56

clojure doesn't have syntaxes introduced by a symbol inside a bracket

Jim Newton16:05:32

In a call to defmulti I can provide a dispatch function. That function normally returns some dispatch value which has been given on some defmethod. Is there a way for the dispatch function to return a value which tells the system, don't call any method?

Jim Newton16:05:05

Of course I can have some method with dispatch value :do-nothing, and just have the dispatch function return :do-nothing. Is that the correct way?

noisesmith16:05:30

that's the only option- there's also :default, which is calledfor every dispatch with no defined method, if it exists

Jim Newton16:05:05

Is there any way for the dispatch function to pass a computed value to the :default method?

noisesmith16:05:54

the default method would see the original args, and you could recursively call the method from within another method

Jim Newton16:05:46

no, I mean is there a way for the dispatch function to compute a value and pass to the method?

Jim Newton16:05:14

Because the ability to do that would mean it is possible to implement CL-like method combinations in clojure

noisesmith16:05:30

no, you can achieve that result by calling the same method again so the other dispatch is invoked

noisesmith16:05:44

but a dispatch only provides a value to match

Jim Newton16:05:21

ahhh, so I can just have the dispatch function always return :default, and have the default method itself call methods and dispatch to one or several of them?

Jim Newton16:05:32

that's perverse 🙂

noisesmith16:05:00

I was thinking more that an individual method would "cook" the args, then call the same method so it hits the other dispatch, for chaining

noisesmith16:05:46

classic "superclass delegation" but it's not restricted to going up the chain

Jim Newton16:05:51

does the language enforce any sort of argument-list consistency at the declarations of the defmethods ?

noisesmith16:05:19

they all need to accept the args that your dispatch function accepts, or you'll hit runtime errors

Jim Newton16:05:05

superclass delegation is a good example. The :default method could presort the methods and call the first method with a call-next-method which passes (rest sorted-methods) to the next method in the chain.

Jim Newton16:05:36

in my case I want all the methods called lazily and a value returned which is a function of the return values of all the methods.

Jim Newton16:05:50

i.e., a method combination

noisesmith16:05:42

multimethods aren't magic, you might have better luck with your own dispatch and registration functions

noisesmith16:05:59

if you do it right, they could build on top of defmulti for convenience

noisesmith16:05:27

more importantly than not being magic, they are just vars and hash table lookups, you can achieve the same thing in "user space"

Jim Newton16:05:36

yes that was my first implementation in fact. But someone suggested that I use (defmethod ...) which already knows how to associate functions with keys. and methods which returns that hash map

noisesmith16:05:32

you could do what defmethod does, and combine hierarchy definition and lookup via isa? with registration in a map

noisesmith16:05:48

I think making defmulti act with the semantics you expect is more complex than doing that yourself

noisesmith16:05:53

that link is broken

Jim Newton16:05:11

Can someone help me convert a set of functions/atoms into a more concise macro definition?  I'm writing the same function several times.

(def disjoint-hooks (atom {}))
(defn new-disjoint-hook 
  "Establish (or override) a named hook for use in disjoint?
  This is necessary because clojure multmethods do not support
  call-next-method.  We need several _methods_ to be called until
  one fails to return :dont-know.
  (new-disjoint-hook ...) establishes a new hook, which must designate
  a binary function which returns true, false, or :dont-know."
  [key hook-fn]
  (swap! disjoint-hooks (fn [_]
                          (assoc @disjoint-hooks key hook-fn)))
  (keys @disjoint-hooks))



(def subtype-hooks (atom {}))
(defn new-subtype-hook 
  "Establish (or override) a named hook for use in subtype?
  This is necessary because clojure multmethods do not support
  call-next-method.  We need several _methods_ to be called until
  one fails to return :dont-know.
  (new-disjoint-hook ...) establishes a new hook, which must designate
  a binary function which returns true, false, or :dont-know."
  [key hook-fn]
  (swap! subtype-hooks (fn [_]
                          (assoc @subtype-hooks key hook-fn)))
  (keys @subtype-hooks))



(def inhabited-hooks (atom {}))
(defn new-inhabited-hook 
  "docstring"
  [key hook-fn]
  (swap! inhabited-hooks (fn [_]
                          (assoc @inhabited-hooks key hook-fn)))
  (keys @inhabited-hooks))

bringe16:05:34

How can I use gensym for a def? As in, I'd like to do (def (gensym 'myprefix) "hello") - and I'd like symbol from gensym to be used for the def - which would result in a var defined as something like user/myprefix1234

bringe16:05:01

This is for tooling where I'd like to store some information in the user's repl for later retrieval with low/no risk of var capturing. I'd return the symbol generated for reference later

noisesmith16:05:12

intern can do it, or you could write a macro

bringe16:05:23

Oh thanks, I'll try that out

noisesmith16:05:41

(ins)scratch=> (intern *ns* (symbol (gensym "auto-")) 42)
#'scratch/auto-25871
(ins)scratch=> auto-25871
42

noisesmith16:05:03

mind you, wanting to do this is often the sign you are trying to use an ns as a data structure, which is counterproductive

bringe17:05:01

Ah that will work! Thanks for the feedback.

bringe17:05:58

> wanting to do this is often the sign you are trying to use an ns as a data structure, which is counterproductive I'm using a clojure library from typescript via nrepl to get some information about the repl environment that needs to be stored/retrieved later. Since I need to interact with that data as a whole via clojure again later, but only need a subset of it in JS, it seems to make more sense to store it in the repl rather than storing as a string or parsing it in JS, and passing back to the repl later.

bringe17:05:27

I'm still figuring out what's optimal as I dig deeper into what needs to be done

noisesmith17:05:42

if your goal is to store data, use a hash-map, you can put it in an atom in a namespace

noisesmith17:05:05

hash-maps are good reusable convenient data structures, code written to use them is relaible

noisesmith17:05:20

code that tries to use namespaces this way gets fragile / weird

noisesmith17:05:32

(as a very broad generalization)

bringe17:05:18

Yeah, the data is a hash-map, I just needed a place to store it that won't conflict with anything the user has defined in the repl thus far, or may define later

bringe17:05:19

So I can't just def an atom with some name, because theoretically there could be a conflict then or later, no matter how unique I try to make the name, unless I use gensym (which maybe still there is a chance of conflict, but it's a standard way to get a unique name)

noisesmith17:05:41

what I mean is a hash map with a predictable name, containing each thing you want to store this way (including hash-maps if you like)

noisesmith17:05:16

if you need to auto-generate keys in that hash-map, you can easily use gensym etc., but the result is something less fragile than alterations to a namespace

bringe17:05:57

Yeah, I get what you're saying. The discussion of my use case is maybe beyond the scope of this channel, but basically, I don't own the repl, it will have been started by some user. This is for adding variable inspection during debugging to Calva, the VS Code Clojure extension. It's mostly written in typescript and it interops with clojure via nrepl. I get the locals from cider-nrepl during a debug session and then the user can "drill down" into each local variable that's structured (map/collection). The orchard.inspect inspector maps are what I need to store for each variable - so it's a choice of storing those in JS and passing it back to clojure or just storing them the user's repl and keeping a reference to them in JS. I'm still figuring out what's best there.

bringe17:05:11

But that is pretty much irrelevant to the original question 😄 . Just felt like explaining

noisesmith17:05:50

I think it's still less intrusive to introduce one variable for storage, that's first class, but of course it's your app and your design

noisesmith17:05:02

if I see a def in an ns, I want to find the source for it

noisesmith17:05:14

existing user tooling deletes all variables in an ns and recreates it

noisesmith17:05:37

with a map in a var, you can make it less likely that that breaks everything

bringe17:05:02

> I think it's still less intrusive to introduce one variable for storage Yeah this is what I was getting at - a single var/map for storing all the inspectors. > if I see a def in an ns, I want to find the source for it What's your implication here? I thought at first read you meant it would be wise not to store the data in the repl, as well as with your statement below that

noisesmith17:05:10

there might be a miscommunication here - what I mean is that if you have an ns where there's something like (def contexts (atom {})) - that's something I can look at and understand - I can look for the code that alters it, etc.

noisesmith17:05:28

if you have something that interns new vars for contextual data, I'm more likely to be confused when debugging

bringe18:05:47

May be wiser to not store in the repl after all... good point.

bringe18:05:31

Since there is no code file in this context, nowhere for the user to see where it was defined

noisesmith18:05:14

I find "store in the repl" an odd statement - in clojure the repl is a tool that gives access to the vm, so I guess this means "store the data in the vm"

bringe18:05:38

Yes, that's what I mean

michaelb18:05:58

after googl’ing quite a bit I see the question I have has come up in the past, hoping maybe there’s a solution now… after lein has finished uberjar (with :aot :all) I need it to run javafx.application.Platform/exit

michaelb18:05:13

is it possible to tell lein to do that somehow?

Alex Miller (Clojure team)18:05:42

javafx might have a headless flag or something

Alex Miller (Clojure team)18:05:05

like for awt, you can use -Djava.awt.headless=true to fix a lot of stuff like this

michaelb18:05:49

unfortunately some javafx classes require javafx to be running due to how a static initializer is setup

Alex Miller (Clojure team)18:05:19

ok, I don't know anything about javafx :)

Alex Miller (Clojure team)18:05:50

but surely if you google headless javafx you may find some ideas

michaelb18:05:04

will keep hunting, thanks for the idea of adding “headless” to the mix

michaelb18:05:33

in general, is injecting code to run in a post-compile step not something easy to do? (maybe a dumb question)

noisesmith19:05:21

why do you need AOT? often the easiest solution is just not doing it

michaelb19:05:12

for my use case it seems to be the best option, just hitting this paint point

noisesmith19:05:04

there's usually the option of using clojure.main as your entrypoint, and providing "-m" and the string of your ns name as the first args

noisesmith19:05:11

all args after that will be sent to your main

michaelb19:05:26

I’m going to be running it through native-image and from my experiments so far I need to use an AOT uberjar

noisesmith19:05:31

oh, yeah, graalvm

vlaaad21:05:43

Do you plan to compile cljfx-based project with graalvm?

vlaaad21:05:34

If that's so, I would be interested to know about your experience, I tried compiling cljfx/hn example app with native-image, but failed so far

michaelb21:05:42

yes, I have a “hello world” that works

michaelb21:05:32

you need substrate version of graalvm, just a sec, getting link

michaelb21:05:20

I followed macOS instructions here, haven’t tried on other platforms

michaelb21:05:51

setup is a little different than normal graalvm w.r.t. GRAALVM_HOME

vlaaad21:05:27

Yeah, I know it requires their own fork of graal

michaelb21:05:55

there is probably a way to automate that, but not sure how to do it

vlaaad21:05:01

How did you figure out what's needed there?

michaelb21:05:16

hours of trial and error

vlaaad21:05:46

https://github.com/cljfx/hn/blob/native-image/build/native_image.clj there is my work in progress for graal, I might resume it now with your findings!

michaelb21:05:06

otherwise the classes didn’t end up in the uberjar

michaelb21:05:14

not sure if that’s a lein problem or my problem

vlaaad21:05:49

Probably mine — cljfx.fx stuff is loaded dynamically

vlaaad21:05:01

So you have to compile all of those too. I wrote a simple workaround to do it here: https://github.com/cljfx/hn/blob/native-image/build/compile.clj

vlaaad21:05:09

Lines 9-10

vlaaad21:05:11

Any results to share so far? What's the executable size?

michaelb21:05:25

about 80 MB

michaelb21:05:42

if run through upx with max settings gets down to about 20 MB

michaelb21:05:10

but upx has downside of initial memory usage being higher because the whole unpacked executable goes into memory and that mem can’t be reclaimed

michaelb21:05:30

iirc, I think at startup mem usage is 130 MB, but that can probably be tuned via settings that can be passed to graal

michaelb21:05:43

also, I found the binary isn’t portable across different versions of macOS, but there’s probably a compiler flag for setting the min OS version to support, just didn’t find it yet

michaelb21:05:53

the reason I went with lein was to make use of the substrate maven plugin

michaelb21:05:18

it’s been some years since I was using clojure and I don’t know the newer tools, but I remembered lein can hook to maven

vlaaad21:05:32

Heh, I think Clojure in the beginning/middle of transition period towards simpler tooling, first with clj/tools-deps, and now they are building tools-build... I tried with substrate the library, not substrate the maven plugin

michaelb21:05:18

makes sense, I just went with what allowed me to get started, since I knew lein from 2013/2014

phronmophobic19:05:28

the folks in #cljfx might know a fix for your issue

michaelb19:05:32

i’m in the situation where I really really need to run Platform/exit after compilation

phronmophobic19:05:02

the compile plugin isn’t that complicated, https://github.com/technomancy/leiningen/blob/master/src/leiningen/compile.clj. unfortunately, the best option might be to write your own lein plugin that works as needed

michaelb19:05:13

yes, going to experiment with a simple custom plugin, though I’m not sure if eval-in-project will work as hope in the context of the uberjar task

michaelb19:05:29

Alright, it looks like a lein plugin may be able to do the trick