This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-16
Channels
- # aleph (1)
- # announcements (16)
- # babashka (36)
- # beginners (62)
- # calva (15)
- # cider (21)
- # cljsrn (5)
- # clojure (84)
- # clojure-dev (3)
- # clojure-europe (22)
- # clojure-italy (2)
- # clojure-nl (2)
- # clojure-uk (3)
- # clojurescript (36)
- # core-async (2)
- # cursive (4)
- # datomic (8)
- # emacs (14)
- # events (1)
- # fulcro (4)
- # hyperfiddle (6)
- # introduce-yourself (3)
- # jobs (1)
- # leiningen (4)
- # lsp (100)
- # nrepl (3)
- # off-topic (36)
- # pathom (17)
- # podcasts-discuss (1)
- # polylith (4)
- # portal (14)
- # react (1)
- # reagent (3)
- # reitit (8)
- # releases (3)
- # remote-jobs (1)
- # reveal (7)
- # shadow-cljs (19)
- # sql (16)
- # web-security (3)
Hello, is there a way to do redirection for GET/POST requests with ring?
Like I want to be able to temporarily preserve backwards compatibility such that GET/POST to /_crux/query
to become GET/POST in /_xtdb/query
. I know there is ring.util.response/redirect
that doesn't seem to help for when it is a query. And I quite seem to get the handler needed unless I am to modify the library
Actually. After tinkering with it, I think in this method I still need to have the handler fn
(ring.util.response/redirect "/_xtdb/query)
was just producing {:status 302 :headers {"Location" "/_xtdb/query" :body ""}}
which isn't surprising i guess that's how ring works
HTTP 307 is a https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect, but wouldn't help if clients don't handle it.
How about just hooking up _xtdb/query
's handler to the _crux/query
route, or calling the former from the latter's handler? I.e. accept the request and handle the backwards compatibility server-side.
Honest question: We tend to prefer requiring stuff with :as
over using :refer
or use
. Why?
To easily know where a function is coming from.
This is why I like using import * as _
for lodash, so I know exactly where a function lives just by looking at its use
@U04V5VAUN it makes reading code without using an IDE or having 20 tabs open so much easier
both remove context from the function at the point of use
if you just see foo
,you have no indication of whether that's in the current namespace or from elsewhere (and with use
, you really need some level of static analysis to even tell where it came from). with refer
you at least have a list at the top of your file
for functions/macros acting as syntax, this removal of context can actually be a feature (like refer'ing >!
from core.async or a defwhatever macro)
Namespace prefixes aide me in both reading and writing code. Knowing where a function comes from at a glance is so nice. I really miss this every time i take another stab at using a scheme or other lisp. For writing, the prefix helps for autocomplete so much. And I just recently felt the pain of use
when a var with the same name was in both namespaces. I copied a var from the test ns and put it into the main namespace, and then later went into the test namespace. Since it used :refer :all
on the original namespace, I had a collision of var names. Super annoying. And this pitfall exists everywhere you use use
. Changing one namespace could break consumers anywhere. It is a nightmare
a little bit goes a long way :)
I never get dogmatic in my style. And its a good rule of thumb for how to decide when to use refer. So thanks 🙂
that’s an enormous block of text and I think you are asking for help making javascript code, which we aren’t really experts at here.
Interesting discussion about identifying special forms in editor for highlighting, #{let fn letfn loop}
all report :special-form true
in their metadata despite not being special forms and not being in (clojure.lang.Compiler/specials)
.
agree. so it sounds like anything reporting to be :special-form
is lying almost by definition
special forms basically define an interface between the language and the compiler and it is not surprising that you might want some kind of facade over that, and macros are an attractive way to implement that facade
but yeah, you cannot substitute a macro for a special form and have it work the same in all situations
yeah. i think this is just for syntax highlighting. and someone pointed out some things were both a macro and a special form which caused a double take leading us here
i don’t believe any of this is semantic and just started with thrown
being highlighted as a macro.
"special form" is not some much of a prescriptively defined notion, but something that just kind of arises out of writing a lisp with macros, the macros have to bottom out at some base language, and that base language needs to be understood by eval
Hey all; does anyone know how I can set a namespace, if I am calling into the clojure compiler from java? I am trying
Compiler.eval (RT.readString ("(in-ns 'user)"));
and seeing
Exception in thread "main" java.lang.IllegalStateException: Can't change/establish root binding of: *ns* with set
Don't remember all the details, but it requires some wiring around it: https://stackoverflow.com/a/70838660/564509
my vague notion here is that *ns*
is something that's designed to be part of a REPL
context, and Compiler.eval
is lower level, and doesn't have the kind of state tracking / session that a REPL provides and `*ns* is useful in
this came up because java was trying to call some clojure that, internally, ran (eval '(clojure.core/+ 2 3))
, and threw a
Caused by: java.lang.RuntimeException: No such var: clojure.core/+
in this case it was because *ns*
is clojure.core
by default, and the java code first evaluated a require
form that replaced the +
definition
so my goal here is to change namespaces FIRST to user
or something. checking that link now
Var.pushThreadBinding(..make-map-of-ns-to-some-ns...);
try {
...eval..
} finally {
Var.popThreadBinding();
}
I think ideally you wouldn't use Compiler.eval, RT.readString, or Var.* whatever, but would use the java api (https://clojure.github.io/clojure/javadoc/clojure/java/api/Clojure.html) to get a handle on clojure.core functions that do those things
hey, nice, that is better. I did get this working but let me give this a try
Using java.api.Clojure
works only if you need to do something simple, like call a known function with known arguments.
Without eval
, you can't do even (+ 1 2)
.
user=> (.invoke (clojure.java.api.Clojure/var "clojure.core/eval")
(clojure.java.api.Clojure/read "(+ 1 2)"))
3
user=>
user=> (try
(.invoke (clojure.java.api.Clojure/var "clojure.core/push-thread-bindings")
(.invoke (clojure.java.api.Clojure/var "clojure.core/hash-map")
(.invoke (clojure.java.api.Clojure/var "clojure.core/resolve")
(.invoke (clojure.java.api.Clojure/var "clojure.core/symbol")
"clojure.core/*ns*"))
(.invoke (clojure.java.api.Clojure/var "clojure.core/create-ns")
(.invoke (clojure.java.api.Clojure/var "clojure.core/symbol")
"whatever"))))
(.invoke (clojure.java.api.Clojure/var "clojure.core/eval")
(clojure.java.api.Clojure/read "(+ 1 2)"))
(finally
(.invoke (clojure.java.api.Clojure/var "clojure.core/pop-thread-bindings"))))
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: + in this context
user=>
my problem is that I was importing sicmutils.env
which knocked out +
from clojure.core., since *ns*
was bound to clojure.core
by default
so when I THEN tried to do (clojure.core/+ 1 2)
from java, clojure.core/+
had not just been shadowed but basically knocked out
// Needed to allow creating new namespaces.
Var.pushThreadBindings(RT.mapUniqueKeys(RT.CURRENT_NS, RT.CURRENT_NS.deref()));
try {
Compiler.eval(Clojure.read("(ns user" +
"(:refer-clojure :exclude [partial zero? + - * / ref compare = numerator denominator])" +
"(:require [pooty :as p] [sicmutils.env :refer :all]))"));
Compiler.eval(Clojure.read("(println \"in\" (ns-name *ns*)))"));
System.out.println(Compiler.eval (RT.readString ("(clojure.core/+ 1 2)")));
System.out.println
(Compiler.eval
(RT.readString
("(->infix (((exp D) (literal-function 'eff)) 'x))")));
} finally {
Var.popThreadBindings();
}
this works
Ah, no - I was evaluating different code. Eval'ing (ns user)
doesn't work, because it still requires *ns*
to be bound.
but, VERY annoyingly, :refer-clojure :exclude
does not silence warnings here
WARNING: = already refers to: #'clojure.core/= in namespace: user, being replaced by: #'sicmutils.env/=
ignore the space in that snippet!!! warnings still occur. edit, fixed.
@U2FRKM4TW my next example shows how to use clojure.java.api.Clojure to setup binding for *ns*
it is slightly incorrect, because I think you want the push outside of the try/catch, but I am too lazy to add the extra do to make it a nice single form for copying and pasting into the repl
Makes sense! So in the end, my Java version on SO seems to be doing the same thing but via a less ideal API.
and, despite commonly referring to special forms by the symbol that is the first part of the list, it is the whole list that is the special form (why it is a special form and not a special symbol)
*ns*
is basically "compilation context", it is used when compiling forms to resolve symbols, so if you are outside of a place where compilation is known to be happening (the repl, loading a file) then it won't be bound and not settable
for syntax highlighting the best thing to do is come up with your own name "most favored symbols" and then make those whatever you want, and it will always be correctly because it is your name and you define it
@hiredman The issue is a bit more general than syntax highlighting: the clj-kondo static analyzer emits information that other tools (like clojure-lsp) use. Should clj-kondo say in its analysis that when clojure.core/fn
is called, that this was a special form invocation or not? The medadata :special-form
makes this a bit blurry.
Perhaps it should follow what tools like tools.analyzer do, I haven't checked there, but I expect that it only says "special form" for special-symbol?
stuff
Agreed. It also doesn't behave like a special symbol here:
user=> (let [catch (fn [] :foo)] (catch))
:foo
@ericdallo In any case, you can use special-symbol?
+ the clojure.core
namespace to determine yourself in clojure-lsp if it's a special form.