clojurescript 2015-11-29

@jaredly: I'd suggest you start with this brilliant bit of work: http://shaunlebron.github.io/t3tr0s-slides/#0 (a step by step guide to building Tetris in cljs). Code: https://github.com/shaunlebron/t3tr0s-slides

šŸ‘ 2

Yes, @eyelidlessness, I’ve added (def f (fn x [] #'f)) to CLJS-1495

I'm puzzled by exists?. At the REPL this works:

cljs.user=> (exists? js/window)
true
But this is odd:
cljs.user=> exists?
WARNING: Use of undeclared Var cljs.core/exists? at line 1 <cljs repl>
nil
It is used in https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs but never defined.

Where does it come from?

why might one of my Om components not get IDidUpdate called ?

(the others do, but one of them doesn't)

@octo221: did you put logging inside render function? is it really being re-rendered by Om?

yes, IRender is being called

(render [this] I mean)

isn’t its parent being re-rerendered as well and discarding it as a child somehow? or isn’t it rendering nil or empty value? just wild guesses

have to go, lunch time

ok cheers for the ideas

hey child components in general don't seem to get did-update called

@borkdude: I believe it is using khroma library: https://github.com/suprematic/khroma, both lib and extension written by @ricardo

@borkdude: are you planning on building some chrome extension?

@darwin: never thought about it, but such a library could become a gateway drug šŸ˜‰

@borkdude: well, I was asking because, just recently I have been working on a similar library simple_smile mine also covers APIs for chrome apps now: https://github.com/binaryage/chromex/

still an early version, want to see some real usage (except for my own extensions) to iron out remaining problems simple_smile

@borkdude: @darwin is correct, it uses Khroma. His ChromeX is a pretty neat approach, too.

If nothing else, easier to maintain than having a random human make assorted, not-necessarily-consistent decisions about how to expose a particular API when he needs it. šŸ˜›

@darwin: I see you removed your ā€œdon’t use this because it’ll kick your petsā€ warning. Do you expect the API is more stable? Are you planning to add some extension-specific tests?

big credit goes to Google developers who were so disciplined to provide automated way how index their APIs, according to my stats there is 1000+ functions in their public apis right now, zero chance anyone could cover them manually

@ricardo: I just started building my own real extension on top of it, I don’t know about any limitations right now

I mean more along the lines if you expect the way you’re exposing stuff to change.

I don’t plan extension-specific tests, that’s Google’s job simple_smile I mock simple extension apis in my tests and test just my wrappers, also I want to automate it and extension code is much harder to test automatically

I wonder what are your plans with khroma-tests

I know. simple_smile That’s why I wrote khroma-tests to be half-test and half-use examples.

kudos for using devcards simple_smile

I merged it into the main khroma repo. This has got me thinking I should just release it to 0.3.0 as is, so that people don’t have to look at two repositories. Going to do that now

I will have one example project which I will maintain, there will be a ā€œtestā€ button to run quick battery of simple tests, but I will just use it for ad-hoc testing

btw. here is my quick chrome API mock, seems to be ok, for simple tests for my wrappers: https://github.com/binaryage/chromex/blob/master/test/chromex/test/playground.cljs#L15-L62

@ricardo: as API stability, I don’t know, conceptually the api won’t change I think, but I cannot guarantee it at this point

To me it’s less about making sure that extensions still work and more about making sure the way I expose them is consistent with what people are expecting from before.

Even if it’s automated, once can still break that.

I think there will be more discoveries about marshalling specific types

sure, if you have library users, that is a valid concern

There. Merged 0.3.0 to master.

that is why I’m trying to spread a word early and get some people on board with their extensions-in-development, so we can discover issues early and stabilise the interface

@borkdude: If you’re looking into getting acquainted with a Clojureic way to access the API, check out the khroma tests.

@darwin: Well, if you’re looking into it, I can’t recommend devcards highly enough.

thanks, I wrote down these libraries to take a look at it later

This returns true with advanced compilation and false without (or with :pseudo-names):

(seq? (google.maps.LatLngBounds. (google.maps.LatLng. 1 2) (google.maps.LatLng. 3 4)))

Any ideas why it would return true? Some kind of name collision?

@henriklundahl: did you test the name collision theory by using a closure around your code?

:output-wrapper true I think is the compiler option

@octo221: there’s an #om specific channel btw

@dnolen: I get the same result with :output-wrapper true...

it’s possible it’s an advanced optimization bug, I’ve certainly seen those now and then

unless you want to dig in I would just tweak your logic a little bit

The thing is I'm trying to use js->clj on the results from the Google Maps geocoder, where LatLngBounds are among the values.

...and seq? is used in js->clj.

@henriklundahl: yeah so I suspect that under advanced the protocol gets renamed to a property that the google map object has

no good answer is coming to mind other than write your own js->clj that doesn’t have the seq? or coll? cases

I don’t really think it should have them, but I think these were added as convenience back in the old days

when people were directly dealing with DOM and child nodes

should maybe revisit that but would need to determine how much breakage it would cause

@dnolen: But couldn't something be done about the name collisions (if that is what is happening)? Feels like anything can happen if functions or properties are overwritten?

(a reproducible advanced mode problem with clojurescript code itself)

if you have an instance of the same issue, then Google Closure Compiler does not connect access to .-lat nad .-lng properties (for reading) with access to them (for writing), and removes them in some cases (for example in LatLng. constructor), that leads to .equals return true when comparing both constructed objects, because it compares undefined values, … just a theory

@henriklundahl: try to build a minimal repro case and we can try to reason about what happened there^

@henriklundahl: you can’t do anything about these kinds of name collisions in JavaScript period

library A gives semantic to object X with method get

@darwin: I think there aren't any usable properties in LatLngBounds or LatLng so I wouldn't expect js->clj to do anything with them, which is what happens without advanced compilation.

library B gives different semantic, BOOM

where is the LatLng stuff coming from?

this happens all the time with stuff like call

@dnolen: Sure, but there are some steps before we end up with the same names...

and the correct externs are used for that?

kk just checking simple_smile

@henriklundahl: this just isn’t how Google Closure works

you are using a foreign library that Google Closure doesn’t know about, there’s no way to know that names won’t clash

@dnolen if the externs are used it will now it

only if the externs are complete

including enumerating private members

ah they only have the getters/setters

@henriklundahl: if you don’t want to monkey-patch js->clj then providing this information is another route

@dnolen: You mean what's missing in the externs?

But couldn't the names of those properties change at any time?

yes, this is why I suggested monkey-patching js->clj

this can’t possibly cause you any problems

But can you help me understand, what's (probably) happening?

or honestly writing your own conversion library that doesn’t have this problem

How can those private properties munge anything?

I already explained what happened, but I will say it again

A) ClojureScript uses properties to know what types belong to which protocols (since there are no interfaces in JavaScript)

B) this get renamed by advanced compilation

C) You are using a 3rd party library with properties the Closure Compiler does not know about and not providing externs to cover you

interesting problem though that the renamed property contain exactly the value required to make it look like a cljs seq

right so we can’t fix the general problem

but in this case we could use a different sentinel value

currently it’s just true

but would need to measure perf implications of doing so

isn't there a bitmask check involved somewhere?

only for fast path protocols

and that's probably not safe anyhow because of JS coercion

@elahti has joined the channel

thinking about it some more Google Maps is probably the worst case scenario - since I suspect they don’t allow you to build from source and the thing you get is already advanced compiled

so externs might not help you anyway

if I'm reading this right

it only checks if the property is true-ish

maybe that should just check true?

we could do that, would narrow the likelihood

@dnolen: Ok, I understand, thanks. It does feel quite brittle as it is now...

You're right about Google Maps.

@henriklundahl: this is the first time anyone has ever reported this issue in 4 years

we’ve had more bug reports about real bugs in the Google Closure compiler than challenging name clash edge cases like this

@henriklundahl: if you just want to pass data to the google maps api and don't need to work on it in cljs you can use the #js {} reader literal stuff to directly construct js objects instead of closure maps

so you don't need clj->js

@thheller: Yeah, I know and I do when it's possible. This time it's the other way around (js->clj), though.

@dnolen: So I guess there aren't many other situations that CLJS handles in a similar way?

@henriklundahl: this really just doesn’t come up that often

3rd library libraries use Yahoo compressor or Uglify for minification

this particularly bad interaction is because you have 2 Closure advanced builds compiled separately

Yeah, I know, but are there other places in the CLJS codebase that relies on object properties in a similar fashion?

yes all of ClojureScript

the whole language is rooted on protocols

Would it be possible to take the whole Google Maps API and put that as an extern?

@henriklundahl: you could try that but that doesn’t sound like a good idea to me

js->clj is so trivial for the longest time I refrained from including it

cases like this reaffirm that it was probably never a good idea

Ok, sure, but I'm just worried that other things suddenly start breaking...

I don’t see why

js->clj is a just convenience thing

you have so many better helpers for dealing with foreign data in ClojureScript and Closure I really don’t know why people bother

Ok, I guess there aren't many places in my code where I'm dealing with Google Maps objects and when I do I don't use any CLJS functions, except in this case.

So I guess I shouldn't worry.

@mfikes: thanks for your follow ups wrt re-defining a function! The solution with the ns-qualified var works great! And good work on the issue report simple_smile

@grav: simple_smile Looks like we are coming up on a year of having var. Interestingly, perhaps the first commit refers to shadowing https://github.com/clojure/clojurescript/commit/91153fa7d26f55cc466ac1d24184ba78bac7cf72

I'm trying to pull an item from a set. The item in the set has metadata, but when I use get, it seems like get returns the lookup value I used, and not the item actually in the set...anyone have ideas?

@tony.kay: seems like you found a ClojureScript bug

that works in Clojure, file an issue in JIRA

ok. will do

@tony.kay: something else to check

{(with-meta [1 2] {:foo true}) 3} in Clojure vs. ClojureScript

when using find

(meta (get #{[1] [2] (with-meta [3] {:k 1})} [3])) returns nil for me

important to check Clojure behavior here

(yeah seems to work fine in Clojure)

so likely the underlying stuff in hash maps is what is wrong

since sets just re-use

Yeah, it works for a vector: (meta (get [[1] [2] (with-meta [3] {:k 1})] 2))

Maps themselves are fine: (meta (get {[1] [1] [2] [2] [3] (with-meta [3] {:k 1})} [3]))

@alau has joined the channel

@mmln has joined the channel

I’m trying to use goog.async.Debouncer http://google.github.io/closure-library/api/source/closure/goog/async/debouncer.js.src.html But when I do (:import goog.async.Debouncer) , I get a no such namespace exception.

@roberto that file is pretty new, good chance it isn't in the closure release that is used by clojurescript

ah, ok. Thank you.

@euwyn has joined the channel

does clojurescript have an index-of function where I can get the position of an item in a list? In clojure proper, we call out to java, but best I can do it seems is convert the list to a js array first then use .indexOf on it.

you could combine filter and map-indexed

I ended up writing my own index-of just now that takes a collection and a predicate function to filter with.

not perfect but works. Seems like something missing from the language, IMO.