Fork me on GitHub
#beginners
<
2018-10-18
>
jstaab00:10:58

Hey everyone, I was going to tweet out of frustration, but I figured asking for help here was a better option. After 3 years of dabbling in clojure (I've built a couple trivial projects in it), listening to Rich's talks, and just generally being sold on the language, I'm trying to get started using it at work, which means figuring out builds, linting, testing, editor integrations, and all-around dev workflow. But after 30 hours or so in the last few weeks, I'm so frustrated. It's been a worse experience than building javascript with webpack 2, or developing with php/apache. A big part of it is my lack of familiarity with java, but it should not be this hard. I've asked plenty of questions on clojurians, read tons of documentation and source, but I'm stuck. I want to love the language, and I think once I "get it" I'll be good to go. I know this is a big ask, but is anyone here willing to spend a couple hours with me on the phone or screensharing to help me get started? I feel like I'm banging my head against the wall.

peter-kehl00:10:46

https://clojure.org/reference/evaluation reads: "A Symbol is resolved: ... Else, it is not qualified and the first of the following applies: .... 1. If it names a special form it is considered a special form, and must be utilized accordingly. 2. A lookup is done in the current namespace to see if there is a mapping from the symbol to a class.... 3. If in a local scope (e.g. in a function definition or a let form), a lookup is done to see if it names a local binding (e.g. a function argument or let-bound name). If so, the value is the value of the local binding. 4. ..." However, aren't symbols in local scope considered over Java classes? (let [Object 1] Object) returns 1, not java.lang.Object. The same for (let [if 1] if). Hence, shouldn't (3) above be pushed up to be #1?

jstaab00:10:46

Feel free to pm me if you're up for something like that. Thanks.

peter-kehl00:10:02

@jstaab Hi Jon. Good your question. If you find any tutorials/resources on using Clojure at work, would you share them, please.

jstaab00:10:20

@peter.kehl I don't think Object is a special form, it's just a built-in name. Special forms are more things like if and def (full list here: https://clojure.org/reference/special_forms). These kinds of things are what lies at the base of most lisps, which are usually implemented mostly in terms of these building blocks. Object is a foreign language concept. I'd expect it to be #2, but maybe I'm misunderstanding what Object is.

hiredman00:10:58

pedantically, 'if' is not a special form, (if ...) which is why something like

user=> (let [if true] (if if true false))
true
user=>
works

hiredman00:10:20

I would not take the text there as definitive, but more as a "it is more or less like this", a complete description would, in my opinion, have to encompass reading(for at least syntax quote), macro expansion (for treatment of '.' sugar), and then compilation, which is what most of that description is concerned with

andy.fingerhut00:10:26

@jstaab Sometimes Eric Normand has spare capacity for mentoring people, perhaps made more likely with a commercial for-pay arrangement. You could try contacting him.

jstaab00:10:07

@andy.fingerhut thanks, I'll reach out!

peter-kehl01:10:09

Thanks @hiredman and @jstaab.

peter-kehl01:10:33

Evaluation order of local scope vs. Java classes at https://clojure.org/reference/evaluation still seems wrong. As per example with Object bound as a symbol.

seancorfield01:10:43

@peter.kehl I think I would agree that #2 and #3 seem the wrong way round.

seancorfield01:10:12

In reality, you'll "never" run into a conflict because class names are CamelCase but local bindings are kebab-case ๐Ÿ™‚

peter-kehl01:10:28

Thanks @seancorfield. If you eat Middle Eastern, you may love a Camel-kebab. I'm filing a pull request.

hiredman01:10:51

actually you get both behaviors, a name like foo.bar can be def'ed just fine, but the compiler will always reject it when try to use it, because it always attempts to resolve it as a class, you can't let bind it because the compiler generates a class with a field name that the jvm rejects

seancorfield01:10:46

But that name is "packaged qualified" and doesn't fall into those four rules...

TK03:10:27

Would be great to receive code review on this solution Any advice/feedback is always welcome! Feel free to comment in the PR ๐Ÿ™‚ https://github.com/LeandroTk/learning-functional/pull/12/files

TeMPOraL05:10:14

hi all ๐Ÿ™‚

TeMPOraL05:10:12

a question: what's the current best practice of using records vs. plain maps + specs?

TeMPOraL05:10:12

I've read some opinions on maps vs. records, but they were all pre-spec; does spec make records less relevant for cases not involving Java interop?

shidima07:10:52

How would I convert this java code to clojure?

publisher = Publisher.newBuilder(topicName).build();

shidima07:10:16

I am trying

(def publisher (Publisher/newBuilder topicName))
(publisher/build)

shidima07:10:24

But that is not working

shidima07:10:02

Ah, I should use the threading macro?

curlyfry07:10:03

the thing/method notation is for static methods

curlyfry07:10:20

(.method obj) is for calling regular instance methods

CyberSapiens9707:10:36

is it normal for a beginner on clojure and FP, to take 4 hours to make your own version of the threading macro? i know everyone has it's own pace of learning, but sometimes i feel frustrated...

niklos07:10:53

no its ubnormal

niklos07:10:04

its very fast learning (for me)

niklos07:10:26

and also i dont have idea what threading macro is

curlyfry07:10:59

Especially FP takes its time to wrap your head around!

Azzurite07:10:37

you can add code to slack with the "+" icon next to the message box, so you don't have to post it as an image ๐Ÿ˜‰ makes it easier for everyone helping you, too

CyberSapiens9707:10:42

i tried to make this with reduce, but soon realized that it was too difficult. later i tried to do directly using other abstractions, and no success, so i've made a decomposition of s-expressions and tried to go along with that, realized i've had to reverse the expression to make a simple one, then would have to start taking a list and applying every item to the next, and things got too hard... and i've tried to tackle the problem from another position, trying to take a simple collection and doing this kind of nesting on each other, and doing so without reduce... turns out that this was my code for using inside the macro with minimal changes

CyberSapiens9707:10:32

the way i code is extremely weird, i get lost quite a few times and then i find my own path doing all kinds of weird examinations and statements about the data...

shidima07:10:33

thanks @curlyfry this works

(def publisher (-> (Publisher/newBuilder topicName) (.build)))

andy.fingerhut07:10:18

@cybersapiens97 Macros can be quite tricky to write and get correct, even for experienced Clojure developers.

CyberSapiens9708:10:10

@andy.fingerhut glad to hear that, it gives me more confidence ๐Ÿ˜…

bronsa08:10:02

@cybersapiens97FYI it took 4 years for the version of ->> that's in clojure.core now to be written, the previous one had some nasty interaction with other macros

bronsa08:10:26

so even expert clojure developers don't get it right the first time :)

bronsa08:10:29

it's useful to think of macros not as syntax transformations but as functions from data -> data (which is what they are!)

CyberSapiens9708:10:32

hmmm i see, i like writing macros because i love using recursion by my own... yeah i treated the macro input as s-expression, so it was easier to manipulate thinking that way

schmee08:10:42

I think of programming as learning to play an instrument

schmee08:10:07

itโ€™s well established that getting good at say, guitar or piano, takes years of sustained practice, and itโ€™s the same with programming

schmee08:10:24

so just think of those 4 hours as that days daily practice session ๐Ÿ™‚

CyberSapiens9708:10:52

makes sense, you could play that song you like, but it's never going to sound the same, on the hands of a experienced artist

CyberSapiens9708:10:08

but in time you can get better

schmee08:10:29

exactly, donโ€™t feel stressed that you donโ€™t โ€œget itโ€ in 4 hours, persistence and patience is key ๐Ÿ’ช

sb09:10:58

I would like to get let params in clojurescript. I wrote a macro where I define the let params to get back.. but not so cool. I know, I can use at clojure part the &env and &form to get all data. How can I create a similar function at clojurescript part?

sb09:10:13

(defmacro debug-fn [& body]
  `(do (cljs.pprint/pprint {"ev: " ~'ev "buffer " ~'buffer "m " ~'m "cb " ~'cb "buffsub" ~'buffsub "prebuff " ~'prebuff "prebuff-1" ~'prebuff-1})
        [email protected]))

sb09:10:45

I use that like.. (debug (some-fn...)) at cljs

sb09:10:20

Could I get the let params automatically? ..because very boring to type all time the things..

moxaj09:10:39

@sb I think you can do the same in cljs, since the macros are clojure macros

sb09:10:51

@moxaj not works..

moxaj09:10:15

if you simply print the value of &env, what do you see?

sb09:10:34

yes, I would like to print the &env with a macro at clojurescript side

sb09:10:27

like this

moxaj09:10:46

you are printing during macroexpansion as a side effect

moxaj09:10:00

try

(defmacro debug [] 
  `(cljs.pprint/pprint {:form ~&form :env ~&env}))

sb09:10:52

Unfortunately, not works for me..

moxaj10:10:28

@sb right, should have been '~&form and '~&env, anyway, this should work:

(defmacro debug []
  `(cljs.pprint/pprint (hash-map [email protected](->> &env :locals keys (mapcat (fn [x] [`'~x x]))))))

sb11:10:08

@moxaj thanks works!! :+1:

Caio Guedes20:10:15

Guys, does exists any difference when you access a property with (.-myProperty ...) and (.myProperty ...) on interop?

Azzurite20:10:09

,myProperty calls it as a function, .-myProperty gets the actual value of the property

noisesmith20:10:53

.myProperty can match a field or a method. .-myProperty can only match a field. This only really matters in cljs where a field and method can have the same name

Azzurite20:10:29

@noisesmith that's not correct, .-myProperty gets the function as a value if it's a function

Azzurite20:10:39

you can do (apply (.-log js/console) ["Test"]) for example

noisesmith20:10:18

I'll take your word for it - none of that works in jvm clojure

Azzurite20:10:28

meanwhile

(.body js/document)
#object[TypeError TypeError: document.body is not a function]

Azzurite20:10:58

(.-body js/document)
=> #object[HTMLBodyElement [object HTMLBodyElement]]

Azzurite20:10:29

to word it a little differently, both .myProperty and .-myProperty access the property obj.myProperty, but (.myProperty obj) converts to the javascript obj.myProperty(); and (.-myProperty obj) converts to obj.myProperty;

noisesmith20:10:59

as long as we specify that's all cljs only, agreed

Azzurite20:10:12

you're right, I was assuming ClojureScript as that is where you mainly see the syntax

Caio Guedes20:10:38

๐Ÿค” interestingโ€ฆ I got it! thanks!

andy.fingerhut20:10:09

Is the behavior of .- documented anywhere?

andy.fingerhut20:10:50

It seems a bit special-like in Clojure/Java and ClojureScript, and quite rare in Clojure/Java in my experience, but it does do something different than if the '-' is not there.

Azzurite20:10:11

you probably basically never see .- in clojure as every Java class has their fields private

andy.fingerhut20:10:45

Thanks. The docs there explain to me why .- is not often seen in Clojure/Java --- because it works the same as . for fields in Clojure/Java, except in the rare circumstance that a 0-arg method and a field have the same name

noisesmith20:10:59

is that shadowing even possible in jvm bytecode?

andy.fingerhut20:10:21

I don't know, and it is about 7 miles beyond my curiosity level to find out right now ๐Ÿ™‚

andy.fingerhut20:10:23

I was happy to see it explicitly documented for Clojure/Java in an official place. Somehow I missed that detail before.

awb9920:10:47

I made this algo which matches the most recent report to a date. I currently use map to do it. But the implementatiojn is inefficient, as it filters the reports with each map step. I was thinking to refactor it with doseq, but I dont know how to return values from doseq into a map, and also I have no idea, how I could setup a mutating variable. I was thinking of atoms, but this is only for multithreading? Any ideas??? Thanks!

hiredman20:10:54

reduce is the way to write reports

hiredman21:10:45

or, I should say, the general structure of generating reports is usually some kind of fold, and the most common fold implementation in clojure is reduce

awb9921:10:38

@hiredman Thanks! I will try to write my problem with reduce then.

hiredman21:10:03

it looks sort of like what you are doing might be more of a join (in sql terms vs. a report which I tend to think of as using aggregate operators like count or avg)

hiredman21:10:34

in which case you should just clojure.core/for (for a cross product)

awb9921:10:39

@hiredman I am basically merging two different timeseries that have different frequencies; I am assigning to a daily series elements from the "sort of" annual series. Since I know that the series are both ordered, I was thinking that it is efficient if I would remove unnecessary elements from the second series.

hiredman21:10:30

(:output
 (reduce
  (fn [{:keys [report output] :as accum} thing]
    (if (contains? thing :releasedate)
      (assoc accum :report thing)
      (update-in accum [:output] conj (assoc thing :report report))))
  {:report nil
   :output []}
  (sort-by ; merge sort if inputs are already sorted
   (fn [thing]
     (or (:releasedate thing)
         (:date thing)))
   (concat reports series))))

awb9921:10:50

wow! Thank yo so much!

awb9921:10:08

I am just trying to understand your code. My head is still spinning. ๐Ÿ™‚ It is exactly what I was trying to do. I hope some day I will be able to write such code myself. I did read 2 books, did many samples, and still I sometimes sit for hours searching for the right approach. The non-mutation approach sometimes really needs a different approach ๐Ÿ™‚

hiredman22:10:14

macros are always :clj

sb22:10:58

that is true. In this case, how can I split the code.. call from clj or cljs?

hiredman22:10:56

just don't put the #? in a macro, you can have the macro expand in to a function call, and the function body can have a #?

sb22:10:07

Ok, sounds good. I test it! Thanks

sb22:10:30

Sorry, maybe Iโ€™m tired. But how can I use a same name in this case?

sb22:10:43

defn > macro not works.

hiredman22:10:21

no, you can't do that

hiredman22:10:40

that is kind of the opposite of what I said

hiredman22:10:21

the easiest thing would actually be to just check if :env contains :locals in the macro

hiredman22:10:47

(if (contains? &env :locals) cljs-stuff clojure-stuff)

sb22:10:12

Thanks! That is great idea!! parrot

sb22:10:24

#?(:clj
   (defn cljs-env?
     [env]
     (boolean (:ns env))))


(defmacro debugy []
  (if (cljs-env? &env) 
    `(cljs.pprint/pprint (hash-map [email protected](->> &env :locals keys (mapcat (fn [x] [`'~x x])))))
    (->> (keys &env)
         (map (fn [k] [`'~k k])) (into {})) 
    )) 

sb22:10:39

solution, maybe useful somebody

Rachna22:10:39

Hello Everyone, I am having this vector of map and I want to update all the keys :col4 depending upon col2. if :col2 = California_LA, then :col4 = Los Angeles else :col4 = San Francisco. [{:col1 Alex :col2 California_LA :col3 1111111111 :col4 } {:col1 Berry :col2 California :col3 2222222222 :col4 } {:col1 Charles :col2 California_LosAngeles :col3 3333333333 :col4 } {:col1 DJ :col2 California :col3 4444444444 :col4 } {:col1 Ernie :col2 California_LA :col3 5555555555 :col4 } {:col1 Fred :col2 California :col3 6666666666 :col4 } {:col1 Greg :col2 California_LA :col3 7777777777 :col4 }] Any Suggestion?

dpsutton22:10:50

so you want to transform each element in a collection so the general idea is (map f coll). so write a function that takes in one of your items and does this

dpsutton22:10:25

don't think about the collection just transform a single one

Sturm23:10:46

How do ClojureScript programmers store dates/datetimes for shipping around via Transit and then doing comparisons on? I'm looking for the equivalent of Python's builtin datetime.date and datetime.datetime, but I have a feeling that JavaScript Date() is not the right answer.

noisesmith23:10:13

I used either Date or an ISO string representation to convert on the other end

Sturm23:10:14

thanks @noisesmith

Sturm23:10:13

@noisesmith do you know if cljs.time produces JS date/datetimes or are they some ClojureScript specific format?

noisesmith23:10:33

not off the top of my head, I've never used it

noisesmith23:10:47

perhaps something from goog

Sturm23:10:20

Unrelated question - did something happen in 2016? I seem to keep running into ClojureScript projects and blogs that were last updated in 2016.

noisesmith23:10:03

I think it became easier to use stuff from npm, and optimized builds without needing to define externs manually? If I recall that stuff was happening around that time, and it makes "wrapper" libraries much less needed