Fork me on GitHub
#clojurescript
<
2018-04-28
>
thedavidmeister02:04:07

@mfikes @thheller hmmm, so it's actually a js file getting compiled into go, so i'm not sure if i can use that approach, but i'll try it out

aleksandr02:04:37

Do anyone know how to integrate the reagent with-let macro with Cursive IDE?

aleksandr02:04:49

Now It cannot identifies my bindings in the with-let macros

lloydshark02:04:10

@al.vyguzov There is a #cursive channel - you could try asking in there.

alvina12:04:22

i write a code which cause repl stuck in re-natal i am out get out it nomally :cljs/quit works in react-native environment it not working how can get rid of REPL[======] without restarting again

chadhs13:04:21

what’s a common pattern for reading in api keys or other secrets / environment vars to keep them out of source control? in clojure i’ve been using environ.

mfikes13:04:07

If you are using lein for example, you could set up :closure-defines as a compiler option, but have the values come from your environment variables by using code like ~(System/getenv "MYVAR")

mfikes13:04:02

:closure-defines is actually easier to use than the docs would lead you to believe https://twitter.com/mfikes/status/979048333850406913

thheller13:04:04

another option is to pass "config" data like this to your app on startup. something like <script src="/js/app.js"></script><script>your.app.init({key:"foo"});</script>

chadhs13:04:23

@mfikes that’s pretty interesting, would there be an option to do an either or like read from a file and from system env as a fallback?

mfikes13:04:46

@chadhs In lein you can execute any code you'd like after the ~

mfikes13:04:19

(That goes in your project.clj file and lein treats ~ in a special way

chadhs13:04:26

ah interesting, should be able to put something together to emulate the clj environ setup then

mfikes13:04:44

Or maybe even use environ somehow

chadhs13:04:00

at a high level it’s handy to have an edn file with “secrets” in a map that are outside of source control, but on deploy have environment vars defined via your deployment pipeline.

chadhs13:04:15

thnx again guys; think i have enough info to play with this idea more

justinlee20:04:24

are field accessors like -body considered first-class functions? I’m trying to pass one around as an argument but I’m getting a warning that my-ns/-body is an undeclared Var. but if i wrap it in a function, the warning goes away

thheller20:04:17

-body is just a normal symbol. .- is field access. no it is not a first class fn

justinlee20:04:37

hm i just confused the hell out of myself 🙂

mfikes20:04:49

There is memfn that could be used for functions... but nothing I can think of for field access.

mfikes20:04:39

#(.-body %) is about the best you could do, right?

pesterhazy20:04:49

I was just going to say that @mfikes

pesterhazy20:04:12

it can't be a function because property access is not a function call in js afaik

mfikes20:04:39

Right, it compiles down to obj.body

pesterhazy20:04:51

so a wrapper fn is needed if you want to pass it around

justinlee20:04:04

okay yes thanks that clarifies things for me. i got confused reading the last example in this block of examples, which passes -body. i wasn’t thinking clearly and assumed that was a property accessor, which of course it isn’t. does anybody know offhand what it’s referring to? https://github.com/JulianBirch/cljs-ajax#getpost-examples

pesterhazy20:04:44

I think this is just a convention used to signify "this is a protocol method"

mfikes20:04:47

Yeah, that is a fn, like (map -count [{:a 1} [1 2 3]])

pesterhazy20:04:09

it doesn't have any actual meaning to the compiler

mfikes20:04:59

Stu had mentioned that the -name convention came about around the time ClojureScript was being built, so it became prevalently used within its standard lib

mfikes20:04:32

The reason, IIRC, was to simply avoid collisions (and perhaps to make it look "private")

mfikes20:04:08

Reference: Clojure Inside Out talk

justinlee20:04:53

hm. but i will need to refer the symbol from the library so I’m referring to the right function, right? otherwise it’ll resolve to my-ns/-body and then it won’t dispatch correctly? sorry for the rudimentary questions--i still have issues figuring out protocols

mfikes20:04:18

Right, it is effectively symbol that refers to a var, just like any other

mfikes20:04:46

My -count example above is really cljs.core/-count

mfikes20:04:39

In other words, it is not a JavaScript method attached to an object that is just "there", like .foo

mfikes20:04:36

So, ajax.protocols/-body, or use an alias like ap/-body or, refer it.

justinlee20:04:47

interesting so you invoke the symbol defined on the protocol, not some implementation

mfikes20:04:52

Another example that may help illustrate: #'cljs.core/-count is the var that -count resolves to

mfikes20:04:35

Maybe to say it another way, the symbols you see in protocol definitions are vars, just like those created using def or defn. There may be subtle differences, but the stuff above is accurate.

pesterhazy20:04:53

it's sometimes helpful to see what js is generated

mfikes20:04:21

Another example, you can do (doc -count)

mfikes20:04:52

They are just vars; I mentally think of them that way. They show up in dir, etc.

mfikes20:04:23

The really cool thing about this is that protocols don't push you into a different model of working than working with functions created via defn. They, of course, have interesting dispatch semantics, based on the first argument, but otherwise they dovetail right in with the way the rest of the language works with functions.

mfikes20:04:49

If you do (type -count), you will see it is just a function like any other.

mfikes20:04:09

If you (set! *print-fn-bodies* true) and evaluate -count you will see a little of how it works

pesterhazy20:04:23

very helpful (to me) explanation @mfikes

mfikes20:04:03

If you are wondering how -count works, on, say [1] try (js-keys [1]) and you will see this in there: "cljs$core$ICounted$_count$arity$1"

justinlee20:04:32

okay I think I see. so you invoke the functions in the protocol, which do dynamic dispatch on their first arg. the various implementations for a given type get “attached” as they are loaded, somewhat similar to how the various implementations of a multimethod are loaded as you go. deftype, defrecord, and reify are just ways to providing an implementation for a given type. is that about right?

mfikes20:04:44

Yeah. The mechanics can change too. In Clojure they are kept in a separate place, so that you can extend a protocol to something that you can't modify, like String

mfikes20:04:03

But ignoring how it works under the hood, you are right

justinlee20:04:06

i think the part of this that eluded me is what impact it has to define a protocol with multiple methods. because in some sense each method seems to operate independently

mfikes20:04:16

Yeah, I think when satisfying a protocol you are supposed to satisfy all of the methods. But it seems you can get away with implementing a subset, and things still work.

justinlee20:04:50

okay great. thanks @mfikes! this has been super helpful

mfikes20:04:58

I'd have to go rummage through some Clojure references to clear up that last bit in my mind.

mfikes21:04:13

FWIW, I initially thought that you could, say refer to -body directly, with this mental model I think coming from my Java experience. I suspect it is a very common misunderstanding made initially by new Clojure devs.

justinlee21:04:32

now that i think about it, it’s the multiple-methods-in-a-protocol bit that has confused me. it has always seemed like it’s more about good self-documenting code than a piece of technology, but i’ve just been assuming that i’ve missed some critical bit

mfikes21:04:35

The "fix" is to just realize that they are vars and move on 🙂

mfikes21:04:21

Another interesting aspect is that protocols are meant to be easy for the implementors to satisfy; they aren't really there for clients. With that comes the recommendation that protocols have very few methods.

mfikes21:04:52

I think most of the protocols in ClojureScript have only 1 or 2 methods

jdkealy21:04:02

Hi, How would one instantiate a nested javascript object? LIke Vimeo.player I've tried

js/Vimeo.Player 
(.-Player js/Vimeo)

mfikes21:04:13

@jdkealy Try

(let [Ctor (.-Player js/Vimeo)] (Ctor.))

pesterhazy21:04:03

(js/Video.Player.) should work as well

pesterhazy21:04:38

or (new (.-Player js/Video))

mfikes21:04:24

In case this looks a bit mysterious: A dot at the end is handled during macroexpansion.

(macroexpand '(js/Video.Player.))
will illustrate a 4th way to construct a Player

mfikes22:04:07

For some reason, I still can't bring myself to put dots in symbols.

(let [x #js {:foo #js {:bar 42}}]
  x.foo.bar)
just bothers me

tokoma23:04:40

I'm trying to use google cloud vision in Clojurescript. I use npm-deps in project.clj as follows:

:npm-deps {
     "@google-cloud/vision" "*"
      :react "15.6.1" :react-dom "15.6.1"
 }
I could load react as follows:
(ns vision-api.core
  (:require react)))
How can I load @google-cloud/vision ?

mfikes23:04:48

@tokoma1 Have you tried using a string to require it, rather than a symbol?