This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-12-29
Channels
- # beginners (29)
- # boot (17)
- # calva (1)
- # cider (31)
- # cljs-dev (3)
- # clojure (169)
- # clojure-europe (1)
- # clojure-france (1)
- # clojure-russia (40)
- # clojure-serbia (3)
- # clojure-uk (42)
- # clojurescript (19)
- # clr (3)
- # core-async (7)
- # core-typed (3)
- # cursive (43)
- # datascript (4)
- # datomic (2)
- # dirac (4)
- # emacs (2)
- # fulcro (85)
- # funcool (1)
- # nrepl (5)
- # off-topic (14)
- # shadow-cljs (28)
- # spacemacs (5)
- # tools-deps (2)
what's the most current/usable dep for interacting with the filesystem now?
seems to be several out there.
@macrobartfast It depends what you want to do...?
I should have said that! I'm trying to list the directories in a directory.
Are you looking for something list this? https://github.com/clj-commons/fs
Or you could just use Java interop -- which may well be the easiest path, depending on what you need.
(.listFiles (io/file "path/to/folder"))
should work I think...
Yeah... example
seanc@DESKTOP-QU2UJ1N:~/clojure$ clj
Clojure 1.10.0
user=> (require '[ :as io])
nil
user=> (.listFiles (io/file "/tmp"))
#object["[Ljava.io.File;" 0x13d186db "[Ljava.io.File;@13d186db"]
user=> (seq *1)
(#object[java.io.File 0x15723761 "/tmp/hsperfdata_root"] #object[java.io.File 0x312afbc7 "/tmp/hsperfdata_seanc"])
user=> (doseq [f (.listFiles (io/file "/mnt/c/users/seanc"))] (println f)
)
#object[java.io.File 0x2ce45a7b /mnt/c/users/seanc/.atom]
#object[java.io.File 0x153d4abb /mnt/c/users/seanc/.cisco]
#object[java.io.File 0x6d4c273c /mnt/c/users/seanc/.ssh]
#object[java.io.File 0x5a67e962 /mnt/c/users/seanc/3D Objects]
#object[java.io.File 0x545e57d7 /mnt/c/users/seanc/AppData]
#object[java.io.File 0x2bc9a775 /mnt/c/users/seanc/Application Data]
#object[java.io.File 0x27b000f7 /mnt/c/users/seanc/Contacts]
#object[java.io.File 0x42f9c19a /mnt/c/users/seanc/Cookies]
#object[java.io.File 0x64bfd6fd /mnt/c/users/seanc/Desktop]
#object[java.io.File 0x2ab2710 /mnt/c/users/seanc/Documents]
#object[java.io.File 0x253b380a /mnt/c/users/seanc/Downloads]
#object[java.io.File 0x29c2c826 /mnt/c/users/seanc/Favorites]
#object[java.io.File 0x3350ebdd /mnt/c/users/seanc/IntelGraphicsProfiles]
...
that's probably what I'm looking for... I was using Raynes's original project.
clj-commons
will maintain it from now on. I'm not sure that it got many updates between Raynes' last version and what's in that new organization?
We use it at work for some compression stuff but elsewhere, when we're just interacting with the file system, we use Java interop.
I'm getting objects back too, but I'm wondering if I should be getting strings... I'll have to see if objects will work in my case.
File
objects. That's what io/file
returns. You're expected to work with those.
https://docs.oracle.com/javase/8/docs/api/java/io/File.html shows all the methods and fields.
Call .getAbsolutePath
or .getCanonicalPath
to get a string 🙂
Or just .getName
.
oh, cool!
yay! that helps. thanks! 😀
The joys of a hosted language 🙂
Are there any packages (or would it ever be a useful concept) to combine core typed + spec? For pre-runtime analysis of things like ADT and runtime instrumentation of actual pre/post conditions?
Do you mean "Is there any value to using core.typed
on my code and clojure.spec
?"... Sure, they serve completely different purposes.
Could core.typed
annotations be derived from specs? Maybe, in some situations.
That's what i'm thinking - at least for the general shape of data, and having some macro based system like ghostwheel provides for spec that would handle both cases seems like it could be pretty useful
in common lisp, I did something similar with their (well, sbcl's) declare ftype + deftypes: https://github.com/ahungry/cl-typed
I think that core.typed
will eventually be a useful addition but it is too restrictive today, IMO.
We've been back and forth between core.typed
and Schema several times, and now we use spec heavily at work.
isn't it similar to typescript, in that it allows optional/gradual typing? so you could just choose not to type some things?
core.typed
was very painful to use. See the CircleCI post about why they abandoned it. Ambrose is taking a step back and looking at radical improvements.
No, core.typed
is not like TypeScript.
Ahh nice, I did take a quick look at that circleci post awhile ago (before i was using clojure frequently). Oh, I'll have to spend some time with it and find how it varies (spec is pretty great, i'm excited to see what new things come of that in the future as well
core.typed
is a lot more invasive. You have to annotate everything in a namespace -- you can't just annotate one function. It also often requires you to annotate code within functions and/or refactor code to satisfy the type checker.
Oh, I see what you mean. if I have something like this:
=(t/ann add-one [t/Int :-> t/Int])
=(defn add-one [x]
= (+ 1 x))
=
=(t/ann add-two [t/Int :-> t/Int])
=(defn add-two [n]
= (add-one (add-one n)))
Still, I wonder if tihs isn't just a cumbersome syntax construct that causes most the grief, writing a signature like this:
(defun add-three (Int n → Int)
(add-two (add-one n)))
if that were a macro that generated a defn + the t/ann, seems like it would be nice and concise
from what I see, its more akin to schema validation (like jsonSchema or AJV in js world)
the generative testing is cool - I found a good (huge) macro a couple months ago that will automatically inject each spec def into your unit test suite so you can run generate testing as part of the default test runner system
the syntax (imho) sucks, thats why I want to write some useful macro to make the types look like C types
It's definitely something stupid on my part, but I register a spec in the registry under a key, they use namespaced ones to avoid colissions cool cool
I understand the entity maps, but I have no clue why each key needs to be defined as its own thing with its own spec
I think the idea is that names are important - so this acctid is now a label (just like 'string' vs 'int' is more useful than some weird _3182 symbol to refer to them)
so, ::person is a composite type (a map) and to meet the minimum definition of a 'person" the data must match, in that it has to have a first name + last name + email
(defmacro defun [name sig & args]
`(do
(t/ann ~name [~@(take-nth 2 (butlast sig)) :-> ~(last sig)])
(defn ~name [~@(take-nth 2 (rest sig))]
~@args)))
(defun add-nums (t/Int a t/Int b t/Int)
(+ a b))
still ugly, Ill need to auto-namespace the types and keep them plain symbols i think (then roll in spec 🙂 )
if you dont like the double dots, maybe you wanna use with a defrecord, you can also use unreq for unqualified required
even though defrecord isn't idiomatic, I made a 'user model' - its a record, not a map, but to be a 'valid' one it has to have name, age, id, language
this says "I am a spec that requires a key :first-name
which satisfies the spec fn registered under :my.ns/first-name
Why in the heck does making a spec that checks a key in a map require I have registered a function in the global registry under the correct name?
like "Okay im in development time, always check my specs and check to make sure I dont mess up specs in my dependencies"
when I was looking, it seemed I had to have an stest/instrument next to each fdef I made, or do something like query the ns for all symbols and map stest/instrument across them
actually no I can see how having a symbol would make whatever it is spec does to work better with reloading during dev
@emccue I think you're seriously overthinking spec (if that helps) 🙂
Specs are mostly just predicates
s/keys
defines a predicate that is a conjunction of predicates on keys.
nevermind, stest/instrument can just be called with no arg and enable full instrumentation (basically exactly what I want during a new defun)
Also, adding a single local jar throws an error like so
Error resolving /Users/rratti/code/calcite-play: 1 problem was encountered while building the effective model for org.apache.calcite:calcite-core:1.18.0
[ERROR] Failed to determine Java version for profile java8 @ org.apache.calcite:calcite:1.18.0
My hunch is that it might be a problem with the local jar?When you use a local jar, it will read the pom inside the jar to determine its transitive deps - that’s what is failing here
I haven’t encountered this particular error before
Thanks Alex. For adding a whole dir of jars, I guess the only way is the add every jar one by one?
Currently, yes
Any clues? Reflection warning, <file> - call to java.lang.ProcessBuilder ctor can't be resolved.
here is the function
(defn- my-proc [version args]
(ProcessBuilder. ["java"]))
A reflection warning in Clojure is only a warning that calls to that Java method will be very slow, as compared to calls to Java methods that do not give reflection warnings.
If it is in setup or init code, run once or only a few times, I wouldn't worry about it.
If it is in an inner loop of your code run billions of times, then it is worth fixing.
@andy.fingerhut I plan on compiling to a native image with graalvm - I need to resolve these reflections
@flyboarder you'll need to bind ["java"] to a name and type hint that name. I presume it's telling you that there are multiple constructors for ProcessBuilder and it doesn't know which one to use.
Looking at the Java docs for ProcessBuilder, there are 2 constructors, one which takes a java.util.List, and one which takes a String..., meaning Java varargs, which in Clojure must be an explicit Object array.
Maybe try: (ProcessBuilder. (object-array ["java"]))
?
I wonder why it needs a hint in this case. The literal string vector does satisfy List and does not satisfy String[]
Depending on how long you want to dig into it, you could put debug print statements inside the Clojure compiler reflection code and try to suss it out.
@eraserhd could you provide an example? what should the type hint be?
@andy.fingerhut the object-array
did not work 😞
@eraserhd yes that did it!!
thank you all!
clojurians, i'm trying to build functions on top of my database to work with users. for example I have a function get-user which takes a username and returns their row in the users table. my problem is this: I want to be able to swap out the database that get-user uses to grab users (for mocking, testing, etc). one solution would be to have each function take an extra db param as argument so get-user would have the following type get-user : db * username -> user-row. the other is to have the db as some global parameter that I can swap out. both of these solutions don't suffice in my mind. the first has the problem of having to pass the same db to every function call, whereas the second requires that all of my function calls access the same db (i might want them to access different ones).
https://github.com/tolitius/mount is a good solution for that, allows you to treat db as a global object but is easy to redefine the state in your tests
Component is also an alternative, but yes this seems to be the recommended way to handle app state since each piece you define with mount can be stopped, restarted, and reset in a deterministic way. If you create a luminus template like lein new luminus test-app +postgres +site
you can see mount and hugsql in action for how it handles test environments and separating db functions from db state.
in the case where the db is a param to your function, you could also have a partial fn for your application with db already bound to it
The problem with a global db is that now all of those functions are impure. db as a param seems more idiomatic imo, and matches the “database as a value” paradigm common in Clojure. And as @U3XNU4Y57 mentioned, it’s easy to partially apply those functions with an initialized db value.
Another way to think about it is in the context of OOP; it’s common to see db.getUsers(...)
, in which the db object is the (implicit) first parameter (`this`).
Edit: I suppose this only makes sense if the database tech in question supports immutability though...
That said, Mount is a great tool for setting that db value up initially (w/ potential dependency injection) and tracking its state in the face of REPL reloads. It can then easily be passed in to the (pure) user functions.
in haskell i'd use a monad, so that get user would have the following type get-user : username -> db user and then i could call rundb : db * db a -> a to get my value out in the context of a certain database.
i like the haskell way, but we are in clojure land now. my other idea was to write a function that takes a database and returns a map of user database functions specialized to that db. this seems silly though and not idiomatic clojure. what is the best way to accomplish my goal?
Not to say that this is a solution to your problem — But if you were to mark a global definition as dynamic, you can use binding
to redefine it in tests.
So you can define some global constant: (def ^:dynamic *some-global-constant* 12)
, and make up your mind later and use: (binding [*some-global-constant* 42] …)
to locally redefine the global constant. But that is not the elegant solution in this case I think.
@henri.schmidt you can implement a similar pattern to the Haskell monadic approach in Clojure, if you like
there are many ways to do it, but one could be to define a simple data structure to describe the database function you want to be executed:
;; get-user
;; example output: [:db/user "someuser342"]
(defn get-user [uname]
[:db/user uname])
(defn run-db! [descriptor]
... )
if you can make the descriptors of your db commands simple enough, a multimethod for the run-db!
function is quite nice:
(defmulti run-db! first)
(defmethod run-db! :default [_]
(throw (RuntimeException. "Unknown database function.")))
(defmethod run-db! :db/user
[[_ uname]]
;; fetch user row
)
Would the above pattern be useful for a database like Datomic, where an immutable db value can be obtained efficiently, and then just passed as an argument? Is the monad pattern mainly useful in contexts where the db is mutable/stateful?
thank you everyone for the advice. i think i'll use mount for the db regardless and then have all the functions take the db as a parameter. should i manually be passing this db parameter around to every function call? id kind of like to define the db at the top level and have it pass down.
@henri.schmidt I think the correct answer is to use both ways of doing it. Thats what I do and you get the best of both worlds assuming you have a sane way to reason about when you use each style
for example I have this for a database reference a (def ^:dynamic *db* (db-connection))
Then I make my api:
(defn get-user
([user] (get-user *db* user))
([db user] (.getUser db user)))
This way I have a default, which is dynamic ( so optional binding overrides) and I also get explicit db to use whenever you need