Fork me on GitHub
#hyperfiddle
<
2023-07-13
>
Reut Sharabani13:07:35

I showed electric at work today and I described it as a way to write "fullstack functions"

Dustin Getz13:07:35

how did people respond

Reut Sharabani14:07:23

they liked it. Took them a while to understand because it was two backend-only devs but I could "hear" it when it clicked for them

👍 2
grounded_sage16:07:05

People out there writing one function serverless functions. We over here writing the whole application as a function.

2
😂 2
braai engineer13:07:24

Exception on Uberjar build: "Method code too large"

15:46:55,640 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@151bf776 - Registering current configuration as safe fallback point

Execution error (IndexOutOfBoundsException) at clojure.asm.MethodWriter/computeMethodInfoSize (MethodWriter.java:2061).
Method code too large!

Full report at:
/var/folders/3y/0kx0ddld5m116s7p_62h1ynr0000gp/T/clojure-11423849822174727895.edn
Execution error (ExceptionInfo) at clojure.tools.build.tasks.compile-clj/compile-clj (compile_clj.clj:112).
Clojure compilation failed, working dir preserved: /var/folders/3y/0kx0ddld5m116s7p_62h1ynr0000gp/T/compile-clj11185829201170148305

Full report at:
/var/folders/3y/0kx0ddld5m116s7p_62h1ynr0000gp/T/clojure-12005292496436482601.edn

braai engineer14:07:08

$ cat /var/folders/3y/0kx0ddld5m116s7p_62h1ynr0000gp/T/clojure-1088563969155590368.edn
{:clojure.main/message
 "Execution error (IndexOutOfBoundsException) at clojure.asm.MethodWriter/computeMethodInfoSize (MethodWriter.java:2061).\nMethod code too large!\n",
 :clojure.main/triage
 {:clojure.error/class java.lang.IndexOutOfBoundsException,
  :clojure.error/line 2061,
  :clojure.error/cause "Method code too large!",
  :clojure.error/symbol clojure.asm.MethodWriter/computeMethodInfoSize,
  :clojure.error/source "MethodWriter.java",
  :clojure.error/phase :execution},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message "Syntax error macroexpanding at (prod.clj:1:1).",
    :data
    {:clojure.error/phase :execution,
     :clojure.error/line 1,
     :clojure.error/column 1,
     :clojure.error/source "prod.clj"},
    :at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3719]}
   {:type java.lang.IndexOutOfBoundsException,
    :message "Method code too large!",
    :at
    [clojure.asm.MethodWriter
     computeMethodInfoSize
     "MethodWriter.java"
     2061]}],
  :trace
  [[clojure.asm.MethodWriter
    computeMethodInfoSize
    "MethodWriter.java"
    2061]
   [clojure.asm.ClassWriter toByteArray "ClassWriter.java" 457]
   [clojure.lang.Compiler compile "Compiler.java" 7909]
   [clojure.lang.RT compile "RT.java" 411]
   [clojure.lang.RT load "RT.java" 457]
   [clojure.lang.RT load "RT.java" 424]
...

braai engineer14:07:24

Trying to debug. When I eval my app namespace in REPL, I get this:

ERROR in () (:)
expected: (hyperfiddle.rcf/= (analyze {} (quote (try 1 (catch Exception e 2) (finally 3)))) [(ir/pub (ir/literal nil) (ir/bind 1 1 (ir/pub (ir/apply (assoc (ir/global :hyperfiddle.electric.impl.runtime/latest-first) :hyperfiddle.electric.debug/meta {}) (ir/apply (assoc (ir/global :hyperfiddle.electric.impl.runtime/bind) :hyperfiddle.electric.debug/meta {}) (assoc (ir/global :hyperfiddle.electric.impl.runtime/recover) :hyperfiddle.electric.debug/meta {}) (ir/apply (assoc (ir/global :clojure.core/some-fn) :hyperfiddle.electric.debug/meta {}) (ir/apply (assoc (ir/global :hyperfiddle.electric.impl.runtime/clause) :hyperfiddle.electric.debug/meta {}) (ir/apply (assoc (ir/global :clojure.core/partial) :hyperfiddle.electric.debug/meta {}) (ir/inject 0) (assoc (ir/constant (ir/pub (ir/apply (assoc (ir/global :hyperfiddle.electric.debug/unwrap) :hyperfiddle.electric.debug/meta {}) (assoc (ir/node 0) :hyperfiddle.electric.debug/name (quote hyperfiddle.electric.impl.compiler/exception) :hyperfiddle.electric.debug/scope :dynamic)) (ir/apply (ir/literal {}) (ir/sub 1) (ir/pub (assoc (ir/node 0) :hyperfiddle.electric.debug/name (quote hyperfiddle.electric.impl.compiler/exception) :hyperfiddle.electric.debug/scope :dynamic) (ir/apply (ir/literal {}) (ir/sub 1) (ir/bind 1 1 (ir/literal 2))))))) :hyperfiddle.electric.debug/type :catch :hyperfiddle.electric.debug/args (quote [Exception e]))) (assoc (ir/global :java.lang.Exception) :hyperfiddle.electric.debug/meta {}))) (assoc (ir/constant (ir/literal 1)) :hyperfiddle.electric.debug/type :try :hyperfiddle.electric.debug/meta nil)) (assoc (ir/constant (ir/literal 3)) :hyperfiddle.electric.debug/type :finally)) (ir/apply (ir/literal {}) (ir/sub 1) (ir/pub (ir/literal 0) (ir/apply (ir/literal {}) (ir/sub 1) (ir/bind 2 1 (ir/variable (ir/sub 2))))))))) (ir/do [] (ir/do [(ir/target []) (ir/target []) (ir/target []) ir/source] ir/nop))])
  actual: clojure.lang.ExceptionInfo: Unable to resolve symbol: hyperfiddle.electric/trace
{:in [(clojure.core/binding [hyperfiddle.electric/trace hyperfiddle.electric.impl.compiler/exception] 2)]}
 at hyperfiddle.electric.impl.compiler$analyze_form.invokeStatic (compiler.clj:643)
    hyperfiddle.electric.impl.compiler$analyze_form.invoke (compiler.clj:628)
dunno if it could be related?

braai engineer14:07:11

Fixed by bumping Electric to latest starter app version: v2-alpha-349-ge9996713

🙌 2
Dustin Getz16:07:58

We have never seen this

markaddleman17:07:47

JVM method size is limited to 64k, I think. The way clojure compiles data structure literals, large data structures can exceed this limit. Easiest work around is to split the function into smaller functions

👀 2
braai engineer08:07:35

It's possible there was some weird cache thing in target/classes and by changing deps it cleared cache 🤷 ? Not going to investigate further.

braai engineer08:08:40

Using v349 getting this Method code too large error again on a project I haven't touched in a while when building uberjar on host machine (not in Docker). I'm guessing it's something Java / deps related and not about Electric, so gonna try clear deps cache and see if it helps.

{:clojure.main/message
 "Execution error (IndexOutOfBoundsException) at clojure.asm.MethodWriter/computeMethodInfoSize (MethodWriter.java:2061).\nMethod code too large!\n",
 :clojure.main/triage
 {:clojure.error/class java.lang.IndexOutOfBoundsException,
  :clojure.error/line 2061,
  :clojure.error/cause "Method code too large!",
  :clojure.error/symbol clojure.asm.MethodWriter/computeMethodInfoSize,
  :clojure.error/source "MethodWriter.java",
  :clojure.error/phase :execution},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message "Syntax error macroexpanding at (prod.clj:1:1).",
    :data
    {:clojure.error/phase :execution,
     :clojure.error/line 1,
     :clojure.error/column 1,
     :clojure.error/source "prod.clj"},
    :at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3719]}
   {:type java.lang.IndexOutOfBoundsException,
    :message "Method code too large!",
    :at
    [clojure.asm.MethodWriter
     computeMethodInfoSize
     "MethodWriter.java"
     2061]}],
  :trace
  [[clojure.asm.MethodWriter
    computeMethodInfoSize
    "MethodWriter.java"
    2061]
   [clojure.asm.ClassWriter toByteArray "ClassWriter.java" 457]
   [clojure.lang.Compiler compile "Compiler.java" 7909]
   [clojure.lang.RT compile "RT.java" 411]
   [clojure.lang.RT load "RT.java" 457]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6908 invoke "core.clj" 6161]
   [clojure.core$load invokeStatic "core.clj" 6160]
   [clojure.core$load doInvoke "core.clj" 6144]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5933]
   [clojure.core$load_one invoke "core.clj" 5928]
   [clojure.core$load_lib$fn__6850 invoke "core.clj" 5975]
   [clojure.core$load_lib invokeStatic "core.clj" 5974]
   [clojure.core$load_lib doInvoke "core.clj" 5953]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$load_libs invokeStatic "core.clj" 6016]
   [clojure.core$load_libs doInvoke "core.clj" 6000]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 669]
   [clojure.core$require invokeStatic "core.clj" 6038]
   [clojure.core$require doInvoke "core.clj" 6038]
   [clojure.lang.RestFn invoke "RestFn.java" 619]
   [prod$loading__6789__auto____140 invoke "prod.clj" 1]
   [clojure.lang.AFn applyToHelper "AFn.java" 152]
   [clojure.lang.AFn applyTo "AFn.java" 144]
   [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3714]
   [clojure.lang.Compiler compile1 "Compiler.java" 7748]
   [clojure.lang.Compiler compile1 "Compiler.java" 7738]
   [clojure.lang.Compiler compile "Compiler.java" 7815]
   [clojure.lang.RT compile "RT.java" 411]
   [clojure.lang.RT load "RT.java" 457]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6908 invoke "core.clj" 6161]
   [clojure.core$load invokeStatic "core.clj" 6160]
   [clojure.core$load doInvoke "core.clj" 6144]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5933]
   [clojure.core$compile$fn__6913 invoke "core.clj" 6171]
   [clojure.core$compile invokeStatic "core.clj" 6171]
   [clojure.core$compile invoke "core.clj" 6163]
   [user$eval136$fn__137 invoke "compile.clj" 5]
   [clojure.lang.AFn applyToHelper "AFn.java" 152]
   [clojure.lang.AFn applyTo "AFn.java" 144]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1990]
   [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1990]
   [clojure.lang.RestFn invoke "RestFn.java" 425]
   [user$eval136 invokeStatic "compile.clj" 1]
   [user$eval136 invoke "compile.clj" 1]
   [clojure.lang.Compiler eval "Compiler.java" 7194]
   [clojure.lang.Compiler load "Compiler.java" 7653]
   [clojure.lang.Compiler loadFile "Compiler.java" 7591]
   [clojure.main$load_script invokeStatic "main.clj" 475]
   [clojure.main$script_opt invokeStatic "main.clj" 535]
   [clojure.main$script_opt invoke "main.clj" 530]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :cause "Method code too large!",
  :phase :execution}}

braai engineer08:08:10

Different error happens when building in a Docker:

#26 39.28 -> Closure - Optimizing ...
#26 42.93 Optimizing CLJS Constants took 187ms
#26 159.0 Execution error (StackOverflowError) at com.google.javascript.jscomp.CodeGenerator/add (CodeGenerator.java:201).
#26 159.0 null
#26 159.0 
#26 159.0 Full report at:
#26 159.0 /tmp/clojure-11715170771542413787.edn
------
Dockerfile:24
--------------------
  22 |     ARG REBUILD=unknown
  23 |     ARG VERSION
  24 | >>> RUN clojure -X:build uberjar :jar-name "opentax.jar" :version '"'$VERSION'"' :optimizations :advanced :verbose true
  25 |     
  26 |     FROM amazoncorretto:11 AS app
--------------------
ERROR: failed to solve: process "/bin/sh -c clojure -X:build uberjar :jar-name \"opentax.jar\" :version '\"'$VERSION'\"' :optimizations :advanced :verbose true" did not complete successfully: exit code: 1

braai engineer10:08:16

Pushed to Dokku and it seems to build 🤷 . So must be deps state issue

Dustin Getz10:08:11

i am traveling next 4 days but something to check is the heap size JVM flags, we customize this in the starter app

👍 2
Dustin Getz10:08:27

i think this probably is related to electric, we have macroexpansion size problems and compile time memory problems (incremental compilation is the next step)

👍 2
s-ol17:07:21

I'm having issues with core.match: > An error occurred while generating code for the form. > ExceptionInfo: failed compiling constant: interface clojure.lang.IPersistentVector; java.lang.Class is not a valid ClojureScript constant.

s-ol17:07:50

in e/server context:

(match path
                  [:link :tink]
                  "test"

                  :else
                  (new NotFound))))))))))

s-ol17:07:20

namespace:

(ns seshat.core
  ....

  #?(:clj (:require [clojure.core.match :refer [match]]
                    [seshat.state :refer [bindings]]
                    [datomic.api :as d])
     :cljs (:require [cljs.core.match :refer-macros [match]])))

s-ol17:07:12

if ti comment out the first pattern it works. Seems like as soon as I introduce a vector pattern it stops working

s-ol17:07:48

empty pattern also breaks

s-ol17:07:18

otoh map patterns don't seem to upset it

Dustin Getz17:07:20

I'm not surprised, just wrap it in a clojure lambda (inline or extract a fn) as a workaround

Dustin Getz17:07:43

We'd have to take a look at what it is doing, perhaps we are missing some feature, or perhaps it is doing Bad Stuff

s-ol17:07:43

but if I want to call e/fn's inside?

s-ol17:07:54

this is supposed to be my router

Dustin Getz17:07:12

Send me what you have so I can grok the specifics

s-ol17:07:41

more complete / real world:

(let [[path query hash] history/location]
              (e/server
                (match path
                  [:link :tink & rest]
                  (new tink/LinkAccount rest query)

                  [:account type id]
                  (new account/View (e/client (keyword (name type) id)) hash)

                  :else
                  (new NotFound))))))))))

👀 2
Vincent17:07:24

newb question: is new x the same as (x.) ?

yes 2
Vincent17:07:02

ok cool. hmmm. make sure id is not a different value than you expect.

Vincent17:07:08

might need a different alias depending on where nested

Vincent17:07:16

(my newb guess!)

Dustin Getz17:07:33

@U05AL1ZH8TW might be worth trying one of the other match libs

Dustin Getz17:07:52

I will need to remember how core.match works it has been a long time

s-ol17:07:01

@U09K620SG for your reference, here's the macroexpand of a simpler case that also breaks:

(macroexpand '(match 123
                     [:a :b] "a b"
                     :else "else"))
=>
(let*
 [ocr-56553 123]
 (try
  (clojure.core/cond
   (clojure.core/and (clojure.core/vector? ocr-56553) (clojure.core/== (clojure.core/count ocr-56553) 2))
   (try
    (clojure.core/let
     [ocr-56553_0__56555 (clojure.core/nth ocr-56553 0)]
     (clojure.core/cond
      (clojure.core/= ocr-56553_0__56555 :a)
      (try
       (clojure.core/let
        [ocr-56553_1__56556 (clojure.core/nth ocr-56553 1)]
        (clojure.core/cond (clojure.core/= ocr-56553_1__56556 :b) "a b" :else (throw clojure.core.match/backtrack)))
       (catch
        Exception
        e__38244__auto__
        (if
         (clojure.core/identical? e__38244__auto__ clojure.core.match/backtrack)
         (do (throw clojure.core.match/backtrack))
         (throw e__38244__auto__))))
      :else
      (throw clojure.core.match/backtrack)))
    (catch
     Exception
     e__38244__auto__
     (if
      (clojure.core/identical? e__38244__auto__ clojure.core.match/backtrack)
      (do (throw clojure.core.match/backtrack))
      (throw e__38244__auto__))))
   :else
   (throw clojure.core.match/backtrack))
  (catch
   Exception
   e__38244__auto__
   (if (clojure.core/identical? e__38244__auto__ clojure.core.match/backtrack) (do "else") (throw e__38244__auto__)))))

Dustin Getz17:07:23

exceptions as control flow + electric smells like trouble, that hits us right in a problem area of interop

👀 2
s-ol17:07:24

stack trace for that one:

[:dev] Build failure:
------ ERROR -------------------------------------------------------------------
 File: /home/s-ol/Documents/other/seshat/src/user.cljs:7:1
--------------------------------------------------------------------------------
   4 |     hyperfiddle.electric
   5 |     hyperfiddle.electric-dom2))
   6 | 
   7 | (def electric-main
-------^------------------------------------------------------------------------
An error occurred while generating code for the form.
ExceptionInfo: failed compiling constant: interface clojure.lang.IPersistentVector; java.lang.Class is not a valid ClojureScript constant.
	cljs.compiler/fn--4087 (compiler.cljc:306)
	cljs.compiler/fn--4087 (compiler.cljc:303)
	clojure.lang.MultiFn.invoke (MultiFn.java:229)
	cljs.compiler/emit-constant-no-meta (compiler.cljc:285)
	cljs.compiler/emit-constant-no-meta (compiler.cljc:277)
	cljs.compiler/emit-constant (compiler.cljc:301)
	cljs.compiler/emit-constant (compiler.cljc:297)
	cljs.compiler/emit-constants-comma-sep/fn--4122/fn--4123 (compiler.cljc:417)
	clojure.core/map-indexed/mapi--8638/fn--8639 (core.clj:7378)

s-ol17:07:03

I was surprised to see how much stuff that little expression generates!

Dustin Getz17:07:15

it's optimized (i think? in theory?)

Dustin Getz17:07:30

is that in a e/server or an e/client?

s-ol17:07:37

e/server

s-ol17:07:41

@U09K620SG any recommendation for core.match alternatives (esp if you've tried them in electric)

Dustin Getz17:07:47

we haven't checked any of them

s-ol17:07:59

also taking general suggestions then, not finding much tbh since core.match seems to be getting traction

Vincent17:07:47

learning how core.match works via errors is... interesting xD

s-ol17:07:07

> 13 years ago 😬

Dustin Getz17:07:27

But uses spec - we haven't checked that either

Dustin Getz17:07:39

actually maybe we have, I think we do have stuff using spec actually

s-ol17:07:08

that one doesn't do destructuring, which is half the benefit of using pattern matching for routing

s-ol17:07:17

matchure also seems to do wonky things

s-ol17:07:32

no big deal, I'll go back to hand-rolled logic here

s-ol17:07:06

(cond and let)

Dustin Getz17:07:49

Do you have a one-liner demonstrating the requirement wrt destructuring, do you just mean this : [:account type id]

s-ol17:07:17

i guess i can do a match and then a let with destructuring

s-ol17:07:30

but at that point i can do the condition with cond and be as brief

Dustin Getz17:07:08

(e/defn Todo-list []
  (e/client
    (dom/h1 (dom/text "core.match test"))
    (dom/pre 
      (dom/text 
        (pr-str
          (e/server 
            (match [:b]
              [:a] "A"
              [x] x
              :else "fail")))))))
this much is working for me

s-ol17:07:36

huh, interesting

Dustin Getz17:07:40

i can rep your error, which is also a type error right?

s-ol17:07:29

can or cant?

Dustin Getz17:07:01

(match 123 x x :else "fail") works

s-ol17:07:03

I'm not sure? it doesn't say type error anywhere but it complains about something being a class rather than a constant

s-ol17:07:08

see stack trace above

Dustin Getz17:07:16

(match 123 [x] x :else "fail") is a weird compiler error

s-ol17:07:28

okay yes, that's what I saw as well

Dustin Getz17:07:56

clj꞉user꞉> (require '[clojure.core.match :refer [match]])
nil
clj꞉user꞉> 
(match 123 x x :else "fail")
123
clj꞉user꞉> 
(match 123 [x] x :else "fail")
"fail"
at JVM repl this works

Dustin Getz17:07:07

so it's confirmed an electric interaction afaict

Dustin Getz17:07:04

well the good news is I tested every usage in the basic tutorial and only one failed, the vector match

Dustin Getz17:07:37

So my concerns about exception control flow seems to be not an issue

Dustin Getz17:07:58

aaaand it worked in clojurescript (e/client), it only fails in e/server

Dustin Getz18:07:27

I'll ticket it at this point, it is likely a simple bug in electric

Dustin Getz18:07:24

minimal repro is (match [[1]] [[1]] 'pass), it's the matching of the vector type. (match [1] [1] 'pass) passes

Dustin Getz18:07:53

Do you really need to match an inner vector? If your paths have static width i dont think you will hit this

Dustin Getz18:07:53

The core.match wiki implies this is just an optimization anyway for random access matching

Dustin Getz18:07:02

For matching dynamic args the sequence syntax works (as a workaround)

(match [[:foo :bar 1 2 3]]
  [([:foo x & args] :seq)] args) ; works

; compare to 

(match [[:foo :bar 1 2 3]]
  [[:foo x & args]] args) ; crash
cursed syntax though

2
Dustin Getz18:07:24

Don't you want the route matching to happen on the client anyway?

Dustin Getz18:07:03

works

(e/defn Baz [a] (dom/text "Baz" (pr-str a)))
(e/defn Bar [a] (dom/text "Bar" (pr-str a)))

(e/defn Todo-list []
  (e/client
    (dom/h1 (dom/text "core.match test"))
    (dom/pre 
      (let [page [:foo :bar 1]]
        (match [page]
          [[:foo :baz a]] (Baz. a)
          [[:foo :bar a]] (Bar. a)
          :else (dom/text "404"))))))

s-ol10:07:20

had moved it to server as a convenience since the views are server-colored so were all wrapped in e/server but yeah I'll try client!

s-ol10:07:50

away from computers this weekend but I don't think I had nested vectors? iirc I had this issue with top-level vector matches

Dustin Getz11:07:22

you mean fixed arity tuples? (the core.match syntax is cursed, one or both of us may be confused)

Dustin Getz11:07:01

in the matches, [] just means “pattern row” according to a footnote at the bottom of one of the wiki pages

Dustin Getz12:07:15

> moved [router] to server as a convenience since the views are server-colored so were all wrapped in e/server but yeah I'll try client! note that the variable inputs to the router are a user interaction on the client, so your DAG looks something like this: user event -> router -> views. So it doesn't seem to matter whether the router is on the client or server i.e., both of these factorings are the same: [client: event] -> [server: router -> views] [client: event -> router] -> [server -> views]

Dustin Getz12:07:54

Note that a UI may have client-only pages (i.e. storing local state in URL), in which case the factorings are no longer the same and co-locating the router with the user interaction becomes preferred to avoid a superfluous round trip

s-ol11:07:22

yeah, it has little impact in my case. With "for convenience" I guess I really meant brevity; having one e/server around the whole router block vs one e/server per each View being invoked

s-ol11:07:09

might be the case that some network round trips could be eliminated but I'm not attempting any optimization at this point

s-ol11:07:02

> in the matches, [] just means “pattern row” according to a footnote at the bottom of one of the wiki pages > hm, indeed I am confused now. Will get back to you about this when I next give it a go

s-ol15:07:58

okay, so: e/client (match) is working great, thanks for reminding me to try it out again. the pattern vs pattern row thing is a bit confusing. I'm currently using a single [] syntax to match against a flat vector-of-strings value:

(e/server
               (match hash
                 [:tx :new]
                 (new transaction/View "new-tx" {"new-tx" {:tx/label "new transaction"}})
                                                           ;:tx/value-time (new js/Date)}})
                 ;[:tx id]
                 ;(new transaction/View (js/parseInt id) nil)

                 nil nil

                 :else
                 (new NotFound))

               (match path
                 [:link :tink & rest]
                 (new tink/LinkAccount rest query)

                 [:account type id]
                 (new account/View (e/client (keyword (name type) id)) hash)

                 :else
                 (new NotFound))))))))))
this works e/client and fails in e/server with the IPersistentVector error posted above

s-ol15:07:59

in the wiki section on https://github.com/clojure/core.match/wiki/Overview#vector-matching they use [[a b]] which suggests that the "outermmost [] is special", but they also have an example with "https://github.com/clojure/core.match/wiki/Overview#matching-single-variables" without any wrapping which is odd again. I've tried doubling-up to (match [hash] [[*:tx :new*]] (new ... but am getting the same error on e/servre

Dustin Getz15:07:04

i agree that the "single variable" section seems exceptional

Dustin Getz15:07:30

I am confident enough now to just state that core.match has cursed syntax and sucks actually

😄 2