Fork me on GitHub
#beginners
<
2020-02-09
>
Cameron01:02:44

@jason358 that's really interesting, I would not have imagined the performance changing (as unless I missed something, the code itself is just straight interop), I'd like to look more into that myself

Cameron01:02:32

oh you know actually I wonder, there's something I'm gonna try

Ivan Koz02:02:54

why don't we use java convention for classpath package names, i.e ./org.domain.project.core?

andy.fingerhut02:02:57

Who do you mean by "we"? http://clojure.org does.

andy.fingerhut02:02:17

It is project by project whether someone does or not, and many people have obviously chosen not to.

Ivan Koz02:02:49

i'm not speaking of maven groupid

Ivan Koz02:02:24

rather ns package path, to avoid class-path collision

andy.fingerhut02:02:43

My answer is the same either way 🙂

andy.fingerhut02:02:14

A few projects do, most do not.

Ivan Koz02:02:51

i said we, because out of many clojure libs i've seen only few used conventional package names

andy.fingerhut02:02:13

we is a set of individuals, each of whom made their own choice, so there could be N different reasons.

andy.fingerhut02:02:42

I suspect a common one is: it is a pain when starting a small open source project to create a new official domain name, if you do not already have one

Ivan Koz02:02:46

so i'm looking to hear about these reasons

andy.fingerhut02:02:18

you do not necessarily know in advance whether it will become widely used. Once established, changing the name is a pain for users of a library.

andy.fingerhut02:02:17

Also, in practice, people are good at avoiding conflicts, and/or the newer one deferring to an existing/established one if a conflict is discovered.

andy.fingerhut02:02:36

I don't know statistics or examples in the Python world, but they don't use the Java convention, and have a much larger collection of library names than Clojure does, I believe, and I haven't heard that the Python world can't find a way to get along without using the Java naming conventions.

Ivan Koz02:02:09

interesting, thank you

andy.fingerhut02:02:30

If there were billions of people not using the convention and creating a library every day, there would be many more conflicts. The actual rate of library creation for Clojure, Java, and Python are much lower than that, and people creating new libs aren't completely unaware of existing names, because they are typically collected together into package repositories/directories

👍 1
alexmiller03:02:36

In my opinion, you should use a top level ns that is something you own, via either trademark or domain name, or just maybe a conferred id via github user (which I wish we had more strongly established a convention around). And if you’re not doing that, you’re wrong. But I also don’t want to be the jerk telling people what to do all the time.

alexmiller03:02:49

And ditto the lein/clojars convention for groupid

andy.fingerhut03:02:36

io.github.<username> is certainly one domain name everyone "owns" simply by virtue of creating a Github account with a unique name.

andy.fingerhut03:02:19

Long term (e.g. decades) I do not know whether Github would ever allow those account names to be reused.

andy.fingerhut03:02:01

but my previous comment implies switching from "accidental conflicts of names" to "malicious intentional conflicts of names". Avoiding accidental conflicts among cooperating people is pretty easy.

seancorfield03:02:21

I asked folks about next.jdbc before I went from alpha to beta. One of the things I asked about was the namespace structure, since I wondered about next.jdbc vs something like seancorfield.next.jdbc -- no one seemed to care and I really felt kind of uncomfortable about my name being in everyone's :require clauses 😞

Ivan Koz04:02:30

i would be absolutely fine seeing your name every day @U04V70XH6 =)

👍 1
didibus07:02:59

I kind of hate single part namespaces, like just the name of the lib. But I also think the full reverse domain convention of Java is excessive.

didibus07:02:32

I like going with just: org-name/lib-name/ns-name

didibus07:02:02

where org-name can be your own favourite online alias or whatever.

Aviv Kotek09:02:37

Using multi-methods and trying to dispatch on wildcards. e.g: (defmulti foo :type) (defmethod foo :rectangle OR :circle (fn [x] (println "i'm rectangle or a circle"))) (foo {:type :rectangle})

=> "i'm rectangle or a circle
how can I get desired behavior? couldn't find anything on docs

bartuka10:02:52

yeah, that's very weird rsrs. But what is happening is this: The keyword ::default is used as a * operator, however, when you call the defmulti with (nil :b) the defmulti does not find a dispatcher for it, so it will go direct to the :default implementation. Right there, he is using the get-method function and looking for an implementation that matches [*, :b] which is saved in the recover variable. after this step he is only validating that recover is not the :default implementation that he is current in [or it would produce a call to itself again] and then he calls this new implementation at (recover * :b)

bartuka10:02:23

I just don't know if it is really necessary to use the (.addMethod...

bartuka10:02:28

you can see that this is a bit hacky, because if you try to call (recover ::default :b) he will find the implementation and will not print that message

Aviv Kotek10:02:50

then what do you suggest? stick to the 'clever-disaptcher' option then?

bartuka10:02:05

for this specific case you show, I would go with the clever dispatcher and use a keyword like :rectangle-or-circle in the defmethod to make my intent clear

Aviv Kotek10:02:53

Maybe this worth a SO thread?

Aviv Kotek10:02:59

Could be a solution we don't know?

bartuka11:02:12

for sure it could have o/

Ben Sless12:02:48

It sound more like you want to do pattern matching and not necessarily dynamic dispatch

Ben Sless12:02:33

Have you looked into using core.match or other solutions based on it (such as defunhttp://github.com/killme2008/defun)

alexmiller15:02:49

multimethods support arbitrary keyword hierarchies - why not create a parent that :rectangle or :circle derive from?

alexmiller15:02:25

(def shapes (-> (make-hierarchy)
                (derive :rectangle :shape)
                (derive :circle :shape)))
  (defmulti foo :type :hierarchy #'shapes)
  (defmethod foo :shape [shape]
    (println "I'm a" (:type shape) "shape"))
  (foo {:type :rectangle})

👍 1
🚀 2
bartuka09:02:42

@aviv I would reproduce this behavior by writing a smarter dispatcher, something like:

(defn clever-dispatcher [{:keys [type]}]
  (cond
    (or (= type :rectangle) (= type :circle)) :rect-circle
    :else :square))

(defmulti foo (fn [v] (clever-dispatcher v)))

(defmethod foo :rect-circle
  (fn [x] (println "i'm rectangle or a circle")))

(foo {:type :rectangle})

bartuka09:02:56

but might be better to have two defmethod [:rectangle and another to :circle] and factor out the function that implements the behavior out, then call this function inside each defmethod to "re-use" the common code.

Aviv Kotek10:02:58

yea I thought about those options, but thought there's maybe any wildcard support to make it cleaner

Aviv Kotek10:02:29

there is a wildcard example in docs, but couldn't grasp it

bartuka10:02:55

can you share the link? I could not find it

Aviv Kotek10:02:19

let's continue on thread

Oz12:02:39

Is there a trick in cider/emacs to structurally edit a map? e.g, I have this line

{:padding    "1em"})
and I want to turn it to
{:padding    "1em"
   :margin     "1em"})
without traveling to the "}" mark before going down a line. It's a really small difference, but I think it makes sense.

flefik13:02:59

you mean when writing code in the editor?

flefik13:02:14

Is this what you are looking for?

didibus18:02:04

Don't think there's a default way no

Oz18:02:46

@UAEFFG05B thanks a lot for the resources! Its probably worth to invest a little more in practicing working with paredit, and it will get more fluent, and if its still bugging me I'll try to write a snippet to deal with it

didibus02:02:27

If you're looking for something good in emacs. Try adjust-parens + aggressive-indent-mode + smartparens

didibus02:02:37

Best combo in the world if you ask me

jwoods18:02:38

What is the easiest way to parse a time string to clojure time?

"2019-01-01T00:34:36"

Baris Aydek19:02:24

Hey. I have a beginner question. I'm trying to use namespaced keywords with :: . So I have 2 modules/files: (ns ex.core) and (ns ex.product) in product I have:

(ns ex.product)

(defn product-price [product] 
  (product {:car 2000 ::ps4 500}))

(product-price ::ps4) 
in core I have
(ns ex.core (:require [ex.product :as product]))

(def fee-usd 1.5)

(defn cost-of-product [p-type] 
  (+ (product/product-price p-type) fee-usd))

(cost-of-product :product/ps4)
in product, the call product-price returns 500 as expected while in core I have NullPointerException What am i doing wrong?

bartuka19:02:57

::ps4 is fully qualified, so it should be the same as :ex.product/ps4 . The usage of ::product/ps4 should work too [merged the two answers]

Baris Aydek19:02:17

yeah it worked with ::product/ps4

👍 1
Baris Aydek19:02:29

yeah confirmed. both full namespace :ex.product/ps4 and ::product/ps4 works. Thank you

alidlorenzo20:02:09

can keywords not be passed directly as function arguments? e.g. a function called foo that destructures its args, this usage throws an arity error (foo :key1 :key2) so if I change function foo to not destructure args and just take a vector, this works (foo [:key1 :key2])

hiredman20:02:49

They can, your destructuring is likely incorrect

alidlorenzo20:02:27

@hiredman hmm it's macro, so maybe that's why? here's what i'm basically doing

(defmacro foo
     [& args#]
     `(apply foo* (cljs.core/clj->js ~args#)))

alidlorenzo20:02:01

ah now that I think about it it's maybe the # suffix

hiredman20:02:41

Just don't write macros until your are more familiar with the language

hiredman20:02:40

That just straight up doesn't need to be a macro

alidlorenzo20:02:18

i wanted to convert cls values to js at compile time

hiredman20:02:45

No, you don't, and that macro is not doing that

hiredman21:02:00

a clojure macro is a little program writing in a meta language that takes in a clojure expression and returns a new clojure expression, it is confusing because the meta language is also clojure

hiredman21:02:34

it might actually be slightly easier to follow in clojurescript because in cljs macros are programs written in clojure that take in clojurescript expressions and return clojurescript expressions (the meta language and language are not the same)

hiredman21:02:10

so to write a macro you need to:

hiredman21:02:21

1. understand the language (clojure or clojurescript)

hiredman21:02:30

2. understand the meta language (clojure)

hiredman21:02:20

3. understand quoting (which determines if your expression is in the language or the meta language)

hiredman21:02:25

looking at your macro(trying to use apply to invoke a function on a js value, and the way you are handling varargs), and what you said about it (saying it converts cljs values to js at compile time, when the way stuff is quoted means it definitely doesn't do that, and understanding the difference between the language and the metalanguage makes that super problematic even if you got quoting right), makes me think you might need to work on all 3 points (really #3 is critical)

alidlorenzo21:02:32

the js function takes a list of args, if i was calling it via js i'd just destructure them foo(...args) from google search found that I can use apply to have similar effect, not sure if there's a better function for that.

alidlorenzo21:02:14

but yea, I'm definitely still a beginner, just wanted to use a macro for generating styles to be consistent with macros used with cljs react* wrapper I'm using. I tried following their code to have a similar effect in my own macro (https://github.com/Lokeh/helix/blob/master/src/helix/impl/props.cljc#L62-L63) so yeah, I'm not sure why you're saying it doesn't do that at all but as you mentioned, perhaps I do need a better grasp at the language first

hiredman21:02:17

so that code isn't a macro, and doesn't translate cljs data structures into js datas structures at compile time

hiredman21:02:23

the #? causes the dialect (clojure or clojurescript) to determine what the reader reads, so on clj you will get

`(->js ~(val entry))
but on cljs you will get
(->js (val entry)))
neither of which is a macro

hiredman21:02:54

the first is a quoted form, the second is a function call to the ->js function

hiredman21:02:42

I don't write clojurescript so I am not sure if it's apply function does things differently from clojure's, but clojure's apply function takes the arguments as a seqable thing, so doing the equivalent of what you are doing (taking the collection of arguments, dumping it in to an array, and then calling apply) is bizarre.

hiredman21:02:12

the ... syntax in js is also not destructuring (I think I've seen it called spreading), so to avoid confusion it is best not to refer to it as that. destructuring is a binding syntax that allows you to not just bindg a name to a value, but bind names to specific parts of a value, and clojure and javascript both have some version of this

hiredman21:02:21

(it does look like ... is re-used as part of the destructuring syntax in js, which might be confusing)

alidlorenzo23:02:04

ah yes, the word I was looking for was spreading. and yeah, I know it's not a macro, but that function is then being used inside a macro. so i figured the effect would be the same. but anyway, appreciate the attempt at clarification. will try and stick to functions for now until i become more familiar w clojure

hiredman00:02:06

Because the macro language for clojurescript is clojure, the version of that function being called from the macro is the clojure one that returns bthe quoted form, so ->js is not called until runtime