I know this is a big ask, @didibus, but I get a bit dizzy by trying to sort all this out into a coherent suggestion on what Calva could do in this space. Knowing how you can structure thoughts… If you do find some time, I’d appreciate a feature request (or several) on the Calva repo. I also of course understand if you do not have the time.
(The load current namespace command is already in the works, https://github.com/BetterThanTomorrow/calva/pull/904 It is the rest of this that I find myself thinking in circles with.)
@seancorfield I am using your clj-new, which is great. One thing I don’t understand is, I see a clj_new.clj file in the jar archive. But that file does not exist in the github repo, https://github.com/seancorfield/clj-new. Which magic makes that file into the jar?
Thanks. I see that now.
https://github.com/seancorfield/clj-new/blob/develop/src/clj_new.clj the file is there
Hi, so we have that nice if-let
binding. However, when I check on strings, if-let
works on an empty string, which makes sense. Is there a similar macro for strings that only creates a let binding if a string is not null or empty?
You can wrap something that returns a string (or any other collection) in a call to not-empty
.
Just in case - also note that if-some
exists.
(defn not-empty-str [s]
(when-not (string/blank? s) s))
(if-let [x (not-empty-str "")]
x
"FAIL")
string/blank?
is different from "an empty string": "True is s is nil, empty, or contains only whitespace."
If you know for sure that something is a string, there's absolutely no reason to not use not-empty
in the described scenario.
> there's absolutely no reason {...}
there is: as you hinted, string/blank?
is a stronger predicate, and the one that one would likely want to use in a custom macro.
(Whether a custom macro is worth it for such a specific use case is a different topic)
I also use seq
which works with strings, collections and so on.
which, not-empty
uses under the covers
Good Morning Clojurians. How come the https://maven.apache.org/guides/mini/guide-mirror-settings.html lists the official maven repo as <https://repo.maven.apache.org/maven2>
and my clj seems to think that (https://repo1.maven.org/maven2/) is the central repo?
I'm using a transit library from 2016 (by @russ767, the golang one) I see this warning on the transit-java page: NOTE: Transit is intended primarily as a wire protocol for transferring data between applications. If storing Transit data durably, readers and writers are expected to use the same version of Transit and you are responsible for migrating/transforming/re-storing that data when and if the transit format changes. Does this mean a go transit lib from 2016 might not be compatible with a clj/java transit lib from 2020?
I mean, what kind of standard is transit, if you cannot rely on this?
Is the spec versioned?
It seems so? Version: 0.8
Are changes to transit versions documented?
I think it's the same repo but available at different URLs.
Check out the top <url>
tag here: https://repo.maven.apache.org/maven2/.meta/repository-metadata.xml
Both ultimately resolve to a caching provider (fastly) with the same subnet, so I wouldn't be surprised if they are simply the same service.
Some details: https://maximilianmichels.com/2017/who-is-behind-maven-central/
@vemv str/blank?
is not stronger, it's completely different:
(str/blank? " ")
=> true
(not-empty " ")
=> " "
This is the original q:
> only creates a let binding if a string is not null or empty?
str/blank?
satisfies that. It's stronger than not-empty
because it rejects more invalid strings.
A custom let
that considered ""
blank but " "
not blank would seem fairly contradictory.
Actually in my context I indeed look for str/blank.
I ended up copying the if-let macro and adding an additional predicate on the test: (if (and temp# (not (str/blank? temp#)))
instead of (if temp#)
Sorry but I don't follow you at all @vemv .
The original question does not use the word "blank" but uses the word "empty".
Maybe we have differences in our understanding of the word "empty". I treat it as empty?
, but maybe you treat it as "not visible if rendered with no context" or something like that?
But given the elaboration from sveri, this is now but a discussion of semantics. :)
Sorry for being unclear in my original question. For me > if a string is not null or empty? refers to str/blank?, but thats just my interpretation.
If I want to represent a pair in clojure, which representation has the least memory used: vector, list or something else?
thanks people, I wanted equality semantics so I didn’t go with array, but rather with (List/of (object-array [val1 val2]))
Does that really take less memory?
Also, forgot to mention before, if you're storing primitives, you can try vector-of it is a space efficient version of vector, the purpose of it is space efficiency.
It's basically a vector interface implemented over a typed homogeneous array of primitives
defrecord
, according to a small experiment with https://github.com/clojure-goes-fast/clj-memory-meter
If you don't care about immutability then regular Object[]
will be even smaller.
also worth a look: https://github.com/ztellman/vertigo
I encountered this exact thing (for IPV6 specifically) https://support.cloudbees.com/hc/en-us/articles/360035734031-Stuck-thread-looking-up-IPv6-hostname in a clj program of mine
Is -<http://Djava.net|Djava.net>.preferIPv4Stack=true
a good idea then? Or at least a not-terrible one I hope?
(I've seen it in various clojure projects, I never happened to know what was being fixed there)
I am trying to run test for https://github.com/fulcrologic/fulcro-rad-sql but getting No matching ctor found for class org.flywaydb.core.Flyway
error. like so:
[I] /home/sporty/clojure/fulcro/fulcro-rad-sql~> clj -M:test
Clojure 1.10.1
user=> (require 'com.fulcrologic.rad.database-adapters.sql.query-test)
Syntax error (IllegalArgumentException) compiling new at (com/fulcrologic/rad/database_adapters/sql/migration.clj:170:28).
No matching ctor found for class org.flywaydb.core.Flyway
I am I missing something in the setup?Sounds like a dependency resolution issue. Are you on Lein or deps.edn?
deps.edn
ok, I lack expertise there but the underlying issue, I think, is that Fulcro expects one specific version of the Flyway .jar, but deps.edn is fetching another Different jars can have different versions of the java code, which would explain the not-found constructor
Thats crazy, but but yes, that was the problem. I make all the deps to use the same older version and now it works. Thank you.
Phew, I have so much to learn with this huge Clujre stack.
Hello every one i am here for searching a good documents that's helps me build a web api using pedestal integrant and vase
10 years on the JVM and still learning (as you can see in the question I posted above yours)... 😃 at least us clojurians tend to not break APIs so much. I don't remember an issue like yours (which is relatively common in Java) with clojure .jars
There’s no way to add support for with-metadata
to instances of a Java class, is there?
Thank you for that example. I’m not sure I understand what the delegate part is in the example and how it differs from java proxies, since the the example seems to use proxy
?
Anyway, if my understanding is correct, I will need the proxied class to have constructor that can take an existing instance of the class and create a new instance from it, right? It is a great hack, but unfortunately it’s not general enough to wrap e.g. random Java objects from a Java library, which is really what I’m looking for… :/
my apologies for not being very clear. proxy
the clojure function isn't the same as a java.lang.reflect.Proxy instance although they're similar in purpose. You can use Proxy instances to support classes that don't necessarily have a "delegate" constructor by adding a layer of indirection between the object consumers see and the real object instance underneath (this is what a java.lang.reflect.Proxy does). To use java.lang.reflect.Proxy you'll need to have interfaces that you can rely on for each type of object (one of which would be IObj), otherwise I believe you'd need to dip even deeper into things like javaassist / cglib to pull it off if your objects don't have interfaces and instead are using abstract classes or things like that
https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
would be interested in hearing more about what you're trying to solve by adding metadata to java classes though - there may be another way to approach the problem that is almost certainly worth pursuing over doing funny things with javaassist / cglib
Sure. The issue is the following: In Stanford CoreNLP you define a pipeline based on a list of annotators. Then when you annotate a piece of text, you get back an instance of an Annotation class. This is basically just a glorified map containing other annotations. As an aggregate, they form a tree of different kinds of annotations. You can navigate down the tree using a set of functions picking different kinds of annotations. One issue is that there is nothing in particular marking what type of annotation the instance is - you only know this from the key that you got it from. You also don’t know what kind of pipeline setup it was constructed from or what it was a child of, so I can’t navigate back up the tree like you would do with something like clojure.zip. One way of solving this lack of information is to wrap the Annotation in a Clojure map when you get it, but that would introduce new complexity when interfacing with the Java API, since it’s now an instance of a different class. Another way of solving it would be to mutate the Annotation object by setting my own key using its setter function, but that would 1) add mutation and 2) pollute the domain with implementation code that doesn’t really belong there. So I thought that maybe I could use metadata to solve this issue with a lack of, well, metadata.
(core/defmacro or
"Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions, otherwise it returns the
value of the last expression. (or) returns nil."
This sentence does not computeread the or
on the second line not as a logical construct but as the macro under discussion. "If a form returns a logical true value, this form returns that value and doesn't evaluate any of the other expressions..."
this is the fragment that is particularly confusing ”
, or returns that value and doesn't
evaluate any of the other expressions,
But what do I know - I am not a native speaker, this could be James Joyce quality for what I know
"if a form returns a logical true value, or
returns that value (the logical true one) and doesn't evaluate any of the other expressions"
Yes, but there have been no changes since it's initial release in 2014
yeah. substitute that "or" with "this macro". It is certainly confusing because we need a way to specify if we're talking about the conjunction "or" or the macro or
funny how the description of boolean stuff sounds so unboolean in english
also, there's an "and" after it which probably primes our brain to interpret the preceding or
as the conjunctive part of speech rather than the macro this docstring is describing
This refers to the transit format spec, which has not changed.
Btw, I'm using the russolsen go transit lib for real now.
I agree, it need more parens
OK, I feel lucky
I dont see how parens would help. I think bronsa put the best solution which is to put backticks around the confusing or
haha, James Joyce was famous for prose that made no clear sense :D
@i Glad you find it useful! There's a #clj-new channel if you get stuck or want to deep dive on anything.
anyone have experience drawing ASCII art in a REPL?
I'm guessing that there's going to be issues dealing across various displays (e.g. TTY, Cursive, Emacs buffers)
if all you do is print line by line, and you use a standard character set, it should just plain work (though emacs bugs out with wide lines)
if you are trying to do cursor control, you need a cursor control lib, and those don't target cursive or emacs (though at least emacs does have buffers that are vt100 compatible...)
yeah I just need to be read only for now
and print line by line
I've been using https://github.com/mabe02/lanterna for terminal graphics
I think any output that displays fixed width properly would just work
yeah, it looks like lanterna is great if you need cursor control
or mouse support!
it's also graalvm compatible if you want to have fast start up
I think that printing to a REPL buffer is as much as I want to do to keep it simple enough to: • View remotely (e.g. across a socket REPL/nREPL connection) • Use in CLJS / browser
if I was only interested in Clojure and doing local dev then lanterna would probably be better
yeah, I've had good luck viewing ascii formatted text in a browser, just make sure to use <pre>
or otherwise ensure fixed width
(I used this for tabulating cljs test output)
(who wants to mess with browser rendering in your test suite...)
Hey all I'm trying to wrap a defn in a macro. Can anyone explain to me why this doesn't work? A little new to macros.
(defmacro m [x]
(defn f [x] (x)))`
@buterajay this might be better for #beginners but to start, macros return lists and the list gets compiled, in your list the function argument is nonsensical
this one is small enough to work out by hand: (m 5)
would become (defn f [5] (5))
(well it would work as (m conj)
for example, except it would create a function that takes an argument named conj and then calls its arg with no args...)
@buterajay do you understand this syntax error?
(ins)user=> (defmacro m [x] `(defn f [~x] (~x)))
#'user/m
(ins)user=> (m conj)
Syntax error macroexpanding clojure.core/defn at (REPL:1:1).
user/f - failed: simple-symbol? at: [:fn-name] spec: :clojure.core.specs.alpha/defn-args
Hm ok that makes sense, but what if my input is a simple symbol like (m 'v)
it would break, as 'v
is (quote v)
which is not a valid argument name
also, your macro gets one step closer to working as follows (but probably isn't doing what you want)
(cmd)user=> (defmacro m [x] `(defn ~'f [~x] (~x)))
#'user/m
(cmd)user=> (m foo)
#'user/f
(cmd)user=> (f conj)
[]
(ins)user=> (f +)
0
the arg name to m
doesn't matter at all, as it is just a placeholder inside f
(what I did to fix the previous error is unquote then quote f
, so that ` wouldn't namespace it and break the defn)
Ooh gotcha
have you used macroexpand
?
Ya but my macros often are too broken for it to work lol
yeah, that's frustrating, here's a small workaround for debugging:
(ins)user=> (defmacro m [x] `(_defn f [~x] (~x)))
#'user/m
(cmd)user=> (macroexpand '(m foo))
(user/_defn user/f [foo] (foo))
I thought with a macro, the inputs are not evaluated, so passing in a symbol would just be the symbol and not (quote v)
it's interesting that the schema check runs by just expanding the macro, kind of agressive...
'v prevents evaluation outside macros
it expands to (quote v)
which is a reader syntax for not evaluating
but if you already aren't evaluating, you just get (quote v)
when you use ' too
user=> ''''''''foo
(quote (quote (quote (quote (quote (quote (quote foo)))))))
because quote doesn't mean "make a symbol when reading" it means "don't evaluate this form", so when you nest it, you get the inner quote as is
Ok that makes sense. So then how would you define a variable name like x? Should I evaluate a string into a list?
what should this macro do?
Basically (m v) should return (defn f [v] (v))
I asked that because I don't understand the question "how would you define a variable name" - usually in macros the variable names are auto-generated and what matters is that they match the binding
the binding block on f there means that v is meaningless
it's just a throwaway name
(for an arg, that gets called with no args)
I see what you mean, maybe I need to rethink exactly what it is that I need..
so as you specify, (m asdfljasdfk) and (m foo) and (m conj) all do the same thing
Essentially I'm looking for a way to compress an expression into a single macro with free variables as inputs. If you have a free moment, I have a video of visual clojure editor I'm working on. Basically this macro would help me to compress larger expressions into single reusable blocks. https://photos.app.goo.gl/Yh2emBVrgsEcDxhF9
@buterajay if I understand what you are trying to do, I think your best bet is to set aside ` entirely, and look at what a macro does your own program is doing some of the work that ` does, while missing the variable capture safety both your program and `, are tools for constructing lists from templates, you can just return the list you want compiled from a macro
(ins)user=> (defmacro silly [] (list 'defn 'f ['x 'y] (list '+ 'x 'y)))
#'user/silly
(ins)user=> (silly)
#'user/f
(ins)user=> (f 1 2)
3
• edited in an attempt to make it clearer what I'm demonstratingfor a non "silly" example, you would be doing something other than just returning that defn list - you'd be doing some sort of list interpolation / splicing / substitution
I don't think ` will help you much here - you are making an alternate way of doing that - which is valid, it's just a series of tree transforms
you might want to skip defmacro
entirely, and just construct lists to pass to eval
perhaps the domain of your program is that a user interacts with the GUI to construct a namespace, this means the goal would be to translate the GUI state into a series of forms that clojure could load to create a namespace
Wow ok I think I'm seeing what you mean. I knew it would just take someone with a clojure mindset haha. I need to process this a bit more. Thank you very much
the check happens at macro expansion time so I don’t actually think it’s aggressive at all
Cursive does implement some ASCII escape codes, but it’s very far from implementing a full terminal. I can get a list of the supported codes if that’s useful.
If you want, you could define "truthyness" differently
(defn truthy? [v]
(not (or (nil? v)
(false? v)
(empty? v))))
and then build something around that
The answer is no. If-let checks for truthy values, and truthy values are all values except for nil and false. So a String, no matter what characters it contains or doesn't is always truthy. So like others said, you need to wrap the string in some other function that returns the string or falsy.
A wire protocol? It just says that new version of transit could be incompatible with the old versions. And since wire is the focus, my guess is if for any reason an incompatible change improves performance a lot of addresses some other major issue they'd do it.
An array most likely
@didibus sure, but this means that a web service in language A talking transit 0.8 (of company Y) and a web service in language B (of company Z) upgrades to 0.9 suddenly can't talk to each other anymore?
that seems like a very brittle way of doing things. what if JSON makes a breaking change?
I get it, but I don't believe this is the use case for transit.
The use case is fast communication between services. I think it's meant for micro-service and client/server communication. Where if you upgraded, you'd upgrade everything together.
I also think what it would mean, is that the two services when communicating would need to agree on the version of transit to use. So maybe transit 0.9 can still communicate in transit 0.8 to a 0.8 client.
But I don't know if that's the case, or maybe since the protocol never actually changed yet, this problem and it's solutions haven't come up
One problem I'm specifically having: babashka can communicate with pods (standalone programs) via transit. If babashka would upgrade its transit lib but the sqlite pod (written in Go) doesn't, there may be a problem
and this go lib doesn't even mention a transit version
In this case I would prefer stability over performance, so maybe transit isn't the right pick then
I picked transit because it has support for byte arrays which JSON hasn't
sending a byte array from clojure to a pod works seemlessly without having to think about base64, or whatever
I guess my surprise is that I'm used to thinking of macro expansion as manipulating symbols of lists, and defmacro wasn't expanding a defn but rather constructing one - it' s a minor thing to be sure
my mental model was that (macroexpand '(defn ...)) would go through defn's validators as it expands defn itself, but I didn't expect the result list to also get validated based on the first symbol
Hum... Well I think it is up to you to negotiate a version of transit to use maybe? But this "negotiation" mechanism isn't in the Spec. And so Transit libraries for various languages don't have to support it or anything. I don't know, are there a lot of data encodings out there that took a stand on cross version compatibility?
> This implementation's major.minor version number corresponds to the version of the Transit specification it supports. I have trouble finding out which major and minor version this lib has: https://github.com/russolsen/transit
I think it would be appropriate to have different namespace names in transit libraries if there are breaking changes, so you can support multiple at the same time
transit08.clj, transit09.clj
but as Alex has said, the format hasn't changed since 2014 so maybe it's a non-issue
Ya, the thing is the libs don't really matter
This is the spec: https://github.com/cognitect/transit-format
Current version is 0.8
That said, the spec does say: "Each library's major.minor version number corresponds to the version of this specification it implements."
So I think a well designed lib for transit should have versions mapping to the spec it implements
But ya, I guess namespaces would be nice, since then you could support multiple versions
> Ya, the thing is the libs don't really matter What do you mean?
So they way they propose to use transit is in controlled environments where you have control over each component - not as something you expose to the outside world, I guess?
I mean that the library can easily be designed badly, or behind, in some given language. The transit version I believe is part of the payload, since transit is self-describing. So in theory, a good lib can decode transit of any versions, or throw if it knows it can't.
But two systems exchanging messages, should also make sure they use the same protocol
I don't think the transit version is part of the payload
I mean, you can expose it to the outside world. But say I had an API, and I took and returned Transit 0.8, I'd tell my clients. And if I'm about to upgrade to 0.9 and no longer support 0.8, that be for me to communicate it to them, and help them migrate, or I can provide another API that takes 0.9, etc.
> I don't think the transit version is part of the payload Hum...
If that assumption I'm making is wrong, then I guess ya, Transit might be meant for closed systems that you control end to end
Because that means there'd be no way to handle a 0.9 that is incompatible with 0.8 if it ever happens
Maybe that's still a non-issue. Like Alex said, who knows if we will ever need a 0.9, and if we do, maybe it will be made backward compatible anyways.
using this flag didn't seem exactly harmless as it triggered this kind of error:
> I get the above exception when I set bind_host to ::
but specify -<http://Djava.net|Djava.net>.preferIPv4Stack=true -<http://Djava.net|Djava.net>.preferIPv4Addresses
.
https://github.com/elastic/elasticsearch/issues/15143#issuecomment-160945522
Interesting: https://groups.google.com/g/transit-format/c/jSo-nE4JoHU
> Transit was released as version 0.8 July 2014 and has not been changed since
Ya, but if the encoding isn't describing of its protocol version, that does mean it can't gracefully handle breaking changes.
So we have to rely on the rationale that most likely at this point, they'd never break compatibility since so many people use it.
Maybe they'd do a Transit2 instead of a 0.9 if they needed a breaking change. I wouldn't be surprised. Clojure core devs and Rich hates breaking people's code, so I think its fine not to worry about this scenario
My conclusion is not to worry about it. I really suspect this is a similar case to Clojure libs being stuck in 0.x forever. And I'm like 99.9% convinced they'd never introduce a breaking 0.9 transit version.
Also, I see the spec specifies MIME types. So maybe the payload doesn't tell you the protocol, but it seems to be intended to use a MIME type with it. So I think it be easy to add a new MIME type if Transit changed in incompatible ways.
right. right now I use transit+json
as the "mime" type in babashka pods
this could also be transit0.9+json
in the future
Ya exactly
I think its safe to use for pods.