Clojurians
#cljs-dev
<
2017-02-28
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

shaun-mahood00:02:08

Jira etiquette/testing question - I've tested CLJS-1868 compilation on both Windows and Mac, for both :none and :advanced, and I've confirmed that it compiles and the new paths look good. The closure libraries are included and under :none they show up in the out folder as expected, but I haven't actually programmed anything that uses them, only tweaked the quick start files. Is this enough to say that it works for me on Jira, or should I try writing some code that actually uses the included cloure libs first?

thheller00:02:51

so I just tried upgrading my work project to latest CLJS 494 and it didn't work, then tried 473 and 456 also no luck.

thheller00:02:03

at first I though I ran into the async issue but that isn't it I guess

thheller00:02:55

also the usual :pseudo-names makes the bug disappear, talking about :advanced here.

thheller00:02:31

someone else on #clojurescript mentioned something like this today as well

thheller00:02:28

the last time I had an issue like this was about with protocol detection, but we fixed that

anmonteiro00:02:13

@thheller did you upgrade from 1.9.229?

thheller00:02:42

293 was the last version I used

anmonteiro00:02:51

it’s a big bump from 293 to 456, you think you can bisect?

anmonteiro00:02:08

by big bump I mean there were a lot of commits

thheller00:02:19

its too late for me to dig into this now, will try some stuff tomorrow .. just completely surprised the usual :pseudo-names debug option doesn't work as it disappears

anmonteiro00:02:22

sounds good, keep me posted

thheller00:02:33

it looks like something was optimized away, but there should be more people reporting this if that were the case

thheller00:02:19

hmm so had an idea

thheller00:02:31

the check that failed is {:pre [(ifn? x)]} ... removed that :pre and just test (when-not (ifn? x) (js/console.log "x is not ifn" x))

thheller00:02:28

the console message display the object as x is not ifn function (a) { ... with the full code of the function

thheller00:02:28

so (goog/isFunction x) returns false ... I have no idea what is going on. going to sleep.

anmonteiro05:02:07

It addresses the first part of the solution proposed in this design doc: https://github.com/clojure/clojurescript/wiki/Enhanced-Node.js-Modules-Support

anmonteiro05:02:17

the patch makes is possible to supply a :npm-deps entry in the compiler options, such as:

{:npm-deps {:react "15.4.2"}}
and then require react directly from a CLJS namespace. e.g.:
(ns foo.core
  (:require [react :as React]))

(def foo (React/createElement "div" nil "Hello, World!"))

anmonteiro05:02:55

the compiler will install the supplied node modules automatically

anmonteiro05:02:09

I appreciate people trying out the patch and reporting back!

richiardiandrea05:02:19

This plus boot-pack-source solves my packaging requirements thanks :grinning:

anmonteiro05:02:04

There might be one hiccup along the way with some modules: you might encounter this Google Closure Compiler issue: https://github.com/google/closure-compiler/issues/2308

anmonteiro05:02:40

^ the fix for that hasn't been included in the February release and some modules may crash the compiler

anmonteiro05:02:00

if you know how to build the Closure Compiler, use a master checkout

thheller09:02:58

@anmonteiro did a git bisect to find the bad commit

thheller09:02:01

git bisect bad
de05b15568c848a1d4f80a44bdffd486abd05150 is the first bad commit
commit de05b15568c848a1d4f80a44bdffd486abd05150
Author: António Nuno Monteiro <[email protected]>
Date:   Mon Nov 7 12:07:32 2016 +0100

    CLJS-1768: cljs.spec perf tweaks

    This patch implements the changes in the following commits:

    
    
    
    

:040000 040000 f8eee4c6e8289c5ec539c478e67c48d0de485f84 f261f856c8492bd4880be536186ccc8ad3fe3557 M	src

thheller09:02:30

no idea why that would cause my app to fail as it fails at a point where spec isn't involved at all

thheller09:02:00

will try to reproduce outside my app now

thheller09:02:43

verified just for sanity git reset --hard de05b15568c848a1d4f80a44bdffd486abd05150 breaks while git reset --hard de05b15568c848a1d4f80a44bdffd486abd05150~1 works

thheller09:02:23

must be emitting something that confuses the closure compiler

bronsa10:02:34

anmonteiro: or start munging local names?

thheller11:02:57

@anmonteiro sorry for wasting your time, your commit wasn't causing this at all. I messed up my externs and somehow that made it look like that commit was causing it.

thheller11:02:35

Had some Google Analytics externs that went missing, somehow the ga variable must not have been touched before that commit

thheller11:02:22

should have been my first clue to look for externs when :pseudo-names worked, guess I shouldn't try to debug those things at 2am

thheller11:02:17

for giggles the the function that was replaced by ga was goog.isFunction which caused by {:pre [(ifn? x)]} to fail :stuck_out_tongue:

roman01la12:02:25

That’s probably not related directly to ClojureScript, but is there a way to make JS stack traces show source mapped ClojureScript code in stack frames?

roman01la12:02:43

I thought browsers can do it already. But if not, this probably could be achieved via stacks rewriting, the way it’s done in React.

darwin13:02:20

@roman01la I believe DevTools developers try to do their best to do this whenever possible

darwin13:02:03

obviously, if you handle error objects yourself and printing them somehow directly this transformation is not present

roman01la13:02:16

@darwin Yes, but I’m interested if there any evidence that source mapped stack frames are supported or not.

darwin13:02:10

AFAIK it is definitely NOT supported from the ECMAScript, so DevTools tries to be smart and transform presentation if they detect you happen to be printing a stack-trace

darwin13:02:19

if you interact with js/Error object in your code for example and processing .-stack by hand it won’t be source mapped, but if you console.log it, DevTools will detect it is a strack trace and try to present it source-mapped

darwin13:02:55

not sure about this particular case, but it definitely works when logging js/Error or exceptions for example

darwin13:02:28

another place is when DevTools present some error or exception on their own (without you explicitly logging it), similar heuristics apply

thheller13:02:23

@roman01la source mapping is exclusively coming from the devtools, the runtime itself doesn't do any mapping at all

roman01la13:02:53

@thheller I believe it’s possible to change function names in stack frames via fn.displayName prop

roman01la13:02:01

that’s how it is done in React I guess

thheller13:02:35

do you have an example of what you mean?

thheller13:02:43

displayName usually was just a way to name a function for devtools

thheller13:02:14

IIRC FireBug was the first to use that

thheller13:02:14

but again .. devtools only

roman01la14:02:04

@thheller yeah, exactly, instead of this clojure$string$includes_QMARK_ it would be nice to see this clojure.string/includes?

roman01la14:02:24

looks like displayName is the way to go

thheller14:02:35

hehe I wanted something like this a very long time ago

thheller14:02:18

(pr-str name)
=> #<function cljs.core/name line:5876>

roman01la14:02:24

I know this is kind of unnecessary when you used to read stack traces, but would be a nice to have for novice devs

thheller14:02:13

I wanted that because accidentally printing functions was annoying as hell

darwin14:02:31

btw. Dirac DevTools tries to do demunging

thheller14:02:43

but it really isn't feasible

roman01la14:02:18

@thheller why?

roman01la14:02:37

@darwin what about cljs-devtools?

darwin14:02:38

well, cljs devtools tries to present user-friendly names when formatting, if I remember correctly

thheller14:02:42

the analyzer doesn't know about every fn that is created

thheller14:02:00

so you still end up with a bunch of anonymous functions

darwin14:02:05

but logging is not the only place where names are presented

darwin14:02:31

that is why in Dirac I try to beautify function names in the DevTools UI everywhere

thheller14:02:38

also the closure compiler didnt like this

thheller14:02:20

since there were a bunch more names it hard to process but I really don't remember the details

thheller14:02:25

way too long ago now

thheller14:02:11

also source maps are a way better solution :wink:

thheller14:02:46

@roman01la there is some work done to manually re-map stacktraces here https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/stacktrace.cljc

thheller14:02:32

not sure how well this works

dnolen14:02:56

@anmonteiro whoa nice!

anmonteiro16:02:08

@thheller no problem, glad you figured it out. Kinda interesting how goog/isFunction ended up being replaced by ga too :upside_down_face:

thheller16:02:03

the fact that everything worked with 1.9.293 is so strange, the externs where missing there as well. guess it replaced a function I didn't reach but then at some point that was shifted.

thheller16:02:11

weirdest few hours of debugging ever :slightly_smiling_face:

samueldev19:02:13

so im encountering some funny behaviour w/ cljs spec

samueldev19:02:25

annnd my code snippet upload is failing :disappointed: stupid s3

samueldev19:02:36

(ns foo
  (:reqire [my-project.domain.specs :as specs]
               [cljs.spec :as s]))

;; for reference: the predicate on :specs/thing is just `string?`

(js/console.info "Incorrectly used other-ns-spec evaulates to:" :specs/thing) // => :specs/thing

;; ^ it correctly fails to identify that as the `thing` spec from the `specs` namespace and assumes the literal keyword ":specs/thing"

;; but..

(s/valid? :specs/thing "") // => true
(s/valid? :specs/thing {}) // => false

;; ^ it correctly identifies & validates when doing an s/valid

samueldev19:02:21

is there some magic going on under the hood to correct that mistake when doing validations?

samueldev19:02:56

this isnt causing any problems, its just a common mistake my team members themselves making when still learning :: vs : that im curious to know if is working as intended

anmonteiro19:02:16

@samueldev you should be using ::specs/thing for the keyword to be expanded as :my-project.domain.specs/thing

samueldev19:02:38

@anmonteiro yup I understand that now - but am curious as to why the validation passes (it seems to correct the mistake for you, and understand what you were trying)

favila19:02:49

@samueldev Are you sure that s/def is ::thing and not :spec/thing?

favila19:02:58

can you paste the def?

samueldev19:02:33

@favila >< that was the mistake

samueldev19:02:40

sorry to bother! working as intended and no confusion now. sorry again.

samueldev19:02:31

ok @favila @anmonteiro i dont think im crazy

samueldev19:02:33

look at this better example

samueldev19:02:52

(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:blah/asdf :blah/fdsa]
          :opt-un []))

(js/console.log "1:::::::")
(def val1 "")
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val1)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val1)))


(js/console.log "2:::::::")
(def val2 {:asdf "" :fdsa {}})
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val2)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val2)))


(js/console.log "3:::::::")
(def val3 {})
(js/console.info (if (s/valid? ::this-is-a-test-map-spec val3)
                   true
                   (s/explain-data ::this-is-a-test-map-spec val3)))

anmonteiro20:02:22

what about it?

samueldev20:02:28

sorry had to edit

samueldev20:02:24

in ^ that example code, the output is thus: https://puu.sh/uo7l0/a231485d14.png

samueldev20:02:34

1 fails accordingly: its not a map

samueldev20:02:39

3 fails accordingly, the map is missing keys

samueldev20:02:40

but 2 passes

samueldev20:02:50

even though there is no "blah" namespace being imported

anmonteiro20:02:11

@samueldev uh…`:req-un [:blah/asdf :blah/fdsa]` this doesn’t make sense to me

anmonteiro20:02:32

you’re saying “these unnamespaced keywords are required”, but you’re passing namespaced keywords

alexmiller20:02:47

the namespaced keyword is the name of the spec

alexmiller20:02:56

just the name part is used to match the key

anmonteiro20:02:20

OK I’m probably not the best person to be answering spec questions :slightly_smiling_face:

samueldev20:02:05

i guess im saying i would expect #2 to fail

alexmiller20:02:31

Is there a spec for :blah/asdf ?

anmonteiro20:02:34

it has :asdf and :fdsa which are required

samueldev20:02:40

no @alexmiller

samueldev20:02:46

there is no blah namespace being imported

samueldev20:02:51

nor a :specs/blah defined

alexmiller20:02:52

then as @anmonteiro said, it’s meeting the spec

alexmiller20:02:08

the spec requires those (unqualified) keys to exist, and they do

samueldev20:02:43

is :blah/asdf going to make it look for the key :asdf? i guess im just misunderstanding

alexmiller20:02:54

that’s what the “-un” part means

samueldev20:02:56

i would think that :blah/asdf would only look for :blah/asdf

alexmiller20:02:45

(s/keys :req [:blah/asdf :blah/fdsa]) will look for a map with keys :blah/asdf and :blah/fdsa

samueldev20:02:57

^ as i would expect

alexmiller20:02:01

(s/keys :req-un [:blah/asdf :blah/fdsa]) will look for a map with keys :asdf and :fdsa

samueldev20:02:25

okay. so basically i can effectively think of the -un as trimming anything but the last part of the keyword (anything after a /) ?

alexmiller20:02:38

in both cases, keys will try to validate the value for those entries with the specs for :blah/asdf and :blah/fdsa

alexmiller20:02:07

the / is the divider between the qualifier and the name of the keyword

samueldev20:02:59

okay. that was my confusion then. i assumed that :blah/asdf would not do any "trimming" and would look for explicit :blah/asdf - i understood it was only parsing qualifiers VS keywords when using :req

samueldev20:02:30

my bad :slightly_smiling_face: thanks so much for the clarification guys

samueldev20:02:39

if i have :blah/asdf and :blah2/asdf, how does it resolve?

samueldev20:02:52

also in the above examples i perhaps wasnt clear: :blah/asdf and :blah/fdsa are not defined anywhere

dnolen20:02:00

they don’t need to be

dnolen20:02:03

keywords aren’t resolved

alexmiller20:02:25

if you have two :req-un specs that share the same name, the result is undefined (so don’t do that)

samueldev20:02:16

so

(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:blah/fdsa]
          :opt-un []))
Does not throw an assertion error, but
(s/def ::this-is-a-test-map-spec
  (s/keys :req-un [:fdsa]
          :opt-un []))

does

samueldev20:02:48

i would expect the latter case to work given the above assessment

alexmiller20:02:14

in both cases, you are expected to provide a fully-qualified keyword that refers to a spec

alexmiller20:02:12

keys does two things: 1) checks that required keys exist (fully-qualified for req, unqualified for req-un) and 2) checks that the value for every key is valid according to the spec

favila20:02:33

@samueldev Said differently, :req-un and :opt-un are the only exception to the spec rule that "Map specs should be of keysets only" https://clojure.org/about/spec#_map_specs_should_be_of_keysets_only

favila20:02:20

It only allows one kind of aliasing: an un-namespaced key to a spec with a matching name part.

favila20:02:31

rather than arbitrary keyword to the spec

alexmiller20:02:41

I don’t see how that’s an exception

alexmiller20:02:08

it’s still a map defined by its key specs

favila20:02:32

the same keys could be mapped to different specs

favila20:02:43

depending on the spec for the map

alexmiller20:02:23

every map spec still defines only one spec for that key though

favila20:02:52

yes but {:foo "x"} could be e.g. :bar/foo or :baz/foo spec depending on what spec you choose to conform the map to

alexmiller20:02:34

yes, but you must choose. whichever you choose, the map spec specifies the key spec

favila20:02:37

but the key in the map and the key for the spec do not match

alexmiller20:02:10

but that doesn’t violate the point being made in that section

alexmiller20:02:23

which is that a map spec is built up of key specs

alexmiller20:02:05

and the specs used for values in the map are not specified by the map spec but by the spec identified (whether exact or partial match) by the key

alexmiller20:02:44

I’m disagreeing with "the only exception to the spec rule"

favila20:02:27

> I.e. in such approaches the schema for a map might say :a-key’s type is x-type and :b-key’s type is y-type

favila20:02:46

I'm saying :req-un and :opt-un is a very limited way of letting this property in

favila20:02:31

(i.e. the field name and the type name differ)