Fork me on GitHub
#clojurescript
<
2017-04-28
>
ingared00:04:38

Does any one used RUM + D3 in ClojureScript ??

jimmy00:04:00

@ingared what is the problem do you have ?

ingared00:04:58

I’m using d3 (strokes) with rum , of all the examples I went through, HTML pages are accessing the compiled javascript files but not any of the clojure-script compoennets/ functions.

jimmy00:04:41

@ingared in venn-diagram do you draw d3 circle in did-mount ? When you draw them like in example, the body element and such is already available. In the case of reactjs, you need to draw them in did-mount, since the dom element is only available then.

ingared01:04:32

No I didn't write did-mount , will try .

ingared01:04:44

Thanks for the tip.

qqq02:04:01

searching for "cljs closure" brings up results, but not for this UI library

tbaldridge02:04:13

@qqq it comes with goog right? So you can just include it like any other goog library.

tbaldridge02:04:21

what happens if you do (:require [goog.ui Dialog]) from inside your CLJS project?

qqq03:04:17

@tbaldridge : good point; just to clarify: under this methd, I would be using the goog ui library in an "imperative" way and not in a "react" way right?

rgdelato03:04:39

you can usually wrap an imperative UI in a React component with componentDidMount/`componentWillUnmount` and then use it like a normal React component from the outside

jimmy03:04:33

@qqq the only draw back I've seen so far is those lib doesn't support server rendering. ( only if you need it )

john03:04:54

I have a macro where I'm trying to test if the second parameter is a vector, but what I have is always returning true.

(defmacro with-vec [fname & x]
  `(if (vector? ~(first x))
    (ex.core/do-my-apply ...
I've tried moving the ~ behind x and (vector?.. but the first then branch always executes.

nrussell03:04:58

@john does ~(first x) -> (first ~@x) work?

john03:04:52

I'll try

john04:04:23

nope... I guess I want the if branch to execute at compile time, not run time

john04:04:53

so I need to remove the unquote from behind the if I think

lincpa07:04:11

(defmacro with-vec [fname & x] (if (vector? (first x)) `(ex.core/do-my-apply ...

john03:04:16

Am I not unsplicing or unquoting properly there?

john03:04:40

oh, the first branch is always being executed

john04:04:29

So I've got this awesome macro where you can do (def t (an.ex/thread)) and then (on t (println "hi") (println "from thread t"))

john04:04:01

(for web workers)

john04:04:21

and I just upgraded the on macro so that if the second arg is a vector, that vector is used as the binding arguments in the code that is passed. But then the actual values of those bindings within the vector are also passed "over the wire" as arguments, which get filled in on the other side, as arguments to the implicit function that executes the body.

john04:04:58

So like, (def a {:a 1}) then (on t [a] (println (assoc a :b 2))) will print {:a 1, :b 2} in the worker thread.

john04:04:11

and if a is a TypedArray, it will transparently convert it to a Transferable and send it by reference.

john04:04:19

at least that's the idea.

claudiu09:04:15

Hello. Anybody know if there’s any way to change the pprint format for (pprint {:p1/a 1 :p1/b 2}) from #:p1{:a 1, :b 2} to {:p1/a 1, :p1/b 2} ?

bronsa09:04:13

(binding [*print-namespace-maps* false] (pprint ..))

claudiu09:04:05

@bronsa thank you. that did the trick 🙂

mseddon11:04:05

Ignore their silly bruteforce method of generating signed distance fields, you can do it in java efficiently if you look into proper algorithms

timgilbert14:04:50

Say, anyone have a recommendation for a rich-text input component that is react/reagent friendly and generates Markdown?

kommen14:04:02

@timgilbert I suggest look at https://github.com/ianstormtaylor/slate, you can define custom serializers, so depending of the content your users are writing it wouldn’t be too hard to generate markdown

drspatula14:04:09

@thheller that worked! That differs from the clojure syntax for multiple arity protocol methods though, doesn't it?

thheller14:04:59

don't think so?

thheller14:04:38

I think the syntax is different on extend-type extend-protocol

thheller14:04:11

yeah clojure throws spec errors

Alex Miller (Clojure team)14:04:45

you can’t use multi-arity fn syntax with protocols

drspatula14:04:42

that's what it was, I was looking at an extend-protocol example

drspatula14:04:52

thank you for your help!

Alex Miller (Clojure team)14:04:41

extend-protocol and extend-type use the same syntax as when embedded in defrecord/deftype

thheller14:04:37

I'm fairly certain I have written the arity syntax before though

Alex Miller (Clojure team)14:04:45

actually, maybe I’m wrong on that! (reading the docstring)

Alex Miller (Clojure team)14:04:48

weird, didn’t remember that

nipperstick14:04:39

anyone have an example project that uses boot and npm dependencies (node_modules)?

dergutemoritz15:04:35

Heya, I just upgraded ClojureScript in a project from 1.9.293 to 1.9.521. For deployment, it builds an uberjar and puts the compiled cljs into it which is then served by a Clojure web server which is also bundled up in the uberjar. Thus, ClojureScript should not be required at runtime, and up until (at least) version 1.9.293 that was indeed possible by marking the ClojureScript dependency as provided. Now with 1.9.521 I get java.lang.ClassNotFoundException: com.google.javascript.jscomp.CompilerOptions when running the main class. Not marking it as provided makes it work but blows up the uberjar's size by 10 MB. Before I file a bug report: is it reasonable to expect this to work in the first place?

dergutemoritz15:04:05

Oh, the clojurescript compiler is of course not referenced anywhere in the Clojure part of the code.

thheller15:04:38

hmm sounds like you require something somewhere?

dergutemoritz15:04:05

@thheller Yeah, but I don't 😄

dergutemoritz15:04:30

Trying again with 1.9.293 now just in case

dergutemoritz15:04:18

I'll try to come up with a minimal repro case unless you talk me out of it 🙂

thheller15:04:38

well the compiled CLJS code definitely doesn't cause anything like that

dergutemoritz15:04:00

Yeah, it can only be the Clojure part

dergutemoritz15:04:19

Maybe some other library is referencing the cljs compiler somehow

thheller15:04:27

maybe something you require in turn then requires cljs?

dergutemoritz15:04:15

OK just verified: it works with the exact same code when depending on clojurescript 1.9.293 as provided

thheller15:04:18

CompilerOptions isn't new .. it has been there for ages

dergutemoritz15:04:53

Sure, that's a red herring - it's not included in the uberjar after all

thheller15:04:54

and the produced jar definitely does not contain any cljs/* files? check wit jar -tvf uber.jar

thheller15:04:28

or com.google.javascript.jscomp.CompilerOptions 😉

dergutemoritz15:04:35

Well there's cljs/core/match/macros.clj for example but that's been there before, too

dergutemoritz15:04:52

And of course it's not required anywhere in the Clojure code

thheller15:04:07

no cljs/core.cljc or the like?

dergutemoritz15:04:01

Well, I'll just ship 10 more megs for now and will try to come up with an isolated reproduction case when I'm done with that

thheller15:04:19

maybe try putting the cljs dependency into the :dev profile

thheller15:04:45

not sure about the :provided part, I have everything in :dev and that doesn't end up in the uberjar

dergutemoritz15:04:15

Indeed, that's worth a try

dergutemoritz15:04:47

Looks like it's not picked up by lein-cljsbuild there

dergutemoritz15:04:17

Using the leiningen.cljsbuild Leiningen hook

dergutemoritz15:04:51

Right, makes sense - the :dev profile is not active when lein uberjar runs after all

dergutemoritz15:04:10

@thheller How are you building your cljs for the uberjar then?

thheller15:04:54

haven't used lein-cljsbuild in 3+ years so can't really say if thats possible there

thheller15:04:44

surprised it doesn't support the :dev profile though

dergutemoritz15:04:54

It does, just not with the uberjar build hook

dergutemoritz15:04:25

@thheller Do you have a guide on how to set up shadow-devtools for uberjar deployment as I described above?

dergutemoritz15:04:54

Never mind, I think I found it

thheller16:04:15

usually I don't put generated CLJS files into the uberjar but serve them from the fs

richiardiandrea16:04:16

Can't you force inclusion with with-profile? I always use :test for my ClojureScript dependency, I don't actually even know why (probably it has to do with Maven's trnasitive dep rules)

thheller16:04:34

but you can do aliases easily

thheller16:04:36

:aliases
  {"foo"
   ["do"
    ["run" "-m" "shadow.cljs.devtools.cli/release" "website"]
    "uberjar"]}

thheller16:04:05

generate into a dedicated directory that the :uberjar profile has as a :resource-path

dergutemoritz16:04:30

@thheller Yup, that's what I came up with

dergutemoritz16:04:57

Thanks for the hint! Maybe I'll switch to shadow-devtools indeed 🙂

thheller16:04:50

happy to help if you have questions 🙂

qqq17:04:07

while running inside a webpage, is there a reliable way to capture F1, F2, F3, ..., or should I assume the browser / OS owns all those keys ?

qqq17:04:12

(this is for key event handlers)

john19:04:41

Is it possible to override the (.invoke ... method on functions, such that if any arguments to the function return (-realized?... = false then said invocation will be queued up for later? Similar to promises, but transparently enabled on the IFn interface?

tbaldridge19:04:04

not really, since IFn is an interface that expects a response. Making a function async changes the return type. So if you have a IFn<Object, Object> now you would have a IFn<Object, Promise<Object>>

john19:04:47

Right, but then if you modify IFn to also handle Promise<Object>, further queuing up invocations?

dnolen19:04:17

@john there’s no obvious way to do that I’m aware of

john19:04:28

I guess I don't know what you mean by "expects a response." Is it impossible to alter IFn's invocation behavior based on the arg type? I was thinking, if any of the args are like MyPromise...

john19:04:00

I looked a bit into seeing if it was possible to integrate JS yield and generators with CLJS -realized? but I couldn't grok it all. It seems like CLJS sequence abstraction is already pretty close to an Iterable, so creating yieldable sequences might be possible.

dnolen19:04:52

yield is a syntactical construct so I don’t know what you mean

dnolen19:04:04

function* constructs generators which support a specific interface

dnolen19:04:24

there’s a ClojureScript helper for dealing with ES6 Iterable

john19:04:58

On a similar note, for a system I'm working on, I might want a promise like interface. But rather than forcing the user into the whole JS promise system, I was think about simply implementing a (-then.. method on my object, which simply queues the function call on a queue inside the object, if the object is still pending.

john19:04:39

@dnolen I saw that helper. Interesting

dnolen19:04:49

ok but ClojureScript users already have core.async if/when they need it - which is probably at this point more idiomatic

dnolen19:04:07

why bother with anything over Promises at all - unless this is just for interop in your own project or something?

john19:04:40

I thought about core.async. It'd provide a number of solutions to my architectural problems. But as of right now, the whole system has zero dependencies. And it creates a fairly small minified artifact, which is nice.

john19:04:04

I'm also not sure about forcing downstream users to use core.async

john19:04:40

Not sure if I want all of my objects returning chans. Using chans internally, I wouldn't mind so much.

john19:04:36

When all that is really needed, for this particular use case, potentially, is a then, which is trivial to implement on an object with an invocation queue

dnolen19:04:52

another alternative is that you write your main interface using callbacks and then your users can layer whatever they want over it

dnolen19:04:09

other thing, taking a dep on core.async doesn’t really matter

dnolen19:04:21

if you put those core.async decorated fns in another namespace

dnolen19:04:26

dead code elimination is a thing

john19:04:05

right, I heard sparsely used core.async produces a pretty small dep size

dnolen19:04:35

but if a user never uses a namespace that uses core.async - there won’t be any stuff at all in the final artifact

dnolen19:04:18

not saying that should change your decision

john19:04:21

So, you're saying, provide an additional core.async interface to the objects in another ns and if that functionality isn't used, it won't be added to the deps. That makes sense

dnolen19:04:21

just something to consider

john19:04:51

No, that changes the equation for me. If I can provide the user more options without forcing those options, I'll provide them.

john19:04:17

I'll provide a Promise interface too, if it can all be DCEd

dnolen19:04:52

Google Closure Library has a Promises thing I thought - not sure how “standard” it is though

john19:04:48

But I'll probably focus on a plain, generic interface for the first iteration. probably with vanilla callbacks and -then as an optional deftype method or something.

john19:04:57

rgr, I'll check it out

john20:04:12

another high level design question: I haven't done much with deftypes and protocols yet. I tend to just use maps and vectors to model my data. In this current project, I'm storing most of the objects created in a map. Those objects have a deftype facade, but their methods generally don't operate on the deftypes initialized values passed in. My plan was to prototype everything out in regular data structures and once the semantics were somewhat figured out, bake those semantics directly into the deftype - move the state out of the object maps and into the deftyped objects and work on them there. But these objects aren't really cpu bound - most of their methods are asynchronous. They need coordination by data structures outside of themselves anyway, so why bother storing the object's values in the objects themselves? Is there any downside to using a deftype as just a facade over a system?

tbaldridge21:04:20

@john I'd start with looking at using defrecord if you are concerned about hashmap performance. They look like maps, and act like maps, but any fields you declare up-front are stored in object fields and have the fast lookup you would expect from objects

john21:04:51

I'll check it out. Do you know what I mean by facade though? As if all the getters and setters on the object just call out to values stored in a global map, which the system operates on. Rather than trying to operate over a collection of objects using their methods.

john21:04:36

The downstream user doesn't need to use or know about the global map that backs all the data structures their using. But the library author can more easily operate on the global map of values and properties, rather than over a collection of opaque objects with method calls

john21:04:28

I'm just wondering if that's a frowned upon design pattern. Or if it's used often with asynchronous method call situations

mobileink21:04:40

facade = protocol?

john21:04:30

like

(defn facade-value [k]
  (reify
    IDeref
    (-deref [_]
      (get-in @db [k :value]))))

john21:04:51

Then @k and you get the value

mobileink21:04:01

i personally would not frown on that, fwiw which ain't much, 2 cents.

john21:04:06

(deref k)

mobileink21:04:58

does that code turn k into sth dereffable? it creates an object implementing IDeref, no?

john21:04:34

Yes, but the deref returns the value in an external map

mobileink21:04:11

(let [k (facade-value other-k)] @k)?

john21:04:51

yeah, where other-k is some key

john21:04:28

It most probably wouldn't be as efficient as lookup in an object, but if many of the operations you have on that object are asynchronous, you don't really care about cpu bound efficiency for lookup. The deref is probably happening after some delayed callback of some sort anyway.

john21:04:50

Not 300 times a second

tbaldridge21:04:08

But, recognize that you are mutating global state. So in that aspect I tend to avoid patterns like this.

john21:04:35

to an extent

tbaldridge21:04:37

You can do this functionally via something like cursors though

john21:04:55

I see what you're saying

tbaldridge21:04:04

zippers work somewhat in the same way, your "thing" contains both state and a path into the state.

john21:04:21

I'm not intending on giving the user direct access to the global background state

john21:04:41

so, in effect, their own access to the object would act as a cursor over that global state

john21:04:48

I just have to get the coordination right

john21:04:12

which wouldn't be any easier, as the author, if I'm just working with lots of little pieces of mutable state

john21:04:29

rather than just maps and vectors

john21:04:52

because aren't the objects tossed around within a deftype just as mutable as some external maps stored in a global map?

mobileink21:04:20

do you really need deref? why not define your own protocol and wrap deref in a fn?

john21:04:40

@mobileink what do you mean?

mobileink21:04:01

working with mutable isn't much different than working with an external db is it? fwiw i wrap access to google datastore with deftype and protocols so it behaves just like a map.

john22:04:31

Well, arguably, the values within a deftype are more mutable than those stored in a vanilla map, in an atom, right?

mobileink22:04:43

your facade-value just wraps get-in already, in IDeref, no? why that instead of sth else?

mobileink22:04:08

you can reify your own protocol.

john22:04:38

Yeah, that's what I didn't understand. What do you mean wrap deref in a fn?

john22:04:46

sth else?

mobileink22:04:42

sorry, my bad. i meant wrap your access operation in sth other than deref.

john22:04:04

oh s/sth/something

john22:04:40

mostly because deref provides a uniform interface across many objects that allows objects to implement any necessary atomic operations in the background, prior to the return. Like a safe getter contract. So it's idiomatic.

mobileink22:04:43

oops, dictionary dork here, sth = something, so = someone, etc.

john22:04:50

and it gives you the sugary @

mobileink22:04:44

how is that different than a fn?

john22:04:30

That's a bit handwavy in cljs, since all data access is also protected by the non-reentrancy of the js thread... but once we start talking about cljs values within a distributed, asynchronous context, that safe getter/setter contract that clojure provides becomes important again.

mobileink22:04:57

ah, syntax. i tend to avoid @ for no particular reason. well, because it mucks up the functional model, i guess.

tbaldridge22:04:10

yeah, having @ littered everywhere is a code smell

john22:04:58

the deref thing doesn't really matter. The point is that many of my deftype methods don't operate over internal values, but rather external values, coordinated by traditional Clojure coordination mechanisms.

tbaldridge22:04:23

they're mucking with mutable data though

mobileink22:04:46

my druthers: implement IFn so user can write (k) instead of @k. it's all about the functions! 😉

john22:04:35

Isn't a deftype mucking with mutable data internally?

tbaldridge22:04:57

deftypes are immutable by default

john22:04:12

But not for the methods on the deftype, right?

mobileink22:04:36

sure, so is everything else in Clojure. Just hide it.

tbaldridge22:04:06

no, deftype is 100% immutable by default

john22:04:21

Well, then I'm confused.

mobileink22:04:29

i was taking "internally" literally. of course it mutates memory, it just hides it

tbaldridge22:04:40

let's not go there

john22:04:01

Can't a deftype implement a method that updates its state?

john22:04:25

how does it do so without mutating the local state?

tbaldridge22:04:49

you can, but that's not default behavior

tbaldridge22:04:58

and in CLJ it's completely dis-allowed without special flags

john22:04:41

But if I want to make a custom data structure in cljs, that's the behavior I need to implement, correct?

tbaldridge22:04:54

(deftype Cons [head tail])

tbaldridge22:04:07

custom data-structure and it's 100% immutable

mobileink22:04:30

but your use case requires mutability?

tbaldridge22:04:55

I don't think it does.

john22:04:58

But there's nothing in deftype that prevents someone from going (deftype MutableCons [head tail] Somthing (-mutate [_ state] (bang on state...

mobileink22:04:27

well that's true, you can always make your "mutation" op return a new object, is that what you mean?

tbaldridge22:04:33

Sure, but don't do that...as it goes against most of the design goals of Clojure

tbaldridge22:04:05

@mobileink exactly, you can have state + a path. Modifying state returns a new state + path.

tbaldridge22:04:15

moving to a new place returns state + a new path

john22:04:18

but if my object has a value, a list of watchers, a list of validators, a list of queued actions, a list of queued callbacks, etc, etc... My object is going to have to mutate something somewhere, right?

john22:04:33

I want to add-watches, add validators, add call backs, etc

john22:04:21

clojure doesn't return a new object every time you add a watcher to it, right?

mobileink22:04:23

i've rassled with this for my gae datastore wrapper. what do database wrappers usually do? returning a new ds after a put seems kinda smelly.

tbaldridge22:04:37

Datomic does that 🙂

mobileink22:04:09

NO FAIR! 😉

noisesmith22:04:29

the concept of a watch assumes mutability I think

john22:04:38

So, I can either mutate the list of watchers, validators, callbacks, values etc within the object, or I can manage all that state in a coordinated system, outside the object.

noisesmith22:04:10

why not use an atom with your object inside it?

noisesmith22:04:20

it already has implementation for watchers etc.

tbaldridge22:04:16

or don't use clojure's watch system, use your own immutable watch system

mobileink22:04:34

(adapting the datomic api to other datastores is an interesting thingie.)

john22:04:41

@noisesmith Yeah, I've messed with that option as well.

john22:04:52

@tbaldridge I'd be interested in hearing your take on what an immutable watch system would consist of

john22:04:48

@noisesmith essentially, extending atoms with my necessary methods.

tbaldridge22:04:02

it's a system where (add-watch obj k f) returns a new obj

mobileink22:04:30

boot watch?

john22:04:56

I just find the objects deftypes create somewhat opaque - more difficult for me to inspect and understand. Though I may just be to dim about deftypes atm

john22:04:52

They're more difficult to inspect for obvious performance reasons. But while I'm building the custom data type, I'd like all that data on the outside of the object first, where I can think about it like regular clojure data

tbaldridge22:04:03

agreed, so that's what's interesting, you could implement all this without using deftype

tbaldridge22:04:15

it's all just data, with functions that modify the data, returning new data

john22:04:24

which is exactly what I've done

john22:04:55

I'm only using the deftype as a facade so it looks like a traditional clojure data structure to the user.

john22:04:43

And I'm thinking, later optimization efforts, can focus on wrapping some of the functionality into the type object itself, when necessary.

tbaldridge22:04:18

But it doesn't sound like this is a Clojure datastructure, and so forcing it to match existing interfaces may cause more problems than it would solve

john22:04:42

that may be the case. I need to get the code out so you all can just look at it

tbaldridge22:04:46

what you're describing here is a combination of Clojure reference types and data

tbaldridge22:04:54

watches go on reference types, not data

john22:04:14

yeah, Agents, primarily

john22:04:27

but I'm exploring the full gamut of derefables

john22:04:45

because some of them may have cljs counterparts on workers

john22:04:02

none of the blocking behavior, obviously

noisesmith22:04:09

right - but the suggestion implied there (worth noting) is the separation of data from mutation - using a mutable container not a mutable data

john22:04:09

Anyway, I should work on a few refactors so I can get this code out so y'all can critque it directly, rather than just talk about the design.

john22:04:30

@noisesmith I believe I'm achieving a better separation by placing the data in traditional clojure data structures and leveraging traditional clojure update semantics. All data type data is stored within persistent data structures and accessed behind derefs and updated via clojure's persistent ds update semantics. Otherwise, I'd be banging on the value directly within the deftype.

john22:04:28

so for constructing a reference type, at least so far, it feels like doing it this way is more clojurey

ingared22:04:15

Can some body suggest me coding exercises to get to speed with Clojure and Clojure Script ??

noisesmith22:04:31

http://4clojure.com - though the exercises are out of order

qqq22:04:08

reading todomvc code is also useful if you want to pick up reagent

qqq22:04:51

someone should create an emailmvc -- showcase your newest ui library / framework by writing an email client in it

mobileink23:04:08

@ingared: i recommend you pick one to start. get clojure down before you move on to cljs.

john23:04:29

I remember it being discussed here previously but I don't remember if there was any resolution to the question. Is there a way to determine at runtime whether a project was compiled with :advanced mode or :none?

tbaldridge23:04:05

open the code, if you see only single variable name inside functions, and it's all smashed together and makes no sense at all, it's :advanced

john23:04:06

(defn smell-it [...

john23:04:09

They should make a linter that checks for code smells 🙂