This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-08-22
Channels
- # announcements (9)
- # beginners (96)
- # calva (14)
- # cider (49)
- # clj-kondo (29)
- # cljsrn (5)
- # clojure (55)
- # clojure-dev (37)
- # clojure-europe (4)
- # clojure-italy (4)
- # clojure-nl (5)
- # clojure-spec (5)
- # clojure-switzerland (3)
- # clojure-uk (5)
- # clojurescript (172)
- # cursive (14)
- # datomic (3)
- # duct (1)
- # emacs (6)
- # fulcro (17)
- # jobs (1)
- # leiningen (6)
- # nrepl (11)
- # off-topic (26)
- # pedestal (2)
- # re-frame (20)
- # reagent (9)
- # remote-jobs (3)
- # shadow-cljs (67)
- # spacemacs (24)
- # specter (6)
- # test-check (3)
- # tools-deps (18)
to "activate" characters someone knows I have (swap! known-kanji union kanji)
how can I do a conditional to de-activate a character when someone clicks again?
(I think)
ah, bingo.
Are there any books or blog articles about debugging exceptions within futures, lazy evaluation, anonymous functions etc?
@caleb.macdonaldblack I can't think of anything off the top of my head -- but what's different about those contexts from regular "debugging exceptions"?
Stack traces are limited
For example here points the the first function called but my actual error is deep down the call stack (perhaps not "call stack" due to lazy eval and futures but you get the idea)
I don't get the idea based on that two line screenshot, I'm afraid, no.
Sorry I don't understand if call stack works the same way with lazy evaluation and concurrency as I'm not familiar with the internals of clojure. I'm wasn't sure if "Call Stack" was the right terminology.
But I'll try to find a comparing example
@seancorfield Looks like I might actually be having trouble with the cursive repl and not clojure itself
maybe not even cursive but just the repl
With that snippet. Executing the comment shows an error like my previous screenshot but the line number is the comment code I executed.
Nothing in the that error helps me find out that a
is where my error is
In a bare clj
REPL, I get this:
user=> (c nil)
Execution error (NullPointerException) at user/a (REPL:1).
null
And the full stack trace is available via *e
showing this
user=> *e
#error {
:cause nil
:via
[{:type java.lang.NullPointerException
:message nil
:at [clojure.lang.Numbers ops "Numbers.java" 1068]}]
:trace
[[clojure.lang.Numbers ops "Numbers.java" 1068]
[clojure.lang.Numbers divide "Numbers.java" 186]
[clojure.lang.Numbers divide "Numbers.java" 3877]
[user$a invokeStatic "NO_SOURCE_FILE" 1]
[user$a invoke "NO_SOURCE_FILE" 1]
[user$b invokeStatic "NO_SOURCE_FILE" 1]
[user$b invoke "NO_SOURCE_FILE" 1]
[user$c invokeStatic "NO_SOURCE_FILE" 1]
[user$c invoke "NO_SOURCE_FILE" 1]
(more stuff elided)So that shows it tried to do a divide on nil
inside a
called from b
called from c
Yea I get the same in my repl too.
So it looks like an issue I'm having with the cursive REPL then
I'll take this over to the cursive channel
Some tools try to be "helpful" about stacktraces but they're usually not actually helpful.
Yeah true. Thanks for the help. *e
is neat. I didn't know about that
With anonymous functions, you get the entire usable stacktrace but each anonymous function is compiled to a uniquely named class so that can be confusing at first. One trick there is to give your anonymous functions meaningful names, such as (fn my-func [x] ...)
instead of just (fn [x] ...)
and then you'll see my_func
in the stacktrace. But I think it's better just to get used to reading the stacktrace as-is without doing that.
With futures, you "lose" the exceptions altogether unless you are specifically try
/`catch`ing them -- but if you catch
them, you'll have the full stack trace from the top of that thread. I use com.taoensso/timbre
as an aid there: it has a logged-future
macro that is a drop-in replacement for future
but it will log any exceptions (without you needing to do anything else). Again tho', use it only if you need to -- the taoensso libraries drag in a bunch of stuff and you're really better off with plain ol' Java logging if you really want logging.
And with lazy evaluation, the "gotcha" is that the exception occurs when a collection is realized which might be some distance away from where it was created -- but given the stacktrace, you'll know what was being realized so you can usually trace back to where it was created and debug that by forcing realization of the full collection (if it isn't infinite) by adding doall
just while you figure it out.
In all of these cases, familiarity and experience mean you need these debugging aids less and less.
Thanks that's very helpful. My misconception was the clojure was not able to provide those stacktraces. But now I know it can.
For some reason loading code into the cursive repl doesn't give me any information in the exception. But running that code directly in the repl does.
Thank god. This has been painful.
I would expect, even in Cursive, that you can still retrieve the last exception in full somehow...
clojure as a new microservice. clojurescript wherever you use javascript (like a SPA served by your php backend)
yes, you could do that. if you want a new service in your php monolith, you could try creating a microservice in clojure for it instead of adding it to the monolith.
how would that look? how to add a service in clojure and make iot available to monolith in php?
an example would be new REST endpoints. the clojure microservice would only interact with the DB; the php monolith wouldn't need to be aware of it
@UKV8CA0UR read this book https://www.amazon.com/Building-Microservices-Designing-Fine-Grained-Systems/dp/1491950358
Why do you want to add clojure to a PHP project? For a particular reason? Or just cause its cool and to try something new? If it's to try something new, maybe try it on a new project instead.
thx for the responds. the reason is that the php monolith is used in production. I want to add new features in clojure and clojurescript without touching the core scripts for now. comparable to how visa and mastercard are still running the credit card transaction trough cobol code
@jarvinenemil thanks I will read that book too
my clojurescript app doesn't see my min build ;(
"what how do i min what's that????"
oh it's lein cljsbuild once min
@abdusalam http://www.japanesecomplete.com/compounds ^^ thanks for your help, it'll take time to get all the kanji up there xX 😄
I am using checkouts in a lein project. Is there a way I can "reload" a dependency without having to restart my REPL?
@mario.cordova.862 require
with :reload
or :reload-all
?
(require '[my.namespace :as alias] :reload)
which will force my/namespace.clj
to be reloaded (and recompiled)
(require '[my.namespace :as alias] :reload-all)
will reload all the namespaces that my.namespace
depends on as well, recursively.
@seancorfield That worked! Thanks! I wonder why this is not in any guide/docs?
(doc require)
has the info. I wish i would have used doc, apropos, dir, find-doc as a beginner more. There's a wealth of information in these. For instance the docstring of require has
>>> Flags
A flag is a keyword.
Recognized flags: :reload, :reload-all, :verbose
:reload forces loading of all the identified libs even if they are
already loaded
:reload-all implies :reload and also forces loading of all libs that the
identified libs directly or indirectly load via require or use
:verbose triggers printing information about each load, alias, and refer
and interestingly, the docstring of require has a version that's kinda shunned these days (require '(clojure zip [set :as s]))
@mario.cordova.862 Well... there are some caveats about reloading code like that (multimethods, for example) as well as old definitions staying around (e.g., if you rename a function, both versions stay loaded). I think a lot of the "restart the REPL" and the push for tools.namespace
for "refreshing" projects dates back to a time before people had really figured out a good, healthy REPL-driven development workflow.
Stu Halloway has a couple of great talks on that and Eric Normand has an entire online course about RDD (which I highly recommend to everyone -- it is totally worth the price!).
I tend to start a REPL and leave it running for days on end, just eval'ing every code change I make often before even saving the file, since I have a hot key for "evaluate top-level form"... make a small change in a function, ctl-, B
, move on to the next change without even saving the change. The key is to evaluate every small change as you make it, always. And to not be afraid to have (comment ,,,)
forms with scratch code in them that you can eval into the REPL to verify your code changes as you go along.
I (almost) never type into the REPL -- I eval code from files (either src
files, test
files, or from a (comment ,,,)
form inside one of those for scratch code).
Not specific to Clojure or Clojurecript, but what is the common way of designing API with Clojure(Script) for communication over the wire? As I am a beginner I am strongly biased towards RPC type of design because it seems to me I can just call function in my backend and the backend returns me the appropriate answer.
I find it is a lot about just adapting functions to whatever medium the api is exposed over
the one place "just do rpc" can have issues is your api needs to push events to clients
I really need to find a book in CLJS teaching all this haha
with clojure it is super easy to end up rolling a custom rpc format, but then, how do you document it, how do you explain how it works to clients, etc
I wrestled with this a bit on a chat server for work, my first pass of the api was sort of messaging passing, not really rpc over websockets, because internally the chat server was mostly message passing, the format of the messages defined in json-schema (generated from clojure specs)
but the json-schema described the data of the messages very well, but didn't do a good job of capturing the interactions and back and forth of the api
it also didn't do a good job distinguishing between async events and the rpc like part of the api, so I threw it out and we ended up going with graphql over websockets
the graphql schema does a good job of describing rpc like operations and async operations and the data formats
Hi, I have a question regarding js/cljs-interop. How can I translate the ...
js-operator to clojurescript?
js
below
await Font.loadAsync({
Roboto: require('native-base/Fonts/Roboto.ttf'),
Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf'),
...Ionicons.font,
});
cljs - missing the ionicons.font
:
(defonce font-roboto (js/require "native-base/Fonts/Roboto.ttf"))
(defonce font-roboto-medium (js/require "native-base/Fonts/Roboto_medium.ttf"))
(font/loadAsync {:Roboto font-roboto
:Roboto_medium font-roboto-medium}))
What do you mean RPC like operation?
Thanks! The web world is messed up compared to the world of data science.
@jarvinenemil is it not a merge
?
yeah I need to add #js ?
You could try to call the assign operator from JS?
yeah Object.assign should do it
for the ... part?
{foo: bar ...baz} becomes Object.assign({foo: bar}, baz)
ahhhh
in cljs that should be (js/Object.assign #js{:foo bar}, baz)
right?
not sure but i'll know in a second.. the repl is 🔥
I just remembered I have lumo
(cmd)cljs.user=> (def baz #js{:bar 1})
#'cljs.user/baz
(cmd)cljs.user=> (def foo #js{:baz 1})
#'cljs.user/foo
(ins)cljs.user=> (js/Object.assign foo baz)
#js {:baz 1, :bar 1}
worked like a charm, thanks for the help guys 🙂