This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-14
Channels
- # announcements (2)
- # aws (1)
- # babashka (18)
- # babashka-sci-dev (103)
- # beginners (165)
- # calva (51)
- # cider (8)
- # circleci (1)
- # clj-kondo (22)
- # clj-on-windows (2)
- # cljdoc (1)
- # cljfx (31)
- # cljs-dev (16)
- # clojure (81)
- # clojure-europe (71)
- # clojure-nl (7)
- # clojure-uk (11)
- # clojurescript (20)
- # code-reviews (26)
- # conjure (1)
- # contributions-welcome (1)
- # core-async (15)
- # cursive (8)
- # datomic (8)
- # defnpodcast (2)
- # eastwood (24)
- # emacs (10)
- # events (1)
- # fulcro (4)
- # funcool (31)
- # graalvm (43)
- # graphql (8)
- # honeysql (9)
- # introduce-yourself (1)
- # jobs (12)
- # kaocha (3)
- # lsp (28)
- # malli (4)
- # meander (4)
- # membrane (7)
- # off-topic (64)
- # other-languages (3)
- # pedestal (1)
- # polylith (31)
- # portal (5)
- # re-frame (4)
- # reitit (1)
- # releases (5)
- # rum (2)
- # schema (2)
- # sci (34)
- # shadow-cljs (21)
- # vscode (1)
I was looking at an old @cgrand post, http://clj-me.cgrand.net/2010/06/10/primitive-types-support-for-fns-coming-to-a-clojure-branch-near-you/, where he claims that the following code takes 650ms on a 2010 laptop. On my M1, at the REPL, I am seeing 21 seconds! What am I missing?
(defn ^:static fib ^long [^long n]
(if (>= (long 1) n)
(long 1)
(+ (fib (dec n)) (fib (- n (long 2))))))
(time (fib 38))
;; "Elapsed time: 21316.721792 msecs"
;; 63245986
M1 java or Rosetta?
You don't need the static (does nothing now) or the long coercions (you do need the type hints)
M1 java
woah… 202ms when I type “clj” at the repl. so something weird is happening with my emacs repl
clj-test.core=> (time (fib 38))
"Elapsed time: 331.063833 msecs"
63245986
on 13" M1 MBPoh wait 🙂
I get it… I HAPPENED to be in a namespace where I had overwritten the arithmetic operators with the generic multi-method based ones
Also, this should actually be faster in the new 1.11.0-alpha4 due to the new use of Math.exact w hotspot intrinsics for the + - dec
This Math/exact really looks promising:
(defn fib ^long
[^long n]
(if (>= 1 n)
1
(+ (fib (dec n)) (fib (- n 2)))))
(quick-bench (fib 38))
;; Evaluation count : 6 in 6 samples of 1 calls.
;; Execution time mean : 304,612157 ms
;; ...
(defn fib ^long
[^long n]
(if (>= 1 n)
1
(Math/addExact
(fib (Math/subtractExact n 1))
(fib (Math/subtractExact n 2)))))
(quick-bench (fib 38))
;; Evaluation count : 6 in 6 samples of 1 calls.
;; Execution time mean : 236,714805 ms
;; ...
(defn fib ^long
[^long n]
(if (>= 1 n)
1
(unchecked-add
(fib (unchecked-dec n))
(fib (unchecked-subtract n 2)))))
(quick-bench (fib 38))
;; Evaluation count : 6 in 6 samples of 1 calls.
;; Execution time mean : 201,021006 ms
;; ...
Am I able to use javascript with clojure? or only java?
Clojurescript: https://clojurescript.org/ 😄 #clojurescript
ClojureScript compiles to JavaScript, Clojure compiles to Java bytecode. It is essentially the same language.
I have javascript. So I might have two options. Convert javascript to java, or rewrite the javascript in clojure. I’ve never written Java, only javascript. Either direction I go, it will probably not take me much time because my project is still very small. it will probably just make more sense to write it in clojure since it is so small right now.
You can run JavaScript code from ClojureScript. Why is ClojureScript not an option? Do you need to use a Java library too?
im not sure if i want to use clojure or clojurescript… im writing for a backend so i figured i should use clojure.
Another option might be using a JS interpreter from Clojure such as Nashorn, but perhaps rewriting in Clojure is the best option like you wrote.
Also possible: using Clojurescript on the server by generating to a node.js target and running it via node. I haven't seen a lot of this but if your infrastructure/server skills are already node-flavoured this could be a somewhat gentler on-ramp.
Not a lot of blog post guidance on this direction relative to the advice you can find on JVM server work, but it's do-able.
Because I’ve been using it lately, I’ll comment on the JS engine… Nashorn is deprecated now. If you’re on JVM 15 or later, then you need to use the GraalVM https://www.graalvm.org/reference-manual/polyglot-programming/#start-language-java.
There is a blog post from Nextjournal on how to use JavaScript inside Clojure using Graal’s Polyglot (as pointed out by quoll). If you’re just starting to learn Clojure I wouldn’t suggest going that route just yet though
I want to use Files/exists
from Clojure but I can't get it working:
p
;; => #object[sun.nio.fs.UnixPath 0x17f007b4 "/Users/blah/sorted.bam.bai"]
(java.nio.file.Files/exists p)
;; Syntax error (IllegalArgumentException) compiling . at (*cider-repl code/blah:localhost:54327(clj)*:240:7).
;; No matching method exists found taking 1 args for class java.nio.file.Files
(java.nio.file.Files/exists p (into-array []))
;; Execution error (ClassCastException) at user/eval62166 (form-init13866759365748960699.clj:248).
;; class [Ljava.lang.Object; cannot be cast to class [Ljava.nio.file.LinkOption; ([Ljava.lang.Object; and [Ljava.nio.file.LinkOption; are in module java.base of loader 'bootstrap')
What am I missing?https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#exists(java.nio.file.Path,%20java.nio.file.LinkOption...) takes an Enum LinkOption linkOption
. Hmmmm...
I want to follow symlinks (the default option) so I was hoping that an empty array would be OK.
(java.nio.file.Files/exists p (into-array [java.nio.file.LinkOption/NOFOLLOW_LINKS]))
;; true
Why does the above work? p
refers to a symlink. I guess NOFOLLOW_LINKS
means: do not check whether the file pointed to exists.
But how do I get Files/exists
to follow a symlink? There is no equivalent enum for following links...I think I solved it: (java.nio.file.Files/exists p (make-array java.nio.file.LinkOption 0))
Is it possible to separate commands with ;
in clojure.java.shell/sh
?
The getting started page https://clojure.org/guides/getting_started#_dependencies doesn't mention Java 17 as a supported version, but the download page https://clojure.org/releases/downloads#_stable_release_1_10_3_mar_4_2021 does. Would be good to have it fixed.
will do, didn't realize that was copied over there
hi everybody! Shouldn't all this expressions return true ?
(vector? `[1 2]) ;=> true
(list? `()) ;=> true
(list? '(1 2)) ;=> true
(list? `(1 2)) ;=> false because (type `(1 2)) => clojure.lang.Cons
(set? `#{1 2}) ;=> true
(map? `{1 2}) ;=> true
list?
is weird and wrong
to be less jocular about it, list?
doesn't do what you expect and usually isn't the predicate you actually want
@noisesmith what predicate should I use to distinguish the things that should be printed out like (...) ?
I mean, I can always do like
#(or (list? %)
(instance? clojure.lang.Cons %))
but is weirdthis also applies to the much more common case of lazy-seqs:
(ins)user=> (list? (map inc (range)))
false
(ins)user=> (seq? (map inc (range)))
true
oh makes sense
that always confuses me
thanks!
(if you also want to include vectors)
from the examples it looked like differentiating seqs from vectors was part of the design
Weird question, but does anyone ever make a jar (possibly AOT compiled) and make a classpath that includes that jar and your normal test directory and test in that way instead of using the regular source tree? Benefits would be faster startup by using the AOT version, and also testing an actual deployable artifact rather than just the source tree that would become the deployable artifact?
yes I've done this in CI (for integration tests in particular)
did you keep tests in a separate repo or do you do some classpath manipulation or classloader shenanigans? Wondering best way to ensure that the jar’s resources are used rather than the source tree
the directory with the tests was added to classpath but not the resource directory - it's the build tool that implicitly adds "src" "test" and "resources" to classpath, clojure itself does not do this
if you use java to start the jar, you have to opt in each path (starting with the jar itself)
of course if you have code that access the file "resources/foo" it's your code that's in error
ah i see. using the clojure cli the src paths are top level. could move them to an alias but that feels a bit weird. Was hoping to start up the process pretty similarly to how we do now clj -X:dev:test
and a bunch of custom test runner stuff.
I’m thinking of making sure when you (require 'foo)
it finds foo.clj or the AOT version in the jar and not in src/foo.clj
it's easier to just not use the clojure cli - all you need is some code to bootstrap and run clojure.test right?
otherwise, just don't start clj in the root dir of your project, and explicitly add the test path
if you need things outside the jar and the test folder to run tests, that could justify a new test-root
directory in the project - and you'd run the tests from that subdirectory
just brainstorming here, I haven't seen this specific situation
yeah. that might be useful. The “easy” way here is to add a new local dep on the jar and dissoc the :paths
from the deps.edn file. Then it all just works™. But a new deps.edn and a new root for just the tests might be a way to do the same
project/
|
- src/
|
- resources/
|
- test-root/
| test/
| test-resources/
in my experience the less knowledge of tool particulars that your system requires, the less likely someone else makes a change that introduces a regression
So this is something that I'd been annoyed with a while back that I'd love to know if there's been any thought put into it. When working with spec you often make specs for domain objects as maps and they have namespaced keywords as keys. Later if things become performance-critical you can replace maps with records and get a speed boost. Unfortunately records can't take namespaced keywords though which forces a breaking change if you're using spec. Has there been any consideration for extending the functionality of records to permit namespaced keys?
my strong suspicion is no, as record fields map 1->1 with static data accessible in instances of a record class, and class fields don't have a concept of namespace
If you have a hash map {:foo/bar 13}
and you switch to a record, that's a breaking change even without Spec in the mix, isn't it? Since the record would only have bar
as a field...
I think the question is just about that breaking change to records and spec is mentioned as a motivating factor
and it would have to be a breaking change, since it's impossible to make a munge that can't clash (though you could make one that' highly unlikely to clash at the cost of severe ugliness)
In the spec, you'd change :req
to :req-un
and :opt
to :opt-un
but keep the namespaced keys for the spec names (since the -un
versions allow namespaced keys for locating the spec but only use the unqualified key for the field name). So that's less of a change than all your code that pulls fields out of a map... So I guess I don't see spec as being the motivator here really?
I take people for their word regarding motivation, but I do agree that it's easier to use spec differently than it is to make namespaces work with record keys
I skipped some steps in my reasoning above re: munging. I take it as a premise that records need that 1->1 mapping of keyword to static field on the resulting object, and a field can't have a namespace, so the only other option I can see there (without some sort of complex indirection) would be munging the namespace into the field name.
Yeah, I think your reasoning is correct.
Given the way keyword invoking works on records, if you were sufficiently motivated I believe you could make your own thing that used the same inline caches with namespaced keywords
I guess I don't recall of the compiler skips the cache stuff for namespaced keywords
yeah
(deftype X [thing]
clojure.lang.IKeywordLookup
(getLookupThunk [_ k]
(case k
::foo (reify
clojure.lang.ILookupThunk
(get [_ obj] (.-thing ^X obj)))
nil)))
((fn [] (::foo (->X 1))))
@U04V70XH6 no the motivation is the change from :req
to :req-un
because all consuming code now has to switch to using non-namespaced keywords, which could potentially be a lot of code, and could potentially be library consumers.
And yes, I was personally considering munging of the field names as the solution to this
Thanks for the suggestion there @U0NCTKEV8