This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-06
Channels
- # announcements (16)
- # aws (9)
- # babashka (76)
- # beginners (92)
- # boot (1)
- # cider (18)
- # clara (7)
- # clj-kondo (26)
- # clojure (104)
- # clojure-europe (4)
- # clojure-nl (11)
- # clojure-spec (11)
- # clojure-survey (101)
- # clojure-uk (35)
- # clojuredesign-podcast (18)
- # clojurescript (8)
- # core-async (29)
- # data-science (1)
- # datomic (13)
- # emacs (4)
- # fulcro (20)
- # graalvm (14)
- # instaparse (2)
- # jobs (1)
- # juxt (6)
- # malli (5)
- # off-topic (30)
- # onyx (3)
- # planck (1)
- # project-updates (7)
- # re-frame (38)
- # reagent (30)
- # reitit (14)
- # remote-jobs (2)
- # shadow-cljs (50)
- # sql (8)
How much work is involved to make a Clojure dialect which runs on a non-java runtime (like Clojurescript does)?
is it just map a few dozen primitive operations to the new runtime and fill in the blanks for parts of the standard library that are runtime dependent, or is it much more involved then that?
Cljs helps a bit because it already ported some of the standard lib Java code to Clojure
looking at the clojurescript compiler, it seems to be a completely different entity to the clojure compiler, so I guess it's probably fairly involved
It was also written much later and leverages learning from the time, i.e. uses protocols heavily (which did not exist when the clojure compiler was written)
@ludvikgalois What do you want to do?
Nothing serious, I was just hoping to get a (reasonable) subset of clojure running on GNU Guile for a joke. But it looks to be a fairly large amount of work.
For the purposes of the joke, it's much easier to just write "Scheme" with syntax that looks like Clojure and then compile that to Scheme. That only involves needing to write something to parse EDN
there's a racket module that gives clojure features and syntax to scheme, that is probably a better place to start than cljs if you are looking at prior art
I wouldn't call it Clojure without immutable maps, vectors, and sets, and those are all implemented in Java for Clojure. They are implemented in ClojureScript, but that would require implementing deftype and protocols on a new target, at least.
not vectors, but sets are implemented using the map implementations.
Looking at the source for maps and vectors, they seem to be based on the same sort of 32-bit array mapped trie, just with very different insert rules. Vectors aren't implemented as a HAMT, so I guess they're just an AMT? But you're right, it's not a trivial amount of work
I suppose vectors could be considered AMT. I know how vectors and maps are implemented in data structures, and that the map data structures are called HAMTs, but whether AMT is a well-known thing by that name, I do not know
As I mentioned, if you start with ClojureScript's implementation, there those data structures are implemented in the Clojure language itself, so probably easier to port. You need only implement deftype and defprotocol, IIRC
I'm not saying any of that is an insurmountable hurdle, by any means, especially given the existing implementations to go from. Just mentioning some things you definitely want to be sure to implement on a new target.
Your irregular reminder - the Exercism Clojure mentoring team is still looking for more mentors. Join us and use few 10s of minutes / month to help a beginner learn Clojure! https://exercism.io/become-a-mentor 🙏
Thanks for the heads up - I've just signed up as a mentor. I've had a lot of enjoyment writing Clojure so happy to give back to the community this way at least.
Thanks for pushing this. I'm currently taking the Clojure track and happy for mentor help
Thank you, @U067BPAB1! We need all the help we can get 🙂
thank you very much @U0JEFEZH6 :D
i use the :resource-paths approach for the REBL jar. there are other options discussed here: https://stackoverflow.com/questions/2404426/leiningen-how-to-add-dependencies-for-local-jars also, you might have more luck in #leiningen
Hey,
let’s say I have something like a.clj
(ns a
(:require [c]))
(defn eval-f
[f]
(eval f))
and b.clj
(ns b
(:require [a]))
(a/eval-f '(c/some-fn))
Then I’ll get an error like unknown namespace c
ie it seems that eval
works as if it was called from the b
namespace
I have done something like
(defn eval-in-ns
[ns form]
(binding [*ns* (find-ns ns)]
(eval form)))
to solve it but I find this behaviour a bit weird and would have thought there would be a with-ns
function or something like it to do it (seems that it was in clojure.contrib https://clojure.github.io/clojure-contrib/branch-master/with-ns-api.html but has been dropped). Anybody can help me understand why this is the case and why this function doesn’t exist ?Why not simply require c
in b.clj
as well, then (a/eval-f c/some-fn)
? You can then remove the require from a.clj
.
@U067BPAB1 yeah that’s a good point and would work well for this example - however what I was trying to show and that I find a bit confusing is that when calling (a/eval-f f)
I would have expected this to be eval’d in the a
namespace as this is where eval-f
is defined but actually it’s not
plain-quoting a namespaced symbol doesn't resolve ns aliases, no matter what namespace you are in
@UCPS050BV I am not sure I understand what you meant - think it’s the same behaviour whether it’s the full name or an alias - in my case I think it was an alias though eg (ns a (:require [xxxxxx :as c]))
ie the namespace is imported where the eval-f
is defined - but then when calling eval-f
the namespace doesn’t get resolved
But in any case it would be a huge code smell to write code in namespace a
that depended on an alias defined in namespace b
If you used the fullly qualified namespace I believe it would work because c
is transitively required
Are there any proper document or source about Strings on Clojure. They are implements serializeable interface but how, why ?
I’ll write something about why this call works like smoothly, (map identity "bello!")
.
Because Clojure Strings implements Serializeable interface.
*A lot of* false-sources are saying Clojure Strings *are* Sequences, but it is all about interface implementation.
Clojure Strings are just Java Strings.
I think this statement is true ?You think that strings can have seq called on them because they implement the serialize interface?
strings are java.lang.Strings
the Clojure runtime has special case code to treat Strings as "seqable"
when you call seq on a string, you get a sequence of characters
that's the whole story
serializable has nothing to do with it
I don't know of any reference documentation about it
This will suffice for the explanation, thank you guys. But I’m very curious person. I need to dig about it.
Basically, Clojure has the concept of Seqable. Those are things that can be coerced to a Seq using the seq fn
seq function has some documentation on it. Not about implementation, just about the contract.
There's a few special cases: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L541-L559
If you want to dig, you will want to dig into Clojure's implementation code quite a bit, not only the part written in Clojure, but also the part written in Java. Feel free to ask for pointers into that source code if you can't find what you are looking for.
Ok, this special treatment comes from Clojure Run-Time. But, are there any special situations like this ?
BTW, is RT.java
considered implementation detail? I.e. does it need to preserve backwards compatibility in terms of its interfaces?
I think the general answer is if it's not in the documentation under "reference" or API on http://clojure.org then it may change
I started to wonder because I saw clojure.lang.RT#assocN
with a comment that says: "//hmm... this is not persistent".
But at the same time, this static method is not used anywhere (well, except if there's some obscure reflection going on).
"is RT.java
considered implementation detail?" yes
"does it need to preserve backwards compatibility in terms of its interfaces" yes
AOT compiled Clojure includes calls into RT and thus we try pretty hard not to break binary compatibility with the RT interface (or Clojure code compiled on an old version would not run on a new version). I actually can't think of a bug report or complaint like this in my memory so I think we do a pretty good job at that.
you may find some vestigial methods in RT that are no longer used but have been preserved for compatibility
Oh, so ABI is still relevant here. After halting any serious work done in C++ I kinda stopped having this problem and eventually forgot about it completely. I see, thanks.
most Clojure code is distributed and consumed as source (so late-compiled when used) so it's usually not something to worry about much
Clojure core is a bit special in being a mix of Clojure and Java and mostly AOT compiled
Is it possible to get meta information about a function at run time? I captured the var in a atom, derefing it tells me the fn sig (in emacs with cider). But i'm curious if you can get more information at run time. I would link so, but my first pass (meta @foo) didnt work.
from a var or a function instance?
for the former, meta should tell you things. for the latter, no it's opaque (just an invokable thing)
"capture the var" is unclear to me which one you did
(meta @foo) is pulling the metadata from the fn
(meta #'foo) pulls the metadata from the var
Just talking about terminology. What would describe this:
(defn foo [])
(def d (atom nil)
(defn zoo [x] (reset! d x))
(zoo foo)
I would say i set the value of the atom to the function foo. Though "function" is more accuratly a "Var". right? I haven't thought about this in a while.
Thats what i was calling capturing. I had hopped to then deref that atom value and get meta information on the function. i assume a docstring is meta information. I'm not sure what all could be there.the var foo
will be dereferenced here and the value inside the atom will be the function object that the var foo
points to
you could reassign a new object to the var foo
and the object inside the atom would not change
the useful meta information for a defined function is stored on the var, not on the function object
Ah, good point. I was thinking the information was on the function object not the var.
user=> (defn foo [x] (println x))
#'user/foo
user=> (meta foo)
nil
user=> (meta #'foo)
{:arglists ([x]), :line 1, :column 1, :file "NO_SOURCE_PATH", :name foo, :ns #object[clojure.lang.Namespace 0x14e2e1c3 "user"]}
user=> @#'foo
#object[user$foo 0x60e21209 "user$foo@60e21209"]
user=> (@#'foo "hey!")
hey!
nil
(defn foo [x]
(println x))
(=
(class foo)
(class @#'foo))
;; => true
(fn? foo)
;;=> true
for the record this is what ended up working to publish 2 jars with different deps from a single project
:aliases {"deploy!" ["with-profile" "default:fixture" "deploy"]}
:profiles {:test-deps {:dependencies [[org.testcontainers/testcontainers "1.12.3"]
[org.testcontainers/postgresql "1.12.3"]]}
;when we run `lein with-profile fixture install` (or `lein deploy!`), gr-db/gr-db-fixture-{version}.jar is published with the test-deps included in the pom.xml
:fixture ^:leaky [:test-deps {:source-paths ^:replace ["src-helper"]
:name "gr-db-fixture"}]
:dev [:test-deps {:resource-paths ["test-resources"]
:source-paths ["src-helper"]
:dependencies [[ch.qos.logback/logback-classic "1.2.3"]]}]}
note re: the comment, about test-deps being included, that profile actually excluses the normal "src" tree (it would merge in src-helper with src if the ^:replace
metadata wasn't there)
because the default for that setting is to merge the vectors and not replace them, and the vector contains "src"
by default, but the ^:replace
metadata tells lein to remove the default setting