Fork me on GitHub
#clojure
<
2021-11-24
>
quoll00:11:55

This has probably been discussed to death already, but I haven’t had the bandwith to follow it, so I’m asking here WRT to the https://clojure.atlassian.net/browse/CLJ-2664 and the https://github.com/clojure/clojure/blob/master/src/clj/clojure/java/math.clj, I’m wondering at the approach saying: • Portability to CLJS is a non-goal (so namespace is clojure.java.math) If portability is not a concern, then I’m wondering what the namespace is for, given that it is such a thin wrapper around https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html. Is it just the typehinting? Having a namespace that was outside of clojure.java would have made portability possible, given that most of the functions are already available in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math, and the rest can be implemented. After all, IEEE754 math is not platform dependent. I can understand not making portability a priority, but blocking it out seems like the wrong approach. (Yes, I know that ClojureScript could implement clojure.java.math, but that would be a poor idea).

☝️ 1
Alex Miller (Clojure team)01:11:03

If you're interested more discussion in #clojure-dev which is a better place for this

quoll02:11:20

So that is what that channel is for!

Drew Verlee03:11:13

If i expost f and s in this could, would f be considered thread safe? e.g if 2 threads try to call `foo "at the same time" is it safe? Or do i have to express that another way?

(ns core)

(defn foo [] "hi")

(def s (atom {'foo 0}))

(defn f [x] 
  (when (= 0 (@s x))
    (do
      (swap! s update x inc)
      ((eval x)))
    ))

@s;; => {foo 0}

(f 'foo);; => "hi"

@s;; => {foo 1}

(f 'foo);; => nil

Alex Miller (Clojure team)03:11:27

it's not thread safe - between the deref and the swap the value of s can change - this is a classic data race

Drew Verlee03:11:53

So this is a job for compare-and-set! then?

potetm03:11:44

swap-vals! will do. Or just look at the return value from swap! .

Drew Verlee03:11:42

(ns core)

(defn foo [] "hi")

(def s (atom {'foo 0}))

(defn f [x] 
  (when (= 1 ((swap! s update x inc) x))
    ((eval x))))

@s;; => {foo 0}

(f 'foo)

@s;; => {foo 1}

(f 'foo);; => nil
then?

potetm03:11:21

yep, looks good to me

nixin7204:11:43

Is there a way to figure out if/when a subprocess is requesting something from stdin when using ProcessBuilder? The usecase is I'm running some long shell commands, and I want to print a little ascii loading icon thing. That works fine, but if any of the subprocess request input from stdin - specifically a sudo prompt, that immediately screws things up because suddenly I have a sudo prompt that's immediately getting written over by a loading icon. What I'd like is if the ProcessBuilder can recognize when it's subprocess is requesting input, signal to my loading (which is on a different thread) to stop and wait for the input to be done, then once the input is entered, continue the loading icon. I can't just run the program using sudo cause that breaks all sorts of stuff since I'm relying on the user's environment - using their home directory and user installs and stuff

Cora (she/her)04:11:09

weird, does ProcessBuilder not let you read stdout of the subprocess as it executes?

nixin7204:11:25

I know that it lets you take control of it, but I don't actually want to take control of the sudo prompt if I don't have to.

Cora (she/her)05:11:19

@phdumaresq this is reminding me of a Tcl tool called Expect. there are ports to many languages, including java https://github.com/ronniedong/Expect-for-Java

reefersleep13:11:16

I’ve been trying to write an Expect script, and maybe I’m spoiled by not having to do that much terminal scripting in my day job, but I found it a little hairy. But I really want what it can give me.

Cora (she/her)05:11:18

you're depending on output from the subprocess asking for input like a password, and you need to handle their password, but it handles the thing you're talking about.

Cora (she/her)05:11:23

@phdumaresq also I was reminded of this, which could be helpful https://mdk.fr/blog/how-apt-does-its-fancy-progress-bar.html -- apt keeps its progress bar at the bottom of the screen using terminal tricks that could be helpful

nixin7205:11:56

Thank you so much @corasaurus-hex! I'll check these out tomorrow!

👍 1
Abhinav06:11:32

ELI5: are functions values? if yes, how and why? (I have a hunch they are, I just don't know why)

emccue06:11:18

i mean - it really depends how you define value

emccue06:11:42

in a loose sense - all things have observable properties. The full set of those observable properties is the “value” of a thing.

emccue06:11:37

the way we talk about values here generally is in distinction to an “identity”, which is a label attached to a succession of values

emccue06:11:50

you can define a function “object” by all the different results it would produce when called with different arguments

emccue06:11:41

but stepping back in to the “real” - if a function in your program depends on context that will change outside of itself then that function itself is not a “value”. The full state of that function and the properties of its environment that it relies on are its “value”

emccue06:11:22

(def state (volatile! 0))

(defn f [x]
  (+ x @state))

emccue06:11:29

so the “value” of the function bound to the identity of f includes the current value associated with the identity of state

emccue06:11:04

which becomes more complicated when you introduce concurrency, since the definition for what exactly the value for f is depends on what processes are doing what with regards to state and at which time/clock cycle the value of state is accessed

emccue06:11:23

which is to say - “pure” functions are values in a way that can be usefully described

emccue06:11:54

“impure” functions are also values that include the value of every property of their environment

emccue06:11:21

its the same kind of thought train that “pure newtonian mechanics” drives you down - If you knew all the properties of the universe at some time P(t), then the laws of physics are just the function from P(t) -> P(t')

emccue06:11:15

which probably doesn’t hold for the universe on account of quantumness

emccue07:11:36

So if your very real function in your program called RDRAND and sampled the randomness of the surrounding universe it would be impossible to define the value of that function at any given point in time, even with infinite knowledge of P(t)

emccue07:11:39

which is your 2am answer of the day

Abhinav15:11:42

@U3JH98J4R Damn, I appreciate your 2am answer. haha. what I understood from this is that since pure functions in the mathematical sense map one value to another they can be considered values themselves. Whereas impure functions aka procedures are not values.

borkdude14:11:44

clojure.lang.Namespace has an implementation for Navigable. But why don't I see that type show up here?

(keys (:impls clojure.core.protocols/Navigable))
(java.lang.Object)

borkdude14:11:39

I see there is even a public function for this:

(extenders clojure.core.protocols/Navigable)
;;=> (java.lang.Object)

borkdude14:11:02

> Returns a collection of the types explicitly extending protocol

opqdonut14:11:47

wild guess: clojure.lang.Namespace implements the Navigable interface, which is generated by the Navigable protocol, but not equal to it

opqdonut14:11:56

also where did you find the Navigable implementation? it's not in https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Namespace.java

opqdonut14:11:40

that's Datafiable, not Navigable, and it seems to work for me:

user=> (require 'clojure.datafy)
nil
user=> (extenders clojure.core.protocols/Datafiable)
(nil java.lang.Object java.lang.Throwable clojure.lang.IRef clojure.lang.Namespace java.lang.Class)

borkdude14:11:20

$ clj
Clojure 1.11.0-alpha3
user=> (extenders clojure.core.protocols/Navigable)
(java.lang.Object)
user=> (extenders clojure.core.protocols/Datafiable)
(nil java.lang.Object)

opqdonut14:11:03

how about after the (require 'clojure.datafy) ?

1
borkdude14:11:45

That worked.

user=> (extenders clojure.core.protocols/Navigable)
(java.lang.Object)
user=> (extenders clojure.core.protocols/Datafiable)
(nil java.lang.Object java.lang.Throwable clojure.lang.IRef clojure.lang.Namespace java.lang.Class)

borkdude14:11:18

Ah sorry yeah, got confused about Navigable and Datafiable

opqdonut14:11:54

protocols, my favourite source of bugs

opqdonut14:11:14

e.g. code that happens to work due to namespace loading order breaks when somebody makes a new namespace

opqdonut14:11:29

explicit requires are the best, but linters want to remove them

borkdude14:11:10

eh, as the author of clj-kondo I don't agree

borkdude14:11:26

clj-kondo only wants you to remove it as if you don't use it for side effects

borkdude14:11:36

if you're using it for side effects, don't give it an alias

opqdonut14:11:00

right, so clj-kondo is fine with (:require ... [foo.bar.quux] ...)? that's a good convention

borkdude14:11:54

also it "forces" you to require explicitly even if you know the namespace is already loaded. e.g. (clojure.string/join ...) isn't accepted if you don't require clojure.string

restenb15:11:43

not a clojure question, but ... does git statusconsider .gitignorebefore showing you modified files?

p-himik15:11:34

There's also #off-topic IIRC Git only considers .gitignore for files that have not been tracked already. If you track a file, adding it to .gitignore will change nothing. But there are ways around that.

restenb15:11:41

i initially forgot adding an /compiled folder to my .gitignore, so now everything in there shows up as modified with git status

restenb15:11:50

just want to figure out if git add and git commit will ignore it, or if I need to reset those modified files first

p-himik15:11:21

Try searching online for "git untrack directory" or something like that. Plenty of answers on StackOverflow and similar websites or blogs.

Michael18:11:59

some time ago I ran across a snippet that somehow called stest/instrument automatically whenever any var was (re)defined. But I can't find it now; does anybody know how they might've done it? Some kind of watch?

Michael18:11:09

(I didn't post in #clojure-spec because I think it's only tangentially related— I believe the key here is watching vars.)

Alex Miller (Clojure team)18:11:35

we have full search in the slack at the moment, I bet you can find it...

Michael18:11:18

it was on the web, and I've tried every search variation I can think of without success. The part I can't figure out is that it worked on all vars, and didn't require manually creating a watch for each one

Michael18:11:29

is there a single var somewhere that holds Clojure's entire var registry?

Alex Miller (Clojure team)18:11:25

no - vars are held in each namespace

Michael18:11:30

is there a way to watch a single namespace's vars, at least?

Alex Miller (Clojure team)18:11:37

no, don't know of any single thing that does that, although the pieces to build it exist

Michael18:11:31

any pointers on what to look at if I want to build that?

Michael18:11:29

interesting, I'll pursue that angle. Thank you!

vemv01:11:14

A good way to accomplish this is:

(clojure.tools.namespace.repl/refresh :after `stest/instrument)

Drew Verlee01:11:26

if i run that from inside emacs with cider i'm told it can't find clojure.tools.namespace.repl class. I can't require it either. hm

paulbutcher18:11:37

Is there a library anywhere of transducer functions over and above those provided by clojure.core? I have a couple of custom partition functions I’ve used in situations where partition-by doesn’t quite do what I need, but now find myself needing transducer versions of them. Before I create transducer versions of them myself, it would be good to see if there’s a well-supported option that I can use? Or alternatively if there’s some way to get equivalent functionality with clojure.core that I’m missing? Specifically the functionality I need is:

(defn partition-with
  "Partitions a sequence whenever pred returns true"
  [pred? coll]
  ...)

(defn partition-when
  "Pass sequential pairs of values to comp? and partition the collection whenever it returns true (splitting the pair)"
  [comp? coll]

hiredman18:11:52

cgrand has an xform library

paulbutcher18:11:53

Thanks - I'll check it out 👍

hiredman18:11:54

partition-by is what you want though

paulbutcher18:11:24

I'm missing something, clearly, as I'm I sure how I can get the same functionality from partition-by?

hiredman19:11:20

user=> (into []
      (comp (map biginteger)
            (partition-by #(.isProbablePrime % Integer/MAX_VALUE))
            (partition-all 2)
            (map (partial apply concat)))
      (range 20))
[(0 1 2 3) (4 5) (6 7) (8 9 10 11) (12 13) (14 15 16 17) (18 19)]
user=>

paulbutcher23:11:24

Ah! Of course. Thank you. I’ll have to see if I can come up with a similar replacement for partition-with. Thanks again!

cgrand19:11:44

The thing with partition-when is that it deals with delimiters and you then have a lot of choices: should delimiters be returned? (and if yes how? As single items? Sequence? Appended to the previous partition? Prepended to the next partition?) How delimiters runs are treated?

cgrand19:11:05

So either a single function with an options map or many functions. Or you find a way to compose it out of other fns.

dpsutton19:11:00

our production jar is AOT compiled for startup speed. When i start the jar with a socket repl, I can successfully evaluate things but it seems that I cannot replace vars. I suspect this is because the classfiles are on the classpath. Is it possible to get an AOT jar back into a more dynamic environment, able to redefine vars and functions in the repl?

borkdude19:11:40

@dpsutton you should be able to "replace" vars, but perhaps you compiled with direct linking, which goes against that

dpsutton19:11:25

yeah i was wondering that. Let me check. Our build system is a bit complicated

borkdude19:11:42

(System/getProperty "clojure.compiler.direct-linking") in your socket REPL

dpsutton19:11:24

(b/compile-clj {:basis      basis
                :src-dirs   paths
                :class-dir  class-dir
                :ns-compile ns-decls})
i don't see that set in this call. Would that property exist in the jar? Or would that only be relevant in the jvm that created the jar?

ghadi19:11:31

the property would be set in the compilation environment, not the socket REPL

borkdude19:11:33

ok, there doesn't seem to be direct linking at play here then

dpsutton19:11:35

i cannot find any grep results of "direct-linking" so i do not think it is enabled

hiredman19:11:19

it may depend on what you are trying to define

hiredman19:11:31

clojure.core is aot compiled with direct linking on

👍 1
dpsutton19:11:04

functions called by api handlers. So I would expect that these can be replaced at runtime with the jar but it does not seem to be happening

hiredman19:11:22

all the usual caveats for var redefinition apply

hiredman19:11:01

like once the var has been derefed and that value is being passed around, redefing the var won't do anything

dpsutton19:11:17

i do not think that is the case here. which is why i was so confused

hiredman19:11:58

have the class files on the classpath doesn't do anything re-vars

hiredman19:11:47

the class files on the classpath could only possible effect looking for classes, but if you are evaling things in the repl, you can get brand new classes

borkdude19:11:29

does "replacing" the vars work in dev though? you've probably already checked this

dpsutton19:11:54

yes when running a repl from source everything works just fine.

hiredman19:11:27

the possible explanations are really: 1, direct linking 2. taking the value of the var once and using that value without ever checking the var again 3. you aren't defing what you think you are defining

dpsutton19:11:47

MB_JETTY_PORT=3006 java -Dclojure.server.repl="{:port 50506 :accept clojure.core.server/repl}" -jar ~/projects/work/jars/0.41.2.jar vs clj -M:dev:...:reveal etc

dpsutton20:11:07

thanks @hiredman and @borkdude. That's what I was worried about. I'll keep looking then

hiredman20:11:11

#2 is very likely

dpsutton20:11:37

i'm glad to know that my expectation is correct and the AOT nature isn't the culprit

hiredman20:11:58

things could get weird if what you are evaluating don't just set the value of vars, but generate named classes, like deftype, defrecord, or defprotocol

dpsutton20:11:35

ah, i've realized what it is. I'm used to changing source and (require ns :reload) and forgot that this doesn't work like this here. I've been reloading the namespaces. The thing that mislead me so much was that i would log to the repl and interact but forgot to individually evaluate forms rather than work on the namespace

dpsutton20:11:56

thanks everyone and i am embarrassed 🙂