Fork me on GitHub
#clojure
<
2021-03-02
>
Valentín03:03:51

Hi everybody

Valentín03:03:49

does somebody know how to convert this java line code into clojure code?

Valentín03:03:53

this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)

Valentín03:03:20

I've been trying this...

Valentín03:03:24

(defn get-API []
  ;this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)
  (let [interface-class (.getClass osquery-clj.interfaces.IWindowsNamedPipeLibrary)
        unicode-options (W32APIOptions/UNICODE_OPTIONS)
        API ^osquery-clj.interfaces.IWindowsNamedPipeLibrary (Native/loadLibrary "kernel32" interface-class unicode-options)]
    API))

hiredman03:03:38

You should print out the value of interface-class

phronmophobic03:03:46

what error are you getting?

Valentín03:03:53

Im getting that error Interface (Class) of library=kernel32 does not extend Library

phronmophobic03:03:25

For JNA, I've been using something like:

(def objlib (try
              (com.sun.jna.NativeLibrary/getInstance "CoreFoundation")
              (catch java.lang.UnsatisfiedLinkError e
                nil)))
It looks like you can pass in an options map to this call too. Does this work for you?
(def api (try
              (com.sun.jna.NativeLibrary/getInstance "kernel32" (W32APIOptions/UNICODE_OPTIONS))
              (catch java.lang.UnsatisfiedLinkError e
                nil)))

seancorfield03:03:54

UNICODE_OPTIONS is not a function so the parens look wrong around that.

phronmophobic03:03:35

that part works though

> (W32APIOptions/UNICODE_OPTIONS)
{"type-mapper" #object[com.sun.jna.win32.W32APITypeMapper 0x4a9f4493 "[email protected]"], "function-mapper" #object[com.sun.jna.win32.W32APIFunctionMapper 0x703d3680 "[email protected]"]}
¯\(ツ)

phronmophobic03:03:57

it also works without the parens :thinking_face:

phronmophobic03:03:53

that block is from my repl, so I can confirm it works with and without parens

phronmophobic03:03:03

unless my repl is doing something goofy

seancorfield03:03:29

I'm just kind of puzzled by a Java interface that seems to have data members...

seancorfield03:03:09

My Java is rustier than I thought? 🙂

phronmophobic03:03:37

there's some odd things in JNA to make interop with c better

phronmophobic03:03:58

honestly, I'm not sure how all of it works

seancorfield03:03:15

Apparently you can declare variables (data members) in an interface and they are treated as static final. TIL.

notbad 1
p-himik09:03:58

I remember reading the code in Clojure compiler that would explicitly turn (MyClass/STATIC_FIELD) into a regular static field lookup. Can't quickly find it right now though. Perhaps it even worked that way for (.regularNotCallableField myObject)...

Valentín03:03:20

now it seems it is working

Valentín03:03:32

(defn get-API []
  ;this.API = (WindowsNamedPipeLibrary) Native.loadLibrary("kernel32", WindowsNamedPipeLibrary.class, W32APIOptions.UNICODE_OPTIONS)
  (let [interface-class osquery-clj.interfaces.IWindowsNamedPipeLibrary
        unicode-options W32APIOptions/UNICODE_OPTIONS
        API ^osquery-clj.interfaces.IWindowsNamedPipeLibrary (Native/loadLibrary "kernel32" interface-class unicode-options)]
    API))

seancorfield03:03:46

And as for WindowsNamedPipeLibrary.class, in Clojure the class name evaluates to the class itself, so WindowsNamedPipeLibrary should be all you need?

Valentín03:03:20

yes you are right

Valentín03:03:43

with that change it seems its working

vandr0iy09:03:23

Hi everybody! I gotta hook up a call (sentry 🙂 ) to all of the exceptions (`Throwable`s) in my application. Is there a nice AOP way to do it by adding a hook somewhere once?

lassemaatta09:03:20

What kind of application are you developing? For example with a HTTP stack you can create a http middleware, which catches and re-throws the exceptions thrown by the handler(s) and reports them to sentry

dharrigan09:03:59

You can try this:

dharrigan09:03:02

(defn ^:private set-default-exception-handler
  [sentry-logger]
  (Thread/setDefaultUncaughtExceptionHandler
   (reify Thread$UncaughtExceptionHandler
     (uncaughtException [_ thread ex]
       (log/warn ex "Uncaught Exception!")
       (sentry-logger {:throwable ex})))))

👍 1
dharrigan09:03:33

You simply need to then provide a sentry-logger, which is a function that creates a sentry instance, configured as you see fit...

vandr0iy09:03:08

hmmm ☝️ that's one way to do it

dharrigan09:03:23

Works for moi in my application 🙂

vandr0iy09:03:54

of course, I'd have to add the sentry hook to all of the caught exceptions - but that's mostly search and replace

vandr0iy09:03:09

yeah, I like this one. Thank you!

dharrigan09:03:26

you're welcome. 🙂

dharrigan09:03:41

btw, which sentry library are you using?

vandr0iy09:03:00

I think I'll go with the official one. Got any reccomendations?

dharrigan09:03:18

Which one would that be?

lassemaatta09:03:32

I recently had some problems with the official one (`sentry-clj`?), it failed to report some clojure exceptions properly. raven-clj did not have this issue.

dharrigan09:03:56

Which version of the sentry-clj are you using?

lassemaatta09:03:29

good question, I believe I tried the latest one a few weeks ago

vandr0iy09:03:49

I also saw one from exoscale - is it worth it? which one are you using?

dharrigan09:03:04

I'm maintaining the semi-official one

lassemaatta09:03:28

(sorry, I didn't mean to hijack this thread with my own issues 😄 )

dharrigan09:03:31

sentry-clj isn't official, in the sense that it's not sanctioned by Sentry. It's deemed a community-driven effort

dharrigan09:03:05

If you have issues with sentry-clj, raise an issue on github and I'll see what I can do 🙂

dharrigan09:03:33

PRs are welcome 'tho 🙂

emccue15:03:34

@U1C72J3J4 you can make your own try catch

emccue15:03:40

thats always on the table

emccue15:03:34

not recommending it but you can always make

(custom/try
   ...
   (catch RuntimeException e
     ...)
   (finally
     ...))

emccue15:03:46

and expand it to have whatever calls to sentry you want

emccue15:03:53

that would be the AOP-iest way

borkdude10:03:38

I'm a bit surprised that transit doesn't offer support for serializing arrays out of the box:

user=> (write-transit [1 2 3])
"[1,2,3]"
user=> (write-transit (into-array [1 2 3]))
Execution error (NullPointerException) at com.cognitect.transit.impl.AbstractEmitter/marshalTop (AbstractEmitter.java:203).
null

raspasov11:03:23

I guess it focuses on Clojure data, and arrays are host-specific things:

raspasov11:03:35

(into-array [1 2 3]) => #object[“[Ljava.lang.Long;” 0x55cad8a0 “[Ljava.lang.Long;@55cad8a0"]

borkdude11:03:16

So are byte arrays, yet it supports them:

user=> (write-transit (.getBytes "foo"))
"[\"~#'\",\"~bZm9v\"]"

raspasov11:03:11

I see… I don’t have other guesses 🙂

Timofey Sitnikov12:03:54

Good Morning Clojurians, if I make a mistake and require something that I should not have, and get this:

user=> (require 'development)
Syntax error (FileNotFoundException) compiling at (app/model/session.clj:1:1).
Could not locate datascript/core__init.class, datascript/core.clj or datascript/core.cljc on classpath.
It seems like after fixing the issue, I have to completely restart the REPL for it to work properly. Would there be a process to fix and not have to restart the REPL?

p-himik12:03:38

Yes. You can use a different classloader that allows adding things to the classpath in runtime. While it may sound complicated, there are already implementations out there. Probably the easiest way to start using such functionality is to look at Sean Corfield's dot-clojure repo: https://github.com/seancorfield/dot-clojure Namely, search for :add-libs in the README.

1
p-himik12:03:03

(I'm assuming you're using deps.edn)

Timofey Sitnikov22:03:00

OK, so how do you start? Do you just execute a single command and everything gets re-loaded?

p-himik22:03:13

Nothing gets reloaded. You require t.d.a (tools.deps.alpha) and call the right function to add a dependency in runtime. The linked repo mentions this near the description of :add-libs: "see the example load-master function in the comments in my deps.edn". That example explains pretty much everything.

borkdude12:03:33

@timofey.sitnikov in the leiningen world you have pomegranate for this, in the deps.edn world there is something called add-lib

Ben Sless13:03:27

I there a way to override a specific method implementation in a defrecord?

borkdude14:03:40

Hmm, maybe :extend-via-metadata helps somehow?

user=> (defprotocol Foo :extend-via-metadata true (foo [_]) (bar [_]))
Foo
user=> (defrecord FooRec [] Foo (foo [_] :foo) (bar [_] :bar))
user.FooRec
user=> (foo (->FooRec))
:foo
user=> (foo (with-meta (->FooRec) {`foo (fn [_] :overriden)}))
:foo
user=> (foo (with-meta (into {} (->FooRec)) {`foo (fn [_] :overriden)}))
:overriden
:thinking_face:

borkdude14:03:21

But not really I think

borkdude14:03:39

Do you mean a defrecord instance of the defrecord type btw?

Ben Sless14:03:55

The idea was to override the equality methods for a record, but I can roll my own with a minimal deftype

Ben Sless14:03:16

Things got less pleasant where I had to implement my own hasheq 😞

alexmiller14:03:12

you should not do this

alexmiller14:03:35

if you want custom equality/hashing semantics, you should deftype

Ben Sless17:03:06

That's what I ended up doing

nooga15:03:15

dumb question about internals: is the compiler supposed to evaluate each top level form one-by-one when compiling? it has to learn about macros somehow as it goes

nooga15:03:51

or is there some more advanced magic involved?

alexmiller15:03:17

the compiler first reads (string -> clojure data)

alexmiller15:03:49

then compiles, then evaluates

alexmiller15:03:35

compiling an expr will look at the thing in function position. if that's a macro, it expands the macro (this happens until it's not a macro)

alexmiller15:03:19

a macro is just a function that takes a form (clojure data representing a function call) as input and returns an alternate form (clojure data) to replace it with

alexmiller15:03:50

the unit of compilation/evaluation is a single top-level form (not a file)

👍 1
nooga15:03:31

yes, but defmacro is basically (do (defn x ...) (set-macro! (var x))) and that set-macro! call has to be evaluated for the compiler to know that x is a macro

nooga15:03:55

obviously it is not called set-macro! in Clojure, used that name for brevity

nooga15:03:47

ah right, that’s what I was wondering about

p-himik18:03:38

Could someone please point me to the repo that tracks the Clojure CLI bash script?

p-himik18:03:17

Thanks! Would've never thought to look in something that has "brew" in its name. :) And for some reason Google doesn't index the repo.

seancorfield18:03:35

https://clojure.org/releases/tools is also a useful reference, listing all the releases and the changes in each.

👍 1
alexmiller18:03:48

Yes, the repo name is bad and we have a ticket for that (but it requires updating a bunch of infrastructure so has not seemed worth it so far)

alexmiller18:03:57

Note that the script linked above does have some variable replacement done on it before it gets published so you can’t just use it as is

alexmiller18:03:00

Often when people ask this, their real need is something else which might have a better answer if you care to share

p-himik18:03:57

Thanks! Yeah, I was just curious about the history of commits that first introduced clojure.libfile and later removed it. Cursive seems to still set the clojure.libfile property.

alexmiller19:03:29

Ah, yeah, that’s dead, replaced by the basis property. I was setting both so add-lib would keep working but that’s updated now

👍 1
p-himik18:03:51

I'm trying to use clojure.tools.namespace.repl/refresh and I've stumbled upon an interesting issue. When called for the first time, it seems to reload absolutely all Clojure files that it could find in the classpath. Regardless of whether they have been loaded before or not. The problem is that I have a few files that aren't loaded and require extra dependencies to be loaded. Clearly, I don't want refresh to load them at all. Is it possible to fix it on my end? Would it make sense to alter something in clojure.tools.namespace to support reloading only the files that have been loaded before?

mkvlr18:03:38

we’re also seeing this, iirc it’s a problem with tools namespace not seeding the timestamp it uses to track what needs to be compiled directly

p-himik18:03:43

Not sure. The docstring explicitly says that it will load all files upon the first call: > Scans source code directories for files which have changed (since the last time this function was run)

mkvlr18:03:09

yeah, might well be a design decision but it’s annoying in our project where you need to wait forever the first time you call it

mkvlr18:03:39

preseeding this timestamp might be worth a try

p-himik18:03:30

Oh, that might help, I'll try that!

mkvlr18:03:04

please let me know if it does!

p-himik18:03:59

OK, adding

(alter-var-root #'clojure.tools.namespace.repl/refresh-tracker
                assoc :clojure.tools.namespace.dir/time (System/currentTimeMillis))
seems to work. However, it truly fixes only the initial loading issue. It will not fix a situation where you change some file that has not yet been loaded (and that cannot be loaded due to a missing dep for example) and then call refresh.

👍 1
p-himik19:03:07

Got it working properly (or at least, as I want it to work) with this:

(alter-var-root #'clojure.tools.namespace.repl/remove-disabled
                (fn [orig-remove-disabled]
                  (fn [tracker]
                    (let [filter-loaded #(filter find-ns %)]
                      (-> tracker
                          orig-remove-disabled
                          (update :clojure.tools.namespace.track/unload filter-loaded)
                          (update :clojure.tools.namespace.track/load filter-loaded))))))

p-himik19:03:49

@alexmiller You're the latest contributor to tools.namespace - do you have any thoughts on the above? Would it make sense to add such a behavior to the lib, perhaps under a flag or via a function that changers some var, like disable-reload! already does?

alexmiller19:03:14

please file a question on ask.clojure..

👍 1
alexmiller19:03:20

don't have time to look at it atm

vemv20:03:20

Looks like you aren't invoking set-refresh-dirs beforehand? It's very recommendable to do so

p-himik20:03:08

It still doesn't solve item 1 in the post above. It's easy to forget to add a newly created dir there. It's impossible to have a file that you don't want to load in the same dir with a file that should be reloaded.

vemv20:03:32

> It's easy to forget to add a newly created dir there. Can be solved in a number of ways; this is not a place to question t.n's API/design. > It will attempt to (re)load even the files that haven't been loaded before. This doesn't make sense, t.n's very job is loading code. Its first load will typically load all your project's code; if you aren't doing this you are following a custom/hybrid approach

p-himik20:03:14

And I don't think that it's an invalid approach. At the very least, mkvlr above seems to share it with me.

mkvlr20:03:50

@U45T93RA6 IMO there’s nothing to reload when you call refresh after you project boots without code changes

vemv20:03:14

there's everything to reload because nothing can be assumed to have been required. If something else was requireing your code, making refresh perceivedly redundant, you should have a careful look at what/why is doing that. https://github.com/stuartsierra/reloaded is the canonical example of how to setup a project using t.n.

p-himik20:03:55

Still, it doesn't invalidate the desire to be able to adhere to, as you called it, a custom/hybrid approach.

vemv20:03:33

I didn't suggest so

alexmiller21:03:40

I’m not tracking this thread so please make sure relevant info ends up on the ask question, thanks!

tcrawley18:03:21

PSA: Clojars is having DNS issues - our provider (DNSimple) is having an outage, which is making it impossible to resolve http://clojars.org in some parts of the world. Hopefully they will get it fixed soon.

❤️ 1
tcrawley19:03:06

If folks are having dependency resolution failures, check your clojars repo url. If it is https://clojars.org/repo/, change it to https://repo.clojars.org. The former just redirects to the latter, and the latter isn't impacted by the DNS issues.

tcrawley19:03:55

But we may be back up! http://clojars.org is now properly resolving for me.

🎉 1
devn22:03:18

Thanks for the heads up @U06SGCEHJ — and glad it was sorted quickly.

tcrawley19:03:06

If folks are having dependency resolution failures, check your clojars repo url. If it is https://clojars.org/repo/, change it to https://repo.clojars.org. The former just redirects to the latter, and the latter isn't impacted by the DNS issues.

rtacconi19:03:14

I remember I found a tool similar to Ansible but written in Clojure, it’s not pallet, it was recently developed, I can’t find. any idea?

rtacconi20:03:27

Yes thank you

Felipe Reigosa22:03:10

Hey guys, I posted this on news-and-articles but there aren't many people there so reposting here, hope it's ok. I published a new video about my visual/mechanical programming language MockMechanics on youtube. It's created and scripted entirely in clojure. In the video I show how I built a 7 segment display that I'm using to build a 3d printer machine. It uses just a little snippet of clojure to do something that looks pretty cool. What do you guys think? https://www.youtube.com/watch?v=9rieZb2hzLE

seancorfield22:03:52

We discourage cross-posting. People who want to see news and articles will subscribe to that channel. It's the same reason that articles/videos/etc are generally disallowed in #announcements -- it is for project/library releases only (and maintainers are discouraged from posting too often -- that's why we have #releases for more minor updates).

seancorfield22:03:47

FYI, every new member is automatically subscribed to #news-and-articles -- so if that channel has fewer people it is because they've chosen to leave it.

Felipe Reigosa22:03:59

Got it. Sorry 😬

seancorfield22:03:41

I deleted it from #clojure as it seems you are getting feedback in #news-and-articles

👍 1
seancorfield22:03:10

Sometimes you just need to be patient before people get around to responding 🙂

Felipe Reigosa22:03:01

Maybe I got greedy, it's not like nobody cared, I'll stick to announcements from now on. 😀

Daniel Hines23:03:16

Hello Clojure friends. It's your prodigal son who's spent some time wandering in statically typed functional land, especially OCaml as of late. Compared to Clojure, OCaml's experience for live editing is really subpar, and I want to improve it. There are 2 routes I'm considering: 1. Add better REPL support in my editor (similar to Calva/CIDER) 2. Don't do a REPL per se, but instead do something like https://quokkajs.com/. Whereas a REPL is stateful, Quokka just runs a file and prints results inline in the editor, discarding the context each time. What do you guys think? I'm guessing that experienced Clojurians probably think 1 is strictly better than 2. Could you explain why?

p-himik23:03:44

One thing that immediately comes to mind - CPU intensive work. It wouldn't be fun to wait for something to finish each time you run the file or to keep track of all the temporary files with intermediate results. Another thing is side-effects. You usually don't want to repeat them unless necessary.

Daniel Hines23:03:05

Come to think of it, Quokka has some pretty crazy heuristics for finding exactly what code needs to be rerun to mitigate those issues @U2FRKM4TW. Re implementing those for OCaml would not be fun, whereas with a REPL, the user decides what needs to be rerun.

Alys Brooks23:03:45

I suspect a Quokka-style setup up is easier to get up and running since you don't have to maintain a connection so I don't know about strictly superior. Although if you're coming up with heuristics, it's probably not simpler anymore. Also, the reloading entire files avoids situations where, e.g., you're running (g (f val))) but the actual code running is (old-g (current-f val))) because you forgot to re-evalute your new definition of g.

p-himik23:03:30

@U8QTB156K Perhaps - apart from having a glance at the website, I'm not that familiar with Quokka so I was talking about just running a file each time.

Alys Brooks23:03:04

I think the REPL approach is ultimately better because like you said, the user can decide and you can include shortcuts to reload the entire file. But running everything from scratch has a certain simplicity. I don't think it's well-suited to Clojure due to the startup time, but it might work for ClojureScript or something like Lumo or Babashka.

vemv09:03:48

Retrofitting a "real" repl into an existing language might be harder than it sounds. See https://news.ycombinator.com/item?id=25620256

noisesmith19:03:18

the workflow that worked for me with OCaml was structuring my projects so that I could iteratively re-compile and run targetting the specific feature I was working on (kind of a TDD flow), since the OCaml compiler is extremely fast and its repl is significantly different from the compiler

noisesmith19:03:23

with my OCaml projects I could compile to native code and run in less time than clojure typically takes to get a repl prompt