This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-23
Channels
- # bangalore-clj (5)
- # beginners (136)
- # boot (1)
- # bristol-clojurians (6)
- # cider (46)
- # cljs-dev (172)
- # cljsrn (35)
- # clojure (82)
- # clojure-china (2)
- # clojure-dev (9)
- # clojure-dusseldorf (1)
- # clojure-finland (15)
- # clojure-italy (54)
- # clojure-norway (4)
- # clojure-russia (6)
- # clojure-spec (19)
- # clojure-uk (61)
- # clojurebridge (1)
- # clojurescript (55)
- # community-development (23)
- # cursive (7)
- # datomic (19)
- # emacs (10)
- # events (4)
- # fulcro (108)
- # graphql (7)
- # hoplon (1)
- # leiningen (7)
- # lumo (14)
- # off-topic (68)
- # onyx (23)
- # parinfer (8)
- # portkey (40)
- # precept (11)
- # re-frame (5)
- # reagent (40)
- # ring-swagger (5)
- # shadow-cljs (58)
- # specter (5)
- # tools-deps (37)
- # unrepl (13)
- # vim (9)
- # yada (12)
Hello, I am trying to make a synchronous http request with clojurescript. I tried installing clj-http
but got the following error
Failed to compile build :app from ["src" "env/dev/cljs"] in 14.445 seconds.
---- Could not Analyze src/myproject/core.cljs ----
No such namespace: clj-http.client, could not locate clj_http/client.cljs, clj_http/client.cljc, or JavaScript source providing "clj-http.client"
I think this is because clj-http
is clojure instead of clojurescript?
Here is my project.clj
...
:dependencies [clj-http "3.8.0"]
...
Any help would be appreciated!The error is coming from the line (:require [clj-http.client :as client])
in my core.cljs
Is there a core function for repeating a function n times on a literal. Eg I want to multiply a number n times by another number.
@edward.banner Yes, clj-http
is a Clojure-only project. https://github.com/dakrone/clj-http/tree/master/src/clj_http
You could try this library instead https://github.com/r0man/cljs-http
@seancorfield thanks for the link. However it doesn't look like cljs-http
does synchronous http requests. What I want to do is a make a request and then play around with the result outside a (go ..)
block
@edward.banner you might want to try https://github.com/JulianBirch/cljs-ajax
Luminus template might be a good start for creating a simple clojure+clojurescript application. See http://www.luminusweb.net/docs/profiles.md I think that +re-frame
will automatically gives you a little example using cljs-ajax although it might be a bit of overkill for you.
Well, that's JS for you -- it's single-threaded so you need to collaborate with the runtime on any blocking operations.
Got it. Well do you have any suggestions for accessing a variable outside a (go ..)
block then? https://stackoverflow.com/questions/36630320/get-information-out-of-go-block looks relevant but there was no clear solution there
I thought something like
(go (let [response (<! (http/get ""))]
(def R response)))
would work and I would be able to play around with R
. But it didn't workSorry, I don't use cljs -- and on the JVM you've got threads so you can do blocking takes from channels in different threads...
def
always defines a global top-level var -- you should not use that inside functions.
In JS, you're pretty much required to use async code to work around the lack of threading -- so you're going to have to use core.async
and go
blocks and structure your code accordingly, as far as I know.
Wow ok thanks. I'm new to javascript. So there's no way even in javascript to set a global variable with the response in a callback...?
I don't program in JS at all.
(and this sort of stuff is mostly why)
Sorry, I couldn't be more help. You could try the #clojurescript channel or #core-async to see if they have more useful advice...
@edward.banner you can definitely set an atom in a callback if you are just playing around in a repl
the mistake most people make is that they run an async operation and then try to read that atom immediately in the code below it and it will never be set because the async operation doesn’t run until you relinquish control back to the event loop
i don’t really know how go blocks work in a repl, however, because they are big complicated macros that compile down to a state machine. clojurescript repls work in mysterious ways
try
(def r (atom nil))
(go (let [response (<! (http/get ""))]
(reset! r response)))
then evaluate @r
in the replYeah for some reason it doesn't work. It works fine when I do a (pr response)
in the go
block but not when I do a reset!
nor def
(go (let [response (<! (http/get "http://localhost:8000/lucky/foo"))]
(pr response)))
> {:status 200, :success true, :body {:foo "bar"}, :headers {"content-type" "application/json"}, :trace-redirects ["" ""], :error-code :no-error, :error-text ""}
(def r (atom nil))
(go (let [response (<! (http/get "http://localhost:8000/lucky/foo"))]
(reset! r response)))
> {:status 0, :success false, :body "", :headers {}, :trace-redirects ["" ""], :error-code :http-error, :error-text " [0]"}
now that is perplexing. the only time i’ve ever seen a :status 0
return code is on a CORS issue. i cannot fathom how changing the body of the let block could change the result.
@edward.banner what happens when you do both the print and the reset?
Huh I'm getting weird errors now. I can't confirm that they aren't causing the weird behavior I am seeing now so I'll try and fix them first
Errors like
base.js:677 goog.require could not find: cljs.tools.reader.impl.errors
goog.logToConsole_ @ base.js:677
goog.require @ base.js:709
(anonymous) @ commons.cljs?rel=1521772505217:9
base.js:711 Uncaught Error: goog.require could not find: cljs.tools.reader.impl.errors
at Object.goog.require (base.js:711)
at commons.cljs?rel=1521772505217:9
goog.require @ base.js:711
(anonymous) @ commons.cljs?rel=1521772505217:9
base.js:677 goog.require could not find: cljs.tools.reader.impl.errors
goog.logToConsole_ @ base.js:677
goog.require @ base.js:709
(anonymous) @ reader.cljs?rel=1521772505574:9
base.js:711 Uncaught Error: goog.require could not find: cljs.tools.reader.impl.errors
at Object.goog.require (base.js:711)
at reader.cljs?rel=1521772505574:9
goog.require @ base.js:711
(anonymous) @ reader.cljs?rel=1521772505574:9
base.js:677 goog.require could not find: cljs.tools.reader.impl.errors
goog.logToConsole_ @ base.js:677
goog.require @ base.js:709
(anonymous) @ edn.cljs?rel=1521772505758:9
base.js:711 Uncaught Error: goog.require could not find: cljs.tools.reader.impl.errors
at Object.goog.require (base.js:711)
at edn.cljs?rel=1521772505758:9
if you have hot reloading going (e.g. figwheel) it may be easier to do this in a file and have it reload on save. the problem with debugging a repl sometimes is that you start accumulating a bunch of state
i mean just stick this stuff in a file and print to console. it’s almost as good as a repl 🙂
Hey @U8ES68TGX it turns out that the error stemmed from a configuration-related issue. Not sure what it was but setting a global variable inside the go
loop works now!
Of course, in real code you do not want to do that because it is unreliable and you’ll create a race condition. You’ll want to wait on the channel that go returns
How do I multiply a float?
@grounded_sage What are you attempting to accomplish? Do you need a float result or is double OK?
All good. It was my code. I was trying to multiply a string :rolling_on_the_floor_laughing:
@seancorfield Do you know how I can create a boot template from an existing project?
@mfiano No, not directly I'm afraid. That's a very interesting idea tho'... A "reverse template generator"...
Ok, I was just curious, because I have a bit of work into a project organization that I'd like future projects to follow.
I guess you'd want a way to walk the directory structure and generate the template code from it, and then you could go in and edit the files to put the "variables" into it all.
Go open a ticket against the boot-new
project and I'll have a think about it.
does slamhound fix up namespace paths in require
and ns
expressions for you, if you e.g. rename a source folder?
in my quick experiment it does not, admiteddly as a bad habit I really like renaming things on the go as my code evolves
Emacs-related: is there a way to make the repl print each element of a sequence on a new line? I'm using Brave and True to learn Clojure and the example outputs are so nicely formatted. I was wondering if I can achieve the same result.
If you are using cider in emacs for your repl you can add this to you init.el (setq cider-repl-use-pretty-printing t)
which should pretty print any results in the repl
Thanks! I've already tried toggling that option on and off but it didn't seem to have an effect.
Nikos press comma on a blank line in the repl and it will bring up a menu. Lots of good things there but you'll see the pretty printer option and you can just select it and press enter
I’m trying once more to work my way through modern-cljs. I’m 2/3 through tutorial 1 - and getting
clojure.lang.ExceptionInfo: Call to clojure.core/ns did not conform to spec:
In: [1] val: ((require [clojure.string :as string] [cljs.source-map.base64 :as base64])) fails spec: :clojure.core.specs.alpha/ns-form at: [:args] predicate: (cat :docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs.alpha/ns-clauses), Extra input
What should this point me to? I only have core.cljs
and build.boot
as files. core.cljs starts with (ns modern-cljs.core)
I think that was actually in cljs but was fixed long ago
I’m not specifying a version of clojure or clojurescript - I’m not sure how to determine what the defaults are that are being brought in.
yeah, this was in cljs and fixed in version 1.9.198
just dropped dependencies for clojurescript and clojure into build.boot - that fixed it.
What is a good rule of thumb to have for arguments to a function ? Should they be 1. positional arguments 2. keyword arguments 3. single argument which is a map which can contain the values as a key and can then be destructed in the defn.
Any pointers to resource where I can study about these kind designs would be great.
@schmee I was thinking along the same lines, so what would be a tipping point in favour of map ... for example if I am dealing with two values even if they are related sometimes I tend to use them as different positional arguments. however if they grow say more than 3 then I tend to use maps. I know that this is highly dependent on context but still is this a good default ?.
@shakdwipeea One common pattern that seems to be a good compromise is to have positional arguments for the common call use case, but a last argument that is a map, usually called opts
to carry optional arguments that "fine tune" the base behavior. Another common pattern is to introduce a "positional arity" that delegates to the one with the map arg, passing nil
for the map.
An example of that pattern: https://github.com/clojure/clojurescript/blob/7c754fbb9ffb9da790f21776d53a3b83deef922b/src/test/self/self_host/test.cljs#L81-L96
Thanks, this really clarifies a lot of my doubts.
If I had to guess, that pattern isn't used that prevalently. Most functions take positional arguments, but there are a class of them (maybe 10% or 20% that thread opts through). It makes for a nice escape hatch when you need it.
Also, as John alluded to, it appears that keyword arguments was an experiment that fell out of favor.
I think the one place where I've seen that (keyword args) might make sense is when humans are typing in stuff to run things. For example ClojureScript REPL startup code employs this pattern in places, so you can just tack on :repl-verbose true
to the argument list, for exmple
This pattern actually fits perfectly to my use case . I had to pass some extra options for running some pipelines so was looking around for ways to do it.
This way the common params could be the positional params and the options for configuring the behaviour could go in a opts map.
Yeah, and it seems that you usually have a good feel for what is "required" vs. "optional"
The "threading" aspect of an opts
map starts to shine if you have a few layers in the call stack, and you just want to pass something down through it without changing any signatures.
I suppose that case can feel like a dynamic var, but with things being explicitly passed.
this is just amazing, I had not thought of it this way so I always had difficulty chaining together a common set of functionality. This way new functionalities could be added to the processing chain and those could be controlled by just tweaking the map being passed.
This also fits in with the mentality that Spec provides a mechanism to indicate that "if this key is in the map, then its value satisfies this predicate" but it doesn't provide a mechanism that would allow you to limit which keys go into the map.
I had seen a discussion about that, makes sense.
If you later decide a "required" argument is optional, you can also handle that fairly easily. For example: https://github.com/clojure/clojurescript/commit/3a6e71e4bb01f97c7a86f46bfed003a602ed5ad3
What is the idiomatic Clojure way to create a record with default field values?
I usually see a second constructor sort of function which applies default values to the new object
Ah so something with merge
like you would do with a regular hashmap?
The second function becomes your entry point and the first you name thing`-impl` or what have you. Yes exactly
This is what I came up with. This is also my first Clojure code written. How well is this?
(defrecord MapCell [x y carved? region features distance])
(def cell-defaults
{:carved? false
:features []
:distance -1})
(defn make-cell
[x y]
(map->MapCell (merge cell-defaults {:x x, :y y})))
right see how it's done here: https://github.com/clojure/clojurescript/blob/ed20adefce0d3f76154577ac36814f48a5107216/src/main/clojure/cljs/repl/browser.clj#L400
that’s fine. or just (defn make-cell [x y] (->MapCell x y false nil [] -1))
?
Ok. I'll probably make a macro because I can see this pattern used over and over again. I'm surprised there is nothing standard to make this a bit more concise.
I usually make an intentional constructor function that is responsible for things like defaults and enforcing invariants on the required parameters, then privatize the automatic constructors to prevent people from using them unawares.
Can you give an example?
sure, this is one I use in a bunch of places:
(defmacro privatize-constructors!
"Changes the default record constructor functions into private vars."
[type-name]
`(do (alter-meta! (var ~(symbol (str "->" type-name))) assoc :private true)
(alter-meta! (var ~(symbol (str "map->" type-name))) assoc :private true)))
so then you’d:
(defrecord Foo [a b x y])
(privatize-constructors! Foo)
(defn make-foo
[a b opts]
{:pre [(string? a) (some? b)]}
(map->Foo (merge {:x 5, :y true} opts {:a a, :b b})))
I see. Thanks
now all callers outside of the namespace who want to construct new foo instances must use make-foo
, or fall back to Java interop. Nothing stops someone from changing the record once constructed, of course - so you could still have non-string values in a
if you do (assoc foo :a 123)
but it does catch problems at construction time and provide a common place for defaults
I wasn't familiar with alter-meta!
or realized things have metadata
This causes me to think a bit 🙂
Is that the hashmap for like pre/post conditions too?
indeed - you could do a more verbose version like (when-not (string? a) (throw (IllegalArgumentException. "Argument 'a' must be a string!")))
which you might want to do in some cases, since preconditions can be disabled and also throw AssertionError
, which is not super friendly to callers
That's great. So the metadata is a hashmap before the function body for functions? and you use alter-meta!
for other forms?
not exactly - that map above is only for pre and post conditions. You can attach arbitrary metadata in a def
or defn
by attaching it to the symbol though, which is why these are equivalent:
(defn- do-thing
"Does a thing"
[x]
(println x))
(defn ^:private do-thing
"Does a thing"
[x]
(println x))
; fully expanded:
(def ^{:private true, :doc "Does a thing"} do-thing
(fn [x]
(println x)))
=> (defn ^{:foo 2 :bar 3} foo {:baz 4 :qux 5} ([] 42) {:fred 6 :wilma 7})
#'boot.user/foo
=> (meta #'foo)
{:baz 4, :fred 6, :bar 3, :ns #object[clojure.lang.Namespace 0xab8dcf8 "boot.user"], :name foo, :file "NO_SOURCE_FILE", :wilma 7, :column 1, :line 1, :qux 5, :foo 2, :arglists ([])}
Clojure keeps impressing me. Thanks for all the explanation
note that metadata aren't carried around with vars in cljs at runtime, like they are in clj
Nice to know. I haven't explored cljs yet
hey everyone, I found out a clojure boilerplate project that has a section for tests...right now it is the following
(ns my-stuff.core-test
(:require [clojure.test :refer :all]
[my-stuff.core :refer :all]))
(deftest a-test
(testing "FIXME, I fail."
(is (= 1 1))))
does someone have an example of how I can import my functions from core.clj inside src/my_stuff/core.clj
so that I can test it
so if you have a function my-stuff/foo
you can just use it as foo
in the test namespace
yeeah makes sense, I got it just now.
is it possible to run tests in a more verbose manner? with logs and such