This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-10
Channels
- # announcements (1)
- # asami (36)
- # babashka-sci-dev (5)
- # beginners (4)
- # calva (10)
- # chlorine-clover (2)
- # clj-commons (2)
- # clojure (35)
- # clojure-android (1)
- # clojure-norway (1)
- # clojurescript (11)
- # cursive (8)
- # deps-new (5)
- # emacs (8)
- # fulcro (11)
- # graalvm (15)
- # gratitude (5)
- # holy-lambda (11)
- # jobs-discuss (5)
- # lsp (9)
- # off-topic (9)
- # other-languages (2)
- # pathom (6)
- # polylith (43)
- # portal (35)
- # quil (6)
- # react (13)
- # reclojure (3)
- # releases (5)
- # rewrite-clj (13)
- # shadow-cljs (32)
The following throws a syntax error (which was a little unexpected) because as I understand, the interning of keywords happens at the read phase and the ns-alias cannot be resolved here.
#_::non-existent-ns-alias/hello
Just trying to learn and understand if this ns resolution for keyword interning should ideally happen at the read or compile phase? And if my feeling of unexpectedness is justified?#_ will read the next thing then skip. The :: is resolved at read time so it fails before it can be skipped.
That said, we actually have a ticket to maybe make this possible
I'm trying to compile the longer example of gen-class
in https://clojure.org/reference/compilation#_gen_class_examples with https://github.com/clojure/tools.build but I can't get it to compile with compile-clj
, it throws
Syntax error (ClassNotFoundException) compiling new at (clojure.examples.instance.clj:41:11).
clojure.examples.instance
whereas I can compile it with (compile 'clojure.examples.instance)
( classes
is in included in the classpath in both cases)Is your file named clojure.examples.instance.clj? That should really be at the path clojure/examples/instance.clj. What does new refer to in your code? (That's not part of the referenced example)
the namespace clojure.examples.instance
is in a file at src/clojure/examples/instance.clj
and I have :paths ["src"]
in my deps.edn
and :extra-paths ["classes" "target/classes"]
in the :build
alias. The line the exception refers to is line 41
(let [x (new clojure.examples.instance s)...
here's the REPL output:
(compile 'clojure.examples.instance)
=> clojure.examples.instance ; works
(b/compile-clj {:ns-compile '[clojure.examples.instance] :basis (b/create-basis {:project "deps.edn"}) :class-dir "target/classes"}) ; :class-dir "classes" gives same error
Syntax error (ClassNotFoundException) compiling new at (clojure/examples/instance.clj:41:11).
clojure.examples.instance
and the full report says:
{:clojure.main/message "Syntax error (ClassNotFoundException) compiling new at (clojure/examples/instance.clj:41:11).\nclojure.examples.instance\n", :clojure.main/triage {:clojure.error/phase :compile-syntax-check, :clojure.error/line 41, :clojure.error/column 11, :clojure.error/source "instance.clj", :clojure.error/symbol new, :clojure.error/path "clojure/examples/instance.clj", :clojure.error/class java.lang.ClassNotFoundException, :clojure.error/cause "clojure.examples.instance"}
I've added a fix for TBUILD-20 in v0.6.0 of tools.build (sha b139316), give it a try
confirmed it works now, thank you @U064X3EF3 !
I think you may be running into https://clojure.atlassian.net/browse/TBUILD-20 which is a bug I'm going to look at today
yep - it works when I update
the basis as described - thanks!
When using deftype
, where to put the one-time expensive processing of the constructor arguments? Let's say I'm making my own Hash Map abstraction:
(deftype HashMap [items]
clojure.lang.IPersistentMap
(assoc ...)
(assocEx ...)
(without ...)
(count ...)
...
)
Where should I put the code of actually building the internal data structure, so that all other methods will have access to it? Or is deftype
not the macro to do this?Okay, looks like all these answers suggest this is impossible to do in Clojure and I'd be better off writing Java for building a class https://stackoverflow.com/questions/6515162/add-constructor-to-deftype-created-class
I see that @seancorfield used the approach of extracting out the constructors as outside functions, e.g.:
(defrecord HashMap [expensive-data-structure]
clojure.lang.IPersistentMap
(assoc ...)
(assocEx ...)
(without ...)
(count ...)
...
)
(defn make-hash-map [items]
(let [expensive-data-structure <...expensive code..>]
(->HashMap expensive-data-structure))
and make-hash-map
can be used as the de-facto constructor.But I guess HashMap is a bad example here because some of its methods (such as assoc
) is best implemented with mutations to the expensive-data-structure
, which is going to be quite awkward to do in Clojure. However, I can see that this "external constructor" technique being used on immutable records that need some one-time processing for constructing arguments -- e.g., a read-only HashMap.
The advice from 2014 is that we shouldn't use :inline
. It hasn't changed in the meantime, is that still true? At the moment I'm writing a wrapper for Project Panama (it'll be ready for proper release soon), and in order to keep performance good for primitive types even when serializers and deserializers are needed for composite types I have to avoid calling the serde multimethods for primitive types. The best case here is that I expand it with inline to reduce the runtime cost.
Is this inadvisable?
Yes, I definitely could, and for some of it I will be doing just that, but I need them to also operate as functions, even if that means it takes a slight performance hit.
I'd prefer to not need to expose two different vars for this.
I'll admit that I'm fighting for ns, but the cost per argument is ~50ns, even for primitives, and Panama is screaming fast so that completely dominates execution time.
No, definline is an exclusively inline function.
This needs both
also that's still experimental, which is what prompted the question in the first place.
Maybe I misunderstood, besides :inline
being experimental does it not do what you needed?
I also tried poking at the issue of :inline
's status several times, it's been experimental for years. I wouldn't feel bad relying on it, already do in my own library, and I suppose even if it will be deprecated it will be in favor of a better solution and we'll have a migration path, too
Well it's never been standardized, so likely if it's changed it would be deprecated, nor is an upgrade path guaranteed. That's why I'm asking here. If this is the status though, I'm likely to just make the version with functions be slower than the one with macros, since the macro case is the more common usecase anyway.
Theoretically, Clojure has never been standardized. Contrast with EDN which has been. Leaves us a bit of wriggle room, I believe.
inline may eventually be replaced with something else, but I think you can use it now if you understand that caveat
Alright, thanks, that's helpful.
Were there ideas of alternative ways to offer something similar to :inline ? Is that why it "may be replaced by something else", because the core team discussed alternatives or feel like there should be something better to it?
A wise man once said something along the lines that the future is both hard to predict and very long. So “may be replaced by something else” is in this case a rather weak statement, almost a tautology, but rules out the much stronger statement “will never be replaced by something else”.
Rich does have some ideas about this but we haven't talked about it in a long time