Fork me on GitHub
#beginners
<
2017-11-07
>
derpocious00:11:47

Hey all, I'm trying to build a function that takes a string and returns a vector of characters that occur more than once in the string. I'm using "into []" to turn the string into a vector of characters, then I'm trying to use reduce on that vector.

derpocious00:11:06

But reduce only has one accumulator collection. I feel like I need one collection to hold chars I've already seen and another to be the collection that I return. Am I doomed? :(

smith.adriane00:11:14

(reduce (fn [[unique even-count] num]
          [(conj unique num)
           (if (even? num)
             (inc even-count)
             even-count)])
        [#{} 0]
        (range 10))

smith.adriane00:11:26

here’s an example that keeps track of all the unique numbers

smith.adriane00:11:32

and also counts the number of even numbers seen

smith.adriane00:11:00

which isn’t really useful, but is similar to your example

smith.adriane00:11:56

the accumulation doesn’t have to a collection

smith.adriane00:11:03

it can be anything

donaldball00:11:36

If you’re not intent on doing it in one pass, you could do one pass to build the frequencies and another to build the results

smith.adriane00:11:57

@donaldball’s suggestion is probably a better way to do it if you’re reducing to two quantities that have nothing do with eachother

smith.adriane00:11:05

as in my example

smith.adriane00:11:46

but you can use a similar approach to my example if you had to keep track of two quantities that do depend on eachother

derpocious00:11:02

Ah thanks @smith.adriane well the accumulation is a vector isn't it? 😛 but I guess it can be a collection of other collections? Is that a huge way to do it. Is it as they say idiomatic clojure?

smith.adriane00:11:40

yea, can be a map, number, string, vector, etc

smith.adriane00:11:08

(reduce + 0 (range 10))

smith.adriane00:11:44

i’m actually not sure if using a collection of collections would be considered idiomatic

smith.adriane00:11:48

maybe someone else could weigh in

tao00:11:28

Clojure is my first programming language. everyone says to pick up Clojure for the Brave and True but to be honest i'm not having a good run of it.

tao00:11:14

what would Clojurists/Clojurians recommend as an alternative?

tao00:11:39

i've even thought about abandoning the pursuit for Racket but as an art-student i'm really into Clojure as a tool for abstract programmatic art (Quil).

tao00:11:10

also not sure if abandoning my first language is the correct move so early on.

tkjone00:11:01

Hey friend, what are you interested in doing with Clojure? Or programming in general

tao00:11:24

at this juncture: maybe a static site art-text in the vein of what Pollen allows and abstract art with Quil.

tkjone00:11:46

Nice. What made you choose clojure?

tao01:11:06

i use Emacs every day and came across this quote you're probably familiar with that learning a Lisp was an "enlightenment experience". i'm heavily invested in meditation so that tickled me.

tao01:11:28

Emacs is in fact my entire desktop environment. 🙂

tkjone01:11:56

You've configured emacs, yes? So you are familiar with emacs lisp?

tao01:11:28

i started with Spacemacs but recently tore off the training wheels and set up my own config with evil-bindings and all of the Ivy/Counsel packages. i'd say familiar insofar as i can tell use-package what to install and set variables with (setq)

tao01:11:14

i still have trouble. my mind is not "in the vein" of a classic programmer's i think.

tao01:11:52

i write screenplays and spend a lot of time thinking about film mostly. 🙂

tkjone01:11:31

That should not be a problem. These insights will likely make you a stronger developer.

tao01:11:07

oh that's comforting to hear!

tao01:11:11

right now it feels like i'm struggling to grok even the most basic things and that really hurts my confidence

tkjone01:11:46

As for learning clj/s, I have been on the same journey myself. A good starting point is these forums. Perhaps something like https://github.com/ClojureBridge/curriculum will be helpful

tao01:11:19

what sort of background did you come from?

tkjone01:11:44

and Quick Clojure

tkjone01:11:18

Agree with sundarj - that series is excellent

sundarj01:11:49

and yeah, don't sweat it about prerequisite knowledge - there isn't any

tao01:11:57

@ oh yes! in fact SICP was the first thing i tried to work through but it's intensely math-oriented.

tao01:11:37

when i hit the third exercise, i spent hours on it and had to bail, it was so frustrating.

sundarj01:11:01

http://www.catb.org/~esr/faqs/hacker-howto.html this is the document that got me into programming, maybe you'll find it helpful

sundarj01:11:54

sorry to hear about your frustration 😞

tao01:11:37

@ thanks for the compassion. it is this dense sheet of murk right now. i'll check out your link.

sundarj01:11:11

i've heard good things about http://landoflisp.com/ and https://mitpress.mit.edu/books/little-schemer too (plan to read them eventually)

tao01:11:38

@ the author of Brave actually mentioned Land of Lisp was his first intro to lisps in general on Cognicast.

sundarj01:11:26

programming is more about the way you think than the language you happen to use, so don't sweat it if it doesn't come to you at first

tkjone01:11:03

Yes, Eric is boss

tao01:11:59

@ this looks interesting.

tao01:11:31

ah they're video casts.

tao01:11:35

even better

sundarj01:11:22

don't forget to play, experiment, explore - have fun with it! don't worry about the end goal for now, just do things, see what happens 🙂

sundarj01:11:56

think about how you learnt screenwriting, it's going to be a similar process with programming (and they're both just forms of writing language, to boot)

sundarj01:11:35

ah yes, this is a great, approachable series of blog posts: https://aphyr.com/tags/Clojure-from-the-ground-up

sundarj01:11:16

also, welcome to programming! it's fun once you get the hang of it, i promise. don't be afraid to ask any questions you might (will!) have here in #beginners

tao01:11:49

@ thank you so much! i have a forest of links to sort and prioritize now. 🙂

cody_slack02:11:41

Clojure for the Brave and True was/is pretty tough for me too. The code examples weren't the way that I would have thought to do it so it thew me for a loop on the end-of-chapter project things. So if that's your problem with it I wouldn't worry too much. It ended up clicking for me without even realizing it until I actually had to use it on something of my own.

mcall2502:11:21

Hello, I need help! I really appreciate your time an help. Problem: I want to format the response of a get request. Currently, I am able to return a generic JSON response from a RESTAPI ( http://localhost:3000/users ) and return all the JSON data returned from my Query (Select * from Users). However, This is not what I want. Instead, I would like to query the data from my database and then transform and format the data. I would like the data to be return in an object that looks like this {data: [ {name: "mike", last: "call" } ] }. Question. how do I manipulate and format the response of my query (Select * from users)? for example, how can I run my query and then format the response with ( :row-fn (fn [row] {:row (row :first-name)}) ) and then push the response to the frontend with a Json format or just a useable format for the frontend. what middleware, libraries, or response information am I missing? I feel that I have tried everything. Please check out my code and see the libraries and code structure I have. It should be super simple. Please follow the flow in my snippet. and check out the github repository (https://github.com/mcall25/shouter) to understand the flow of the code.

madstap02:11:54

@smith.adriane @derpocious It is idiomatic to use a vector of collections in reduce (I'm not really an authority on the subject, but it is widely used, personally I consider it clearer than the alternatives, and it's apparently really fast)

mseddon14:11:25

is there a function like group-by that returns a 2-tuple for a boolean test function?

mseddon14:11:46

I can destructure a map with true/false keys, but wondered if there's a tidier way

retnuh14:11:36

Something like this maybe?

retnuh14:11:03

(vec (vals (group-by even? (range 10))))

mseddon14:11:23

oh, that's neat

mseddon14:11:04

but i wonder if the hashing algorithm will always put them in the right place? 😕

noisesmith14:11:15

#(reduce (fn [[t f] e] (if (% e) [(conj t e) f] [t (conj f e)]) [[] []] %2)

noisesmith14:11:06

might be worth making it into a transduce with transients actuall

retnuh14:11:15

it wouldn't necessarily preserve order, if that's what you mean (then again, maybe it will... hmm)

noisesmith14:11:32

it is not guaranteed to preserve order between clojure versions

mseddon14:11:34

i checked- it's consistent in clojurescript and clojure for booleans, but that's blind luck 🙂

retnuh14:11:27

well group-by will do the right thing; true and false are different keys

mseddon14:11:49

yeah, it's fine for my purposes, i was just wondering if there was a builtin i'd missed

retnuh14:11:06

ah I see what you mean, in terms of the order of the vals. Gotcha.

mseddon14:11:23

oh, actually another noob question, can I put a native javascript object in a map as a key?

mseddon14:11:06

i'm thinking in particular, things like DOM elements, keyed on identity but it's a bit scary

chris14:11:25

you can, it's not likely to be advisable though, for the reasons you mention

mseddon14:11:50

vanishing mutable objects in hashes is fun 🙂

noisesmith14:11:01

+user=> (load-file "/tmp/foo.clj")
#'user/t-f
+user=> (t-f even? (range 10))
[[0 2 4 6 8] [1 3 5 7 9]]
(defn t-f                                                                       
  [pred? coll]                                                                  
  (transduce identity                                                           
             (fn                                                                
               ([] [(transient []) (transient [])])                             
               ([[t f]] [(persistent! t) (persistent! f)])                      
               ([[t f] e]                                                       
                (if (pred? e)                                                   
                  [(conj! t e) f]                                               
                  [t (conj! f e)])))                                            
             coll)) 

mseddon14:11:03

nice, thanks! still getting my head around transducers

rcustodio14:11:37

about core.async, all go blocks share the same pool size? example (go …..) (thread (go ….)) even if I do that, they still share the same pool size and the same concurrency (thread)? or the first is in main thread and the second is in a second thread?

noisesmith14:11:57

that thread call is just a waste of a thread

noisesmith14:11:08

thread is for when you want a blocking operation to return a channel

noisesmith14:11:56

all go blocks use the same small thread pool, the reason to use thread is so that you don't block one of those small number of go threads

noisesmith14:11:13

because otherwise you can block up all the go blocks in the whole program easily

rcustodio14:11:28

but its kind of that, rmq consumers (thread (consumer/start)) inside of that i will use go for on-mesasge

noisesmith14:11:13

OK - sure - but if all you are doing is putting a message on a chan, use (put! c msg) instead of (go (>! c msg))

noisesmith14:11:42

or, better yet, just return msg, and then let the one who started the thread read it from the chan thread returns

noisesmith14:11:07

none of this applies if it's more than just putting a message on a channel of course

rcustodio14:11:38

you are saying instead of

(fn [ch {:keys [message-id delivery-tag reply-to]} ^bytes payload]
                       (>!! chan {:ack #(rmq/ack rmq-state ch delivery-tag)
                                  :company (protobuf/<-bytes CompanyProto$Company payload)
                                  :message-id message-id
                                  :reply-to reply-to}))
i do
(fn [ch {:keys [message-id delivery-tag reply-to]} ^bytes payload]
                       (put! chan {:ack #(rmq/ack rmq-state ch delivery-tag)
                                  :company (protobuf/<-bytes CompanyProto$Company payload)
                                  :message-id message-id
                                  :reply-to reply-to}))

rcustodio14:11:44

It’s just putting messages

rcustodio14:11:40

For external communication I will use rabbitmq, but for internal I will use core.async

rcustodio14:11:02

Faster communication if it’s internal

noisesmith14:11:18

right, and if that fn is being called directly in a thread call, you can just use more like:

(let [result (<! (thread (ack-fn m payload)))] ...)
inside a go block

noisesmith14:11:34

and inside the fn, you just return the map, instead of putting it on a channel

rcustodio14:11:34

my on message is like this

(defn- on-message [rmq-state mongo-state chan service]
  (go-loop [message (<! chan)]
    (let [[errors ok] (valid? (:company message) true)]
      (if (true? ok)
        (save mongo-state (:coll service) (:company message))
        (send-error rmq-state (:message-id message) (:reply-to message) 400 errors))
      ((:ack message)))
    (recur (<! chan))))

noisesmith14:11:06

oh, so that fn is being invoked multiple times and keeps returning messages to that chan

rcustodio14:11:06

I used go-loop

rcustodio14:11:30

Yes, would be like (while true)

rcustodio14:11:16

So… doesn’t matter where I put go-blocks (if its inside a (thread) call), they will always share the same pool size and thread

noisesmith14:11:35

@rcustodio also, another issue entirely, never do a go-loop like that without checking the return value of <!

noisesmith14:11:48

it's valid to close chan, and if that happens, your current loop goes very very fast

noisesmith14:11:54

(doing nothing useful)

noisesmith14:11:44

you can change (recur (<! chan)) into (some-> (<! chan) (recur)) and it fixes that issue

rcustodio14:11:48

I don’t know what you mean… closing the chan mean that I would have to stop this consumer, right?

noisesmith14:11:08

closing a chan means that every time someone reads from it, they instantly get nil

noisesmith14:11:23

since you are not checking the return value from reading the chan, you'll get nils as fast as you ask for them

noisesmith14:11:53

probably you'll get an NPE on ((:ack message)) of course, so this one would blow up instead of hot looping

noisesmith14:11:00

but in general, check <! for nil

noisesmith14:11:05

also check >! for nil btw

rcustodio14:11:33

i see, do you mean here i would get nil very fast (>!! chan {:ack #(rmq/ack rmq-state ch delivery-tag)

rcustodio14:11:42

when i try to put a value to the channel

noisesmith14:11:52

if chan was closed, yes

rcustodio14:11:46

that some-> change would stop that and checking the message value would stop that??

noisesmith14:11:52

(some-> x (f)) means (f x) if x isn't nil, or nil (without calling f) if it is

noisesmith14:11:00

it's like -> with nil checks at each step

rcustodio14:11:09

I see, thanks

rcustodio14:11:41

if the message is nil the go-loop is gonna stop, no?

noisesmith14:11:59

not without some->

noisesmith14:11:23

as written, it gets a nil, and justgoes with that - if nil breaks something, it blows up and stops for that reason

noisesmith14:11:34

in some cases that can mean it loops fast on nil

rcustodio14:11:54

So would be like this

(defn- on-message [rmq-state mongo-state chan service]
  (go-loop [message (<! chan)]
    (let [doc (mongo/find-one-as-map mongo-state
                                     (:coll service)
                                     {:_id (:_id message)})]
      (rmq/publish rmq-state
                   nil
                   “”
                   (.toByteArray (protobuf/<- CompanyProto$Company doc))
                   {:content-type “application/octet-stream”
                    :headers (merge (into {} (:headers message)) {“out” (:reply-to message)})
                    :message-id (:message-id message)})
      ((:ack message)))
    (some-> (<! chan) (recur))))

noisesmith14:11:08

yeah, that's safer

rcustodio14:11:12

isnt the first loop message (<! chan) safer as well if i do message (some (<! chan))

noisesmith14:11:38

well no because that way message is still nil if chan is closed

noisesmith14:11:06

but if you compare, getting a nil once and getting an error because it's nil, vs. repeatedly processing nil until you get an error

noisesmith14:11:15

(when-some [msg (<!! chan)] (go-loop [message msg] ...)) might be safer?

noisesmith14:11:33

but also consider that the channel is less likely to close right as you start this loop

rcustodio14:11:40

I understand

rcustodio14:11:23

I will let <! chan Since I’m using put! chan, what is the diff from <! and also take!

noisesmith15:11:07

put! is async, and always returns immediately, unlike <! which parks, and take! which is async but also allows a callback

rcustodio15:11:08

I see, thanks

noisesmith15:11:10

really you can pair them up, >! / <!, >>! / <<!, put! / take!

rcustodio15:11:54

but with take i would use go instead of go-loop, right?

rcustodio15:11:24

core.async is really cool

noisesmith15:11:24

take! doesn't use go or go-loop

noisesmith15:11:35

it's like put! in that it doesn't use that stuff at all

rcustodio15:11:02

(defn on-message [state1 state2 chan] (take! chan (fn [message] process)) (recur state1 state2 chan)) like this?

rcustodio15:11:35

the take! is safe

noisesmith15:11:44

well - the recur will go out of control

noisesmith15:11:50

since take! doesn't block

rcustodio15:11:22

just this (take! chan (fn [message] process)) takes all my messages then?

noisesmith15:11:40

it takes one message, and does nothing

rcustodio15:11:02

so take is for one message only

noisesmith15:11:10

perhaps you would want (take! chan (fn [m] (process m))) - which will consume one value and process it

noisesmith15:11:40

of course that last one is just (take! chan process)

rcustodio15:11:03

I see, if you want a loop process then we have to use <! or <!!

noisesmith15:11:29

right, that is why we have go blocks

rcustodio15:11:43

Thanks @noisesmith, that helped a lot

rcustodio15:11:52

Finally understanding core.async

leo.ericson19:11:23

I plan to try to make an react native app and I will use re-natal, so I have 3 choices for react wrappers: reagent, om.next or rum. Which do you guys recommend?

mseddon21:11:20

I'm a beginner, but I had a bit of fun with rum and figwheel. The bonus from my perspective is rum is extremely small and simple, so you can at least decide if it is not enough quickly. The #rum slack channel is rather quiet though :(

mseddon21:11:36

I haven't tried om.next or reageant yet, so can't compare.

eggsyntax22:11:29

I'm a fan of reagent, and you've got re-frame on top of it to simplify things further, if your app fits well into a functional-reactive approach.

eggsyntax22:11:10

reagent itself is also pretty simple (although not AS simple as rum). It's got one core concept that you need to fully absorb, the ratom.

leo.ericson06:11:07

I think it might be a good idea to start with rum and if it's not enough I'll move to reagent. My app will (probably) be simple so I hope it'll be enough. Thank you for your input!

tkjone22:11:54

Before I spend much more time on this, I am trying to create a macro that when called does this:

(.-style element )
This is what I have:
(defmacro get-attr
  [el attr]
  `(let [element#   ~el
         attribute# ~attr]
     (attribute# element# )))
which would be called like this:
(get-attr highlight '.-style)
I am putting the syntax-quote infront of .-style so it does not try to evaluate the symbol. Any pointers would be appreciated. Again, this is only out of interest, not because this is a solution to a real world project

smith.adriane22:11:15

(defmacro get-attr
  [el attr]
  (list '-> el attr))

(defmacro get-attr
  [el attr]
  `(-> ~el ~attr))

smith.adriane22:11:26

that’s two different ways to write it

smith.adriane22:11:34

used like (get-attr highlight .-style)

smith.adriane23:11:53

oh, you changed example of what you wanted

tkjone23:11:16

no, thats pretty much it

smith.adriane23:11:21

one way to check see how your macro is coming along is to using macroexpand-1

tkjone23:11:25

I thought the reorder would make it clearer

smith.adriane23:11:09

so for the macro you started with

smith.adriane23:11:12

> (macroexpand-1 '(get-attr highlight .-style))
(clojure.core/let [element__30398__auto__ highlight
                   attribute__30399__auto__ .-style]
 (attribute__30399__auto__ element__30398__auto__))

smith.adriane23:11:12

> (macroexpand-1 '(get-attr highlight .-style))
(clojure.core/let [element__30398__auto__ highlight
                   attribute__30399__auto__ .-style]
 (attribute__30399__auto__ element__30398__auto__))

tkjone23:11:20

Just to understand this better, does clojure think, because .- is a special form, that when I do this

(let [local-bind .-style])
That I am trying to access an instance method? vs doing this:
(let [local-bind "string"])
Which is just a simple data type, which evaluates to itself, being bound to local-bind.

smith.adriane23:11:31

.-style is just a symbol

smith.adriane23:11:03

so in the first case, it’s going to try to look up the value of .-style

smith.adriane23:11:11

since that’s how symbols are evaluated

smith.adriane23:11:29

(.-style obj) is the full special form

smith.adriane23:11:25

the symbol by itself isn’t a special form

tkjone23:11:02

hmmm, is there a way to bind .-style like I was trying to do? so it could be passed around as a variable?

tkjone23:11:17

I am hoping that seeing a distinction will make this clearer

smith.adriane23:11:14

anyway, with macros, the big idea is that you’re writing code that writes code

smith.adriane23:11:38

so if you want (.-style obj)

smith.adriane23:11:52

you’re creating a list where the first item is the symbol .-style and the second item is the symbol obj

smith.adriane23:11:31

(list '.-style 'obj)

smith.adriane23:11:42

would be one way to do that

smith.adriane23:11:11

with a macro you’re getting passed the arguments as data

smith.adriane23:11:32

i’m not sure i’m making any sense

smith.adriane23:11:58

macros are kinda tricky at first

tkjone23:11:11

It is. I see that part. I think they become tricky because, for myself, I am still figuring out the mechanics of clojure itself. e.g. If you did this:

(def name .-style)
The above fails. I am not sure why that fails though...

tkjone23:11:50

Understanding the above, explains why my code fails, I believe

smith.adriane23:11:00

the evaluator is trying to lookup the value of .-style

tkjone23:11:47

Ah! I get it now

smith.adriane23:11:50

.-style only makes sense in the context of (.-style obj)

tkjone23:11:13

its a symbol which is trying to evaluate to something that is not there

tkjone23:11:41

Symbols reference something else - like a var. In this case, there is nothing that it references.

smith.adriane23:11:47

even (-> obj .-style) is expanded into (.-style obj)

tkjone23:11:34

Why is the error message Uncaught SyntaxError: Unexpected token .?

tkjone23:11:51

is the . evalutated separate?

smith.adriane23:11:26

the . is a special form too

smith.adriane23:11:33

used for interop in both cljs and clj

tkjone23:11:49

haha in that case its because there are no spaces, which made me think the whole thing is evaluate together

smith.adriane23:11:39

so if you a macro get-attr that is used like (get-attr obj .-style), then it will be passed in two arguments. the two arguments will be symbols with the above usage

tkjone23:11:59

To go back to the original question, is it possible to assign .-instanceField to a var? What would that look like? My thought is no because it would just expand to (. your-var -instancefield) and fail

smith.adriane23:11:18

it doesn’t really make sense to assign .-instance field to a variable

tkjone23:11:48

true. more of a "how would you do it in clojure?" kind of thinking

smith.adriane23:11:11

you can assign the symbol to a var

smith.adriane23:11:45

like you could do

(let [prop-sym (quote .-instanceField)]
                         prop-sym)

smith.adriane23:11:49

which is equalivalent to

(let [prop-sym '.-instanceField
      obj-sym 'obj]
  (list prop-sym obj-sym))

smith.adriane23:11:56

you could also write it like

(let [prop-sym (symbol ".-instanceField")
      obj-sym (symbol "obj")]
  (list prop-sym obj-sym))

smith.adriane00:11:03

which might look more familiar

tkjone00:11:38

Nice, so altogether:

(defmacro get-attr [i e]
 (let [prop-sym i
       obj-sym e]
   (list prop-sym obj-sym)))

 (get-attr .-style element)

tkjone00:11:07

Thanks! A huge step forward for me 🙂

smith.adriane00:11:50

it’s really fun to play with macros

smith.adriane00:11:12

and once you play with them a bit, it helps you understand macros that you might end up using better

smith.adriane00:11:34

like if you ever use core async, the gotchas aren’t as bad because you develop a mental model of what’s going on under the hood

tkjone00:11:43

For sure and at a minimum it forces you to understand clojure way better

tkjone00:11:24

I promise this is the last question, how can I see what this expands to (def hello .-style)

tkjone00:11:49

if this happens:

(.-instanceField instance) ==> (. instance -instanceField)

tkjone00:11:06

would the above expand to (. def hello -style)?

smith.adriane00:11:25

the special dot syntax has to match a whole list form

smith.adriane00:11:31

so it won’t get expanded

smith.adriane00:11:55

> (macroexpand-1 '(def hello .-style))
(def hello .-style)

smith.adriane00:11:51

so it only matches if the evaluator gets a list where the first item is a symbol and the symbol starts with . or .-

smith.adriane00:11:07

and the list has to have at least 2 elements

smith.adriane00:11:17

for (def hello .-style)

smith.adriane00:11:23

it’s a list with 3 items

smith.adriane00:11:45

the symbol def, the symbol hello, and the symbol .-style

smith.adriane00:11:11

since def doesn’t start with “.-“, then it doesn’t match

tkjone00:11:04

ah, so its trying to evaluate that item but looks at it and just breaks because it sees .- on a third item

smith.adriane00:11:49

I don’t have a clojurescript repl handy

smith.adriane00:11:58

but in clojure you get CompilerException java.lang.RuntimeException: Unable to resolve symbol: .-style in this context, compiling:(*cider-repl websheet*:508:24)

smith.adriane00:11:28

basically, it just sees a symbol

smith.adriane00:11:40

and the evaluation rule for symbols is to try to look up its value

smith.adriane00:11:28

I guess I’m not using the precise terminology. the evaluation rule for symbols is that they are “resolved”

smith.adriane00:11:41

this actually works in clojure

smith.adriane00:11:44

> (do
                         (def .-style 1)
                         (+ 1 .-style))
2

smith.adriane00:11:56

although I really, really don’t recommend it

tkjone00:11:30

hahaha that's scary

smith.adriane23:11:35

you can see it’s trying to bind the attribute__30399__auto__ from .-style

smith.adriane23:11:43

which isn’t exactly what you want

smith.adriane23:11:45

a more fun example is trying to create a macro that works like (get-attr window.location.host) into (-> window .-location .-host)

tkjone23:11:05

Good stuff. I will read into this a little more. Thanks! Would a macro be the only way to do the above? I know I asked this yesterday, but I am a little thrown that it would not work.

smith.adriane23:11:03

for this particular type of syntactic sugar, I would use the goog.object/get function

smith.adriane23:11:18

(goog.object/get highlight "style")

tkjone23:11:24

Yes, and than you could just wrap the above in a function if really desired. Good call

smith.adriane23:11:28

yea, I think the adage is “Don’t write a macro if a function will do”