This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-23
Channels
- # adventofcode (21)
- # announcements (4)
- # babashka (35)
- # beginners (36)
- # calva (76)
- # cider (16)
- # clj-kondo (24)
- # clj-on-windows (12)
- # clojure (70)
- # clojure-europe (7)
- # clojure-nl (13)
- # clojure-spec (3)
- # clojure-uk (3)
- # clojurescript (34)
- # conjure (11)
- # cursive (22)
- # datomic (30)
- # deps-new (2)
- # emacs (36)
- # fulcro (28)
- # gratitude (4)
- # honeysql (16)
- # hugsql (8)
- # introduce-yourself (6)
- # jobs (1)
- # malli (4)
- # missionary (6)
- # off-topic (129)
- # other-languages (34)
- # polylith (3)
- # reagent (9)
- # reitit (27)
- # releases (13)
- # remote-jobs (1)
- # reveal (1)
- # shadow-cljs (2)
- # tools-build (3)
- # tools-deps (18)
- # web-security (7)
- # xtdb (4)
Maybe a stupid question, but in clojure.tools.cli
what is the best way to fail upon giving no arguments?
I thought to do something like this, but the program still seems to run.
(def cli-options
[[nil "--url" "Any YouTube link."
:default nil
:validate [#(some? %) "Must input a URL."]]
["-h" "--help"]])
Should this check take place in the main
function?that nil should be a sting indicating the shorthand name of the argument
so "-u"
the default might run in the validate fails, it doesn't work in either case.
so don't have that as nil either
i also just wouldn't use clojure.tools.cli unless i had to meet some contract to deliver to another developer wasn't going to learn clojure. clojure deps has a thing for running functions for one and secondly i just eval functions in my repl. I know there are lots of cases where you might need to use a CLI program though, just making sure you were aware of the trade offs.
I suspect the nil
in the shorthand argument position is intentional, it looks like OP knows what he’s doing.
drew might be correct though, the :default
might be silencing your validation error. Try removing it and see what happens?
I guess nil could be a way to say "i dont' want to supply that". I prefer to use keys for that to avoid this kind of confusion. then you just dont include the key value pair.
is
(loop [f_n-2 0 f_n-1 1] (recur f_n-1 (+ f_n-1 f_n-2)))
tail call recursive? I guess i should say, does the machine's memory have to grow in reltionship to the symbol tracking or update the integer changing. i guess the later because i get an inter overflow before anything else.If you can use recur
then it’s tail recursive. Using recur
in a non tail recursive position will cause an error.
then it’s tail recursive.
thanks max, i should have used the term "tail call optimized". I think the funny thing here is that this will throw an error regardless, just depends on which and how fast it happens.
But i take your meaning, the compiler wont even accept it in some cases.
i don't think this is regular tail call since its not actually calling the function but requiring the programmer to use a goto. tail call optimization would be (defn foo [x y] (foo y (+ x y))
and that would hit the integer overflow not the stack overflow
this:
(ns foo)
(loop [f_n-2 0 f_n-1 1] (recur f_n-1 (+ f_n-1 f_n-2)))
produces a Integer overflow, which i understand to be the best outcome. A stackoverlow would happen much earlier and likely is slower to unwind to... idk.
1. Unhandled java.lang.ArithmeticException
integer overflow
Numbers.java: 1576 clojure.lang.Numbers/throwIntOverflow
...
i likely have lost track of what it means to be "tail call recursive" again though.
(dpsutton: err sorry i shouldnt DM especially this late at night)
https://clojure.org/reference/special_forms#recur "`recur` is the only non-stack-consuming looping construct in Clojure" for example:
(defn foo [x y]
(foo y (+ x y)))
will hit IntegerOverflow only because it happens early than StackOverflow with default JVM configuration
(defn foo [x y]
(foo y (+' x y)))
this will hit StackOverflow (note +' instead of + to autopromote long)
(defn foo [x y]
(recur y (+' x y)))
and then using recur will block main thread "forever". No StackOverflow or IntegerOverflow.
However there is no tail-call optimisation in clojure (as in java 8).
non-tail recursive position means:
(defn foo [x y]
(when (recur y (+' x y)) 42))
this will throw because recur
occurs in the middle of the when
formin practice, "tail call optimization" means that the compiler will emit a "better/faster" code for that recursion
In the case of clojure, when using recur
it emits a while
(that do not accumulate stack, that is faster)
when not using recur
, it will call the function again, as expected
> i should have used the term "tail call optimized" tail call optimization is the only thing recur is capable of doing, if you are not in tail position it will error, if you are it compiles into a goto in the byte code (same as a Java for)
Thanks that makes sense. So when using recur
the recursive calls aren't creating a stack. So nothing to consume.
looks like recur is working just fine. The error is because an integer is not infinite and the loop doesn't have a condition to stop it looping and so keeps increasing the integer values until overflow.... I'm sure you've spotted that by now though.
Hi, I've this function that runs in the REPL, but not when called inside a .jar file (locally built with lein uberjar
). Any idea why?
(defn- get-posts-files []
(-> "posts"
(io/resource)
(io/file)
(.listFiles)))
java.lang.IllegalArgumentException: Not a file: jar:file:/.../target/uberjar/blog.jar!/posts
> io/resource
returns a URL, not a file
found a partial https://stackoverflow.com/questions/32232662/clojure-uberjar-not-loading-resource-file. So how I can list all the files in a resource directory? .listFiles
accept a File
object, but I need to point it to the resources directory
Yeah, they are no longer files when bundled in a jar. I had this same exact issue in Optimus. Check out the code here for some answers: https://github.com/magnars/optimus/blob/master/src/optimus/class_path.clj
Heya folks! Is there any good way to test if a collection can be made transient
?
Is (instance? clojure.lang.IEditableCollection form)
enough?
Hey folks 👋 What are some popular library choices nowadays for building REST APIs? I remember Pedestal being recommended a lot previously, is that still the case? What do you use? Thanks!
Pedestal is staying strong and "boring" which is a good thing in this churn-y dev world!
There's also pedestal 2
in the works apparently from what I heard the other day.
We just use plain ol' Compojure but our APIs are more "REST-like" than "true REST". I hear compojure-api mentioned a lot and for a while folks were talking about liberator, but I haven't used either and can't comment on them (nor have I used Pedestal).
Does that have explicit REST support @emccue?
(I would probably use reitit instead of Compojure for any new projects I started, at this point)
i personally crashed our site by not understanding the defroutes macro in compojure last week so i might be a tad bitter with that rec.
pedestal is actually nice though if you need/want to do websockets or more involved middleware stacks. i think “stock ring with jetty” is good enough for most though.
> what do you consider explicit REST support? Good question. I would want to be able to declare "resources" and the verbs that are allowed for them and have some automated wiring for that, rather than having to explicitly write out every possible matching route pattern.
Apart from that, if it's HTTP-based then it's nice to have HTTP be abstracted away to some extent. Like not having to do (assoc response :status 404 :message "Not found")
when something is missing - stuff like that. yada
does that to some extent.
I've heard that reitit has some issues with reloadability if you aren't using one of the system-state-managers like component, mount, integrant, etc.
Not that i'm aware of. I initially had a repl friendly reitit setup going without state managers.
I may be incorrect on it, but I didn't have good experiences with reloadability last time I tried it, some while ago.
This is a more general problem. Making and keeping things REPL friendly in Clojure has a learning curve. Similar to making things HMR friendly in the front end.
In the case of Reitit, the reloading is described here: https://cljdoc.org/d/metosin/reitit/0.5.15/doc/advanced/dev-workflow
That could be one reason to consider using compojure-api over reitit, although reitit is second to none in terms of speed.
https://cljdoc.org/d/metosin/reitit/0.5.15/doc/misc/performance this has some good links and data
Please write an issue about reloadability, would be easy to add a dev
-mode, that compiles the route tree on each request.
I've had good experiences with #yada but JUXT now has a new project called "site". I haven't used that myself yet.
Thanks for the reference, this looks interesting especially because I was planning to use bitemporal db anyway
Malcolm/Jon have a rule that all our libraries must contain only 4 letters, no one knows why and at this point we're too afraid to ask
https://github.com/juxt/site - #juxt-site
a new entrant in the "least googgleable project name" competition :)
hi, what is the "equivalent" of an abstract class in Clojure? I'm trying to work with Apache Calcite from Clojure and they extend AbstractTable :
public abstract class AbstractTable implements Table, Wrapper {
protected AbstractTable() {
}
// Default implementation. Override if you have statistics.
@Override public Statistic getStatistic() {
return Statistics.UNKNOWN;
}
@Override public Schema.TableType getJdbcTableType() {
return Schema.TableType.TABLE;
}
@Override public <C extends Object> @Nullable C unwrap(Class<C> aClass) {
if (aClass.isInstance(this)) {
return aClass.cast(this);
}
return null;
}
@Override public boolean isRolledUp(String column) {
return false;
}
@Override public boolean rolledUpColumnValidInsideAgg(String column,
SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) {
return true;
}
}
What is the pattern of reuse for Clojure in this case?
I mean the implementations for unwrap, isRolledUp should be the same for most / all my implementation (let's call them MyTable)
Should I just define functions for each method and when when I implement each MyTable with reify
I need to delegate to the functions ?
I feel this will create some boilerplateHello macros
so this is a good use case for macros then. I haven't used macros and not a big fan of rushing into them. I kind of have a feeling it's going to get complicated. The first thing that comes to my mind is: what if I want to implement a method differently one time. Anyway, I decided to re-implement the csv java example they have in clojure and will try to send it upstream if it works. It would serve as an example 🙂
How does that work? I had to use proxy
and then in the end fall back to Java when dealing with certain Netty abstract classes. How do macros help there?
my question was: how can I deal with copy pasting the implementations for all the methods that make up the abstract class
you can also use functions
(defn foo-build [{:keys [foo-fn bar-fn]}]
(reify Interface (method [this] (foo-fn this ..)) ...))
The abstract implementations are provided by the macro, overriding implementations by the user
@UK0810AQ2: I'm new to this so, do you have an example I can follow? What I understood is that I can write a macro that I can call to define a new Table and the macro will handle default implementations for methos. When I do call the macro I will have the option to provide different implementations for some/all of the methods defined in the macro .
now that I write it, is kind of makes sense. Thanks, let's see when I get there - now it's project setup 🙂
another benefit to using functions in your method implementations is that you can avoid a lot of hassle / weirdness that comes with class reloading, since you can't change methods on instantiated classes, but if you change a function implementation the var lookup does the right thing on each invocation