Fork me on GitHub
#beginners
<
2017-08-23
>
athomasoriginal00:08:29

I have a a JS array of objects that looks like this

const years = [
  { year: 1879 },
  { year: 1643 },
  { year: 1564 },
  { year: 1500 },
];
I am trying to filter values between 1500 and 1600 which I have written like this:
(filter #(<= 1500 (:year %) 1600) js/years)
The above always returns an empty list. I should note that the js is defined in <script> tags within an html file - just to make practising easier šŸ˜‰ so the js/years does contain the expected data structure. I believe my syntax is correct because if I change the object from a JS array of objects, to a clojure list of maps it works as is. Any pointers?

shaunlebron01:08:39

@tkjone the error is in (:year %), which doesnā€™t work on js objects

shaunlebron01:08:31

you can either convert the object to clojure with js->clj, then the filter will work

shaunlebron01:08:15

or you can stay in js and use (aget % "year")

athomasoriginal01:08:35

Thanks, shaunlebron - that makes sense. Curious, when developing cljs and doing something like this, is it best practice to stay in js land or convert?

shaunlebron01:08:50

@tkjone if I care about performance or if Iā€™m trying produce js objects, then iā€™ll stay in js

shaunlebron01:08:16

js->clj can be slow

shaunlebron01:08:57

but obviously, code is going to look more idiomatic when dealing with clojure data

shaunlebron01:08:43

there are still first-class facilities for dealing with js data as is, but itā€™s not going to look or feel as good

shaunlebron01:08:11

I feel this is by design so you always know what youā€™re dealing with

shaunlebron01:08:07

honestly, if Iā€™m doing heavy JS processing, Iā€™ll just write it in JS if it gets hairy, no point fighting that

athomasoriginal01:08:04

Yeah, that makes sense. Cheers!

shaunlebron01:08:51

@tkjone if you want more depth, the question of using keyword lookups on JS objects came up in this twitter thread: https://twitter.com/mfikes/status/882585745424338944

shaunlebron01:08:16

(second comment in the twitter thread)

shaunlebron01:08:31

that might raise more questions than answers, but we are here in slack for more depth when you want it!

athomasoriginal01:08:24

would it be correct to say, based on that tweet, that while (aget % "year") is fine, another option is (goog.object/get % "year")?

athomasoriginal01:08:41

I probably messed up the syntax, but I can research that a little.

shaunlebron01:08:29

aget is legacy but works well, gobject/get is recommended, and oget is my personal recommendation from https://github.com/binaryage/cljs-oops

athomasoriginal01:08:39

why the preference on the third-party library?

shaunlebron02:08:40

@tkjone i find gobject less friendly in this case

shaunlebron02:08:13

oget/oset are easy to remember and they are multiple arity, not true for gobject

shaunlebron02:08:30

it also supports things like ocall so you never have to worry about externs

noisesmith16:08:07

@shaunlebron @tkjone aget only works accidentally and might not work in future clojure versions

didibus18:08:41

@noisesmith Woa, what are we talking about? Clojurescript? And do you mean aget for objects only? Why wouldn't it just get fixed to work again for arrays if it gets broken in future versions?

noisesmith18:08:42

I meant on objects - aget is only meant for arrays, and the question was about looking up keys in js objects

noisesmith18:08:21

it happens that aget accidentally allowed lookup in objects in cljs, so it became a relatively common thing, but it could break at any time

didibus18:08:30

Okay, ya, makes sense, was never meant for objects

emilaasa19:08:45

Is there a good talk about clojure programmers workflow? I started working thru braveclojure literally yesterday and I think the part I'm both most intrigued by, and least knowledgeable about is how to actually "do" dynamic programming.

noisesmith19:08:10

I assume you donā€™t actually mean dynamic programming - do you mean programming without static types? https://en.wikipedia.org/wiki/Dynamic_programming

emilaasa19:08:49

I'm unsure about my terminology here, but I mean the act of programming without static (and explicit) types.

noisesmith19:08:11

right, OK - just double checking but thatā€™s what I thought.

noisesmith19:08:39

the real key, if you arenā€™t doing so already, is to spend a lot of your time using the REPL

emilaasa19:08:08

Yeah, I've gotten as far as writing stuff in a file and sending it to the REPL for evaluation

noisesmith19:08:11

this can include using an atom while developing to capture data that you get in a certain context, in order to experiment with it in a repl

noisesmith19:08:18

yeah, Iā€™m not talking about using a file

seancorfield19:08:50

@emilaasa Have you watched Stu's talk on the REPL?

emilaasa19:08:08

Yep you linked it yesterday and I watched it

noisesmith19:08:09

for example, this is a pretty great pattern:

=> (-> foo type)
...
=> (-> foo keys)
...
=> (-> foo :bar type)
where at each step you up-arrow and add something new to find out more about the data in question

emilaasa19:08:38

@seancorfield It got me pretty excited! But I feel like I would like to see some actual screencast workflows to understand better how it's done

emilaasa20:08:16

Thanks sundarj they look great!

sundarj20:08:57

no worries šŸ™‚

emilaasa19:08:44

@noisesmith It's pretty much what I'm doing now, except I'm not typing into the REPL but to a file and sending the expression to the REPL after each stumbling step I take

seancorfield19:08:30

If I didn't spend most of my time working on proprietary code I can't share, I'd probably livecast a lot more...

emilaasa19:08:27

I've found watching some screencasts can help a tremendous amount with things like workflow, problem solving and similar subjects

akiroz20:08:54

I remember being asked to solve a problem in an interview using DP... I was free to choose my language so naturally I just (memoize (solve-sub-problem)) in clojure šŸ˜¬

zlrth23:08:47

Iā€™d expect this to output 1, not 0. why is this?

user> (let [c (atom 0)]
        (for [el [1 2 3 4]]
          (if (= el 3) (swap! c inc)))
        @c)
0
my for loop itself seems to be working:
user> (let [c (atom 0)]
         (for [el [1 2 3 4]]
           (if (= el 3) "three")))
(nil nil "three" nil)
but i canā€™t seem to do anything in the then clause of the if statement if i dereference c after the for expression:
user> (let [c (atom 0)]
        (do
          (for [el [1 2 3 3 4]]
            (if (= el 3)  (print "swap! was called")))
          @c))
0

seancorfield23:08:49

for is lazy so it doesn't get evaluated here.

zlrth23:08:13

ah. thanks.

seancorfield23:08:27

Since you only want side-effects, you should use doseq instead of for

seancorfield23:08:36

(`for` produces a lazy sequence of results and only realizes as much of it as the consuming code requests; doseq eagerly processes all elements and just returns nil)

seancorfield23:08:27

for trips up a lot of people new to Clojure because they think it's like a for-loop in non-functional languages.

zlrth23:08:13

fixed. yeah. i guess i intuitively thought ā€œmap is for lazy and for is for strict.ā€ thanks again.

noisesmith23:08:53

yeah, I kind of wish ā€œforā€ had a different name, because it isnā€™t a loop, itā€™s a list generator