This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-12-14
Channels
- # adventofcode (42)
- # babashka (37)
- # beginners (62)
- # cider (13)
- # clj-kondo (12)
- # cljdoc (1)
- # clojure (80)
- # clojure-australia (2)
- # clojure-dev (43)
- # clojure-europe (69)
- # clojure-italy (8)
- # clojure-nl (10)
- # clojure-switzerland (130)
- # clojure-uk (12)
- # clojurescript (23)
- # code-reviews (8)
- # cryogen (5)
- # cursive (6)
- # datomic (3)
- # duct (4)
- # emacs (12)
- # fulcro (60)
- # kaocha (7)
- # lambdaisland (4)
- # malli (4)
- # meander (1)
- # nrepl (31)
- # off-topic (2)
- # re-frame (16)
- # rewrite-clj (5)
- # shadow-cljs (11)
- # spacemacs (7)
- # xtdb (1)
anyone ever seen > Syntax error (VerifyError) compiling new at (/task/sync_databases_test.clj:143:1). > Operand stack underflow
Syntax error (VerifyError) compiling new at (********/task/sync_databases_test.clj:143:1).
Operand stack underflow
Exception Details:
Location:
********/task/sync_databases_test/MockJobExecutionContext.put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @8: areturn
Reason:
Attempt to pop empty stack.
Current Frame:
bci: @8
flags: { }
locals: { '********/task/sync_databases_test/MockJobExecutionContext', 'java/lang/Object', 'java/lang/Object' }
stack: { }
Bytecode:
0000000: 2a2b 2cb9 017e 0300 b0
Full report at:
/tmp/clojure-18430136797529807953.edn
Tests failed.
> Running with these options enables execution of Java programs that violate the Java Virtual Machine Specification. hmm. i'm hoping we're not purposefully emitting programs that violate the jvm spec
Hard to say without more of the stack trace to see where the method is being called but my guess is one of the interfaces you are pulling into the mockjobexecutioncontext is also defining a put method (JobExecutionContext) and defrecord implicitly defines put method (as a map) and something is getting confused about which method is being called
method resolution is slightly different between java8 and post java9, which could explain the put method confusion passing on java 8 but failing on java 11
I would really like to see the clojure code that produced a verifier error. (Shame on lein for disabling verification)
The verification was an explicit Arg we added here. This is another time I’ve been bitten by the stacktrace thrown into a random temp file on a machine in the cloud. Not a huge fan of that default
@U050ECB92 https://github.com/metabase/metabase/blob/remove-xverify/test/metabase/task/sync_databases_test.clj#L143-L149
Disabling the verifier is a bad idea, there is no good reason to do that (which is why you can’t in newer Java’s)
yeah. someone added this PR for exactly that reason. it doesn't work going forward and is deprecated in 13+ i think
If you can boil this into a small repro, would definitely like to see an ask question or jira ticket
i just added the option to print the stack trace to stderr so maybe that will give a bit more info
#error {
:cause "Operand stack underflow\nException Details:\n Location:\n metabase/task/sync_databases_test/MockJobExecutionContext.put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @8: areturn\n Reason:\n Attempt to pop empty stack.\n Current Frame:\n bci: @8\n flags: { }\n locals: { 'metabase/task/sync_databases_test/MockJobExecutionContext', 'java/lang/Object', 'java/lang/Object' }\n stack: { }\n Bytecode:\n 0000000: 2a2b 2cb9 017e 0300 b0 \n"
:via
[{:type clojure.lang.Compiler$CompilerException
:message "Syntax error compiling new at (/Users/dan/projects/clojure/metabase/test/metabase/task/sync_databases_test.clj:143:1)."
:data #:clojure.error{:phase :compile-syntax-check, :line 143, :column 1, :source "/Users/dan/projects/clojure/metabase/test/metabase/task/sync_databases_test.clj", :symbol new}
:at [clojure.lang.Compiler analyzeSeq "Compiler.java" 7115]}
{:type java.lang.VerifyError
:message "Operand stack underflow\nException Details:\n Location:\n metabase/task/sync_databases_test/MockJobExecutionContext.put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @8: areturn\n Reason:\n Attempt to pop empty stack.\n Current Frame:\n bci: @8\n flags: { }\n locals: { 'metabase/task/sync_databases_test/MockJobExecutionContext', 'java/lang/Object', 'java/lang/Object' }\n stack: { }\n Bytecode:\n 0000000: 2a2b 2cb9 017e 0300 b0 \n"
:at [java.lang.Class getDeclaredConstructors0 "Class.java" -2]}]
:trace
[[java.lang.Class getDeclaredConstructors0 "Class.java" -2]
[java.lang.Class privateGetDeclaredConstructors "Class.java" 3138]
[java.lang.Class getConstructors "Class.java" 1944]
[clojure.lang.Compiler$NewExpr <init> "Compiler.java" 2575]
[clojure.lang.Compiler$NewExpr$Parser parse "Compiler.java" 2667]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7107]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler analyze "Compiler.java" 6745]
[clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6120]
[clojure.lang.Compiler$FnMethod parse "Compiler.java" 5467]
[clojure.lang.Compiler$FnExpr parse "Compiler.java" 4029]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7105]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7095]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler access$300 "Compiler.java" 38]
[clojure.lang.Compiler$DefExpr$Parser parse "Compiler.java" 596]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7107]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7095]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler analyze "Compiler.java" 6745]
[clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6118]
[clojure.lang.Compiler$LetExpr$Parser parse "Compiler.java" 6436]
[clojure.lang.Compiler analyzeSeq "Compiler.java" 7107]
[clojure.lang.Compiler analyze "Compiler.java" 6789]
[clojure.lang.Compiler analyze "Compiler.java" 6745]
[clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6120]
it seems @U0NCTKEV8’s guess about deftype
versus defrecord
was correct. that's some amazing bytecode intuition
Hi. Is there an interface lower level than ILookup? I want to "proxy" lookups to a record field but can't figure out how to get record fields once I overwrite the ILookup interface for the record. So something like this:
(defrecord foo [id map]
ILookup
(valAt [o key]
(or (get o key)
(get-in o [map key])))
I'm guessing get
and get-in
here would create an infinite lookup loop. Is there a way to do that? ThanksWas trying to figure out what defrecord
does in the impl of ILookup it generates and I absolutely do not understand that magic. Essentially it amounts to (get __extmap key)
and I can't even figure out how this magical __extmap
gets into scope (a global or some special runtime thing?) and this
isn't even used. Confused
I think you just call the java .get on the map your record closes on? Potemkin has plenty of magic like this https://github.com/clj-commons/potemkin/blob/master/src/potemkin/collections.clj I also saw pohjavirta do something similar too. https://github.com/metosin/pohjavirta/blob/master/src/pohjavirta/request.clj
problem isn't in delegation - it'll work out of the box since record field value would probably implement its own ILookup. Problem is obtaining record field value in the first place since we are overriding this record's interface
Potemkin is cheating by rolling out its own type abstraction. I'd rather not go there
If you are changing lookup semantics you’re already there
This is what deftype is for
yeah that's what I figured. IIUC I'll have to extend all the usual interfaces the moment I switch to deftype
. Fair enough
I ended up solving the problem I had differently without proxying, cause in this case it lended itself to this other solution (typical - 9 out of 10 times you don't need special non Clojure sematics). But I still hoped that there was a simpler way to do such delegation.
The extmap is just fallback (when you assoc in extra stuff), defined fields go the mapcat's way which I think closes over the values https://github.com/clojure/clojure/blob/38bafca9e76cd6625d8dce5fb6d16b87845c8b9d/src/clj/clojure/core_deftype.clj#L194-L195
user=> (defrecord Bar [a])
user.Bar
user=> (.__extmap (assoc (->Bar 12) :c 42))
{:c 42}
are there any advantages/disadvantages of using clojure.test
over midje
. please feel free to share articles that can help me answer this question
By Sean Corfield, on this Slack some time ago: > I personally would also recommend not using Midje. It's considered non-idiomatic and drags in a lot of transitive dependencies that can be problematic. > Just use plain old clojure.test > Midje isn't compatible with any standard test runners or test tooling.
my projects run with both the cognitest test runner and leiningen, so you get the benefit of using more standard tools as well
I feel like when it comes to mocking/stubbing, clojure.test
is falling short. is midje better at this?
@USWTQB9RU You can consider 1) dynamic vars to swap out existing functions or make tests more flexible, 2) with-redefs
(watch out, not thread-safe)
With option 1) wouldn't I have to re-write the functions I would like to test to use dynamic vars to reference the functions I would like to stub?
sometimes it's worth it. E.g. if you're testing a function that does #(System/exit x)
that's pretty much your only option. Or use with-redefs.
the problem I've found with using with-redefs
is that the tests will not tell you when the stubbed function was not called with the correct/expected arguments; unless of course, you write these instructions into your stub. so, you may have to add this logic to every stub or write some kind of macro to do this. But midje
does it out of the box!
I'm starting to want to use midje. I just want you guys to check the math on why I'm about to use midje 😆
you have to write the expectations somewhere > unless of course, you write these instructions into your stub that would be the logical place to me.
it's a choice between code that's easy to reason about or some black box testing lib you will depend on
> clojure.test is simpler and less magical, with a larger ecosystem of tools and plugins. this is why I use clojure.test
Hi, what my options for sprinkling a few reactive components in a server side rendered Clojure app without going full SPA, is this doable with Rum? I'm looking to have form inputs filter the the db and return the results client side without incurring a full page refresh. #beginners #programming-beginners
you might get better answers in #clojurescript but I haven't seen anyone talk about using rum in years
@UG9U7TPDZ had started building a server side rendered reactive application using Reagent at https://github.com/kwrooijen/yggdrasil. But this is not yet production ready I think, but the idea of server side rendering but having Reagent at your disposal (and perhaps even connection with the backend) seems interesting and useful to me. Not sure if there are any other solutions for this
Except for this https://github.com/kwrooijen/yggdrasil-playground
@U2PGHFU5U Thanks, I'll check it out
@U01GD44GX2P This is doable in Rum, and exactly why I use it. I build a SaaS-type web app, where all the pages are HTML pages served by Rum components in .cljc files. Some are completely static, while others have quite complex behavior.
@U06BEJGKD thanks, that's exactly the type of set-up I had in mind. Glad to hear its being used successfully.
I am trying to create a Clojure Google Cloud Function and I have to specify the entrypoint of a leiningen console app (via lein create new app hello-world
):
$ gcloud functions deploy jar-example --entry-point=hello_world_core$_main --runtime=java11 --trigger-http --source=target/uberjar
This entry-point is not correct. /
is not allowed. Any suggestions on how to specify the entry-point
correctly?There are messages in the #google-cloud channel on how to do this. You need to create a Java file as a wrapper
hello_world.core$main or elloworld_core$_main or anything like that is almost certainly not correct
those are all "jvm" names for clojure functions, and the gcloud api will have no idea what to do with a clojure function
Thanks! I forgot the logic, this helps 🙂. Still get an error though with --entry-point=hello_world.core$_main
Build failed: build succeeded but did not produce the class "hello_world.core" specified as the function target: Error: class not found: hello_world.core; Error ID: fb35dca7
maybe bash substitution
Ah and with ‘’ it’s:
Invalid value 'hello_world.core$_main': Entry point name must contain only Latin letters (lower- or upper-case), digits, dot (.) and underscore (_), and must be at most 128 characters long. It can neither begin nor end with a dot (.), nor contain two consecutive dots (..).
you need to look at the documentation for gcloud functions and see what kind of thing it expects as an entry-point, instead of just putting the names of random things in
if entry-point takes a class name, you'll need to ensure that the named class exists in the jar file, and is not a class that is generated while loading clojure code, because gcloud almost certainly doesn't know about loading clojure code
and if it is a class name, that class almost certainly will need at least a specific method, but likely to implement some interface
originally posted this to #beginners for lack of a good idea to put it, @arthur recommended I post this here instead.
the only other library I can think of in the same space is https://github.com/hoplon/javelin, but it's cljs based. Another solution is to wrap functions using https://github.com/clojure/core.memoize and have it automatically cache repeated calculations.
thanks
Some related projects, although with a larger scope of running the tasks concurrently and maybe in a distributed manner: - https://github.com/framed-data/overseer - https://github.com/mikub/titanoboa - https://github.com/schmee/daguerreo