beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
oxalorg (Mitesh) 2020-09-27T06:53:56.175200Z

When working with looping over strings, should I be using first and rest heavily or use a [Buffered]Reader? Does using a reader and passing it around means that we're now in mutable land? I'm trying to parse html something like Selmer / Mustache. Selmer is using a reader and passing it around, but I'm wondering if there are other ways to do something like that?

sova-soars-the-sora 2020-09-27T14:24:26.196Z

not a pro but, I don't think there is a significant performance benefit for the trouble involved -- not sure how it's implemented under the hood but i reckon it's probably close to optimal. Check out how other projects do it -- hiccup, selmer as you mentioned, maybe enlive by cgrand can point you in the best direction.

2020-09-27T17:11:24.200200Z

using strings via the seq api is a bad idea, the slowdown is significant

đź‘Ť 1
2020-09-27T17:12:41.200400Z

if you are just reading you can use indexing and subs, and just keep track of indexes

oxalorg (Mitesh) 2020-09-28T08:47:18.246400Z

Thanks will try the subs approach, I was mainly concerned if passing around a reader is like an anti pattern or not. I've seen it being used at multiple places so I guess it's fine.

Jim Newton 2020-09-27T09:58:57.176800Z

• The fn macro distinguishes between the two syntaxes: (fn name? [params*] exprs*) vs (fn name? ([params*] exprs*) +).

Jim Newton 2020-09-27T09:59:37.177500Z

What is the correct way in closure to distinguish between [something ...] and (something ...)

Jim Newton 2020-09-27T09:59:54.177800Z

especially when writing macros ?

Jim Newton 2020-09-27T10:31:34.180200Z

When I look at https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core.clj#L4513 it seems, on line 4525 that the function vector? is used to distinguish these two cases.

Jim Newton 2020-09-27T10:32:39.181200Z

This would seem to mean that I can use vector in my code or any structure that implements IPersistentVector. Is that true?

Jim Newton 2020-09-27T10:55:13.183Z

Is there a naming convention for functions which I intend to only be used within a file or from within the implementation of a group of functions? In common lisp it is customary to name such functions starting with a %. other namespaces which import this namespace can use such a function, but the naming convention implies they shouldn't.

Jim Newton 2020-09-27T10:55:51.183600Z

If I make such a function a local function, than I cannot write test cases for it, so it is better for development purposes to make it a top level function.

Jim Newton 2020-09-27T11:03:13.186100Z

Is there a word clojure programmers use to describe the type of destructuring which happens with a let or fn like this: ?

(let [[[a b] [c [d]]]] some-data] ...)
In Common Lisp it is referred to as destructuring but that name unfortunately is very long, resulting in very long function names such as destructuring-bind which sometimes gets abbreviated in literature as dsb which is very terse.

Darin Douglass 2020-09-27T12:11:13.193200Z

When you say “local” do you mean “defn-“? You can still write tests for those fn’s, you just have to call the var instead of the name:

(#’foo/my-private-fn)

Jim Newton 2020-09-27T13:00:45.194800Z

Can someone please remind me how to figure out which dispatch value a defmulti is returning. My program is triggering some error in the dispatch that I cannot figure out. If I have the values from the call site, I'd like to know what the code in defmulti returned, or whether it encountered an error while trying to figure that out?

chucklehead 2020-09-27T13:12:16.194900Z

You can use get-method with the method and dispatch value to see which dispatch fn would get called

chucklehead 2020-09-27T13:12:32.195100Z

not sure if that's what you're looking for exactly

Jim Newton 2020-09-27T13:32:03.195600Z

yes but how can I get the dispatch value?

Jim Newton 2020-09-27T13:32:27.195800Z

There is some function, I seem to recall, for debugging purpose, which will give you back the dispatch value.

schmee 2020-09-27T14:25:42.196200Z

yes, prefix the function with -, i.e (defn -foo [] ...). note that this is just a convention and is not recognized by the compiler in any way

sova-soars-the-sora 2020-09-27T14:25:57.196500Z

unaware of an extant term, might I suggest "pickpocketing" ... at least I can sort of grok it right away

schmee 2020-09-27T14:27:19.196900Z

it is called “destructuring” in clojure as well: https://clojure.org/guides/destructuring

schmee 2020-09-27T14:28:52.197100Z

user=> (vector? '(1 2 3))
false

user=> (list? [1 2 3])
false

schmee 2020-09-27T14:29:10.197300Z

but most code should not care about whether something is a list or a vector

sova-soars-the-sora 2020-09-27T14:29:56.197500Z

Is it prefers you're talking about? https://clojuredocs.org/clojure.core/prefers that's the closest something I could locate right now

2020-09-27T14:31:05.197700Z

True. There are very few data structures built into Clojure that implement IPersistentVector, and none that I am aware of that can be written as literal expressions in code other than clojure.lang.PersistentVector. The other I know of you can create a vector of Java primitive values using (vector-of :byte 1 2 3), but there is no literal syntax for that, so not useful in macros.

2020-09-27T14:33:00.198100Z

There is also the notion of a private function, written (defn- private-foo ...), or (defn ^:private private-foo ...). Those can be called from outside of the namespace where they are defined, e.g. useful in namespaces containing test code for such functions, but you must use syntax like #'some.namspace/private-foo to refer to them in namespaces other than the one where they are defined.

2020-09-27T14:36:30.198300Z

If you defined the multimethod yourself, then you know what the dispatch function is, and can call it on any object you want.

2020-09-27T14:38:07.198500Z

If you are asking "for an arbitrary multimethod, is there a way I can call its dispatch function, even if I do not know what that happens to be?", then I don't know of any Clojure function included in core that can do that, but there is a Java field named dispatchFn in the object with class clojure.lang.MultiFn that is public, and so you can use Java interop to get it.

2020-09-27T14:40:34.198700Z

user=> (defn foo [x] (inc x))
#'user/foo
user=> (defmulti mymm "blarg" foo)
#'user/mymm
user=> mymm
#object[clojure.lang.MultiFn 0x68ad99fe "clojure.lang.MultiFn@68ad99fe"]
user=> (.dispatchFn mymm)
#object[user$foo 0x1755e85b "user$foo@1755e85b"]
user=> foo
#object[user$foo 0x1755e85b "user$foo@1755e85b"]
user=> (identical? foo (.dispatchFn mymm))
true
user=> ((.dispatchFn mymm) 5)
6

practicalli-john 2020-09-27T17:39:05.200600Z

I probably have misunderstood, but why would a function be written just to destructure a value? I would name the function on the logic or purpose I needed destructured values for. If destructure was part of the name, would also the type of destructuring (positional, associative) be used? This seems a very low level and brittle approach. What if the function changed it's arguments and didn't destructure, or changed the type of destructuring, the name would no longer be relevant.

Jim Newton 2020-09-27T18:13:12.201100Z

Not sure that I agree. I write tests for my private functions, making testing the public functions easier. Especially when I write the private functions first, and write the public functions when I get the private ones all working.

practicalli-john 2020-09-27T18:36:55.201300Z

It is of course your right to disagree and take a different approach. I've rarely seem to use a distinction of public and private functions, the distinction seems largely irellevant, especially compared to the approach I used to take with Java and Scala. I usually have functions and helper functions, occasionally spinning off the very generic helper functions into their own namespace (which would then require refactoring the tests if they had them). I tend to write tests when I have evolved a sufficient understanding of the constraints around the 'public' functions which form the API for each namespace. The design of this API is usually more important to the overall design and should be supported by valuable tests. I tend not to write tests for everything, especially if it is tested elsewhere. When exploring a design I may write funcitons that become helper functions, used by others. However, at that stage of uncertanty I typically would not write unit tests (or not many) as the design would not be concrete enough to put into unit tests that would be stable enough to feel useful. I have found that exploring design choices in the REPL and codifying data models in spec provide an effective way to evolve my understanding of the challenge at hand. An of course just spending a good detail of time away from the computer thinking about the problem in detail (hamock time). Once specific design descisons are made then they can also be codified in test, using clojure.spec generative testing to provide a more diverse set of test data Naturally I do not have a shared set of experiences with all developers and of course you should take an approach that you find effective.

Jim Newton 2020-09-27T19:54:08.203Z

@andy.fingerhut I recall that there's an easier way. What you've done is factor out the dispatch function from the defmulti. There's a way, I just have forgotten what it is, to ask the system to call the dispatch function and give you the value back, without actually dispatching.

zhuxun2 2020-09-27T19:55:33.204700Z

Is there a way to escape the spaces in main-opts in deps.edn? They seem to always break the argument, even when they are in the quotes... For example :main-opts ["--param={:a 1}"] is always intepreted as ["--param={:a" "1}"]

zhuxun2 2020-09-27T19:56:12.205Z

It seems to be a reported problem: https://clojure.atlassian.net/browse/TDEPS-56

zhuxun2 2020-09-27T19:56:22.205300Z

Has there been any fixes? Are they any work-arounds?

jsn 2020-09-27T20:01:34.205500Z

"--param={:a,1}" should work

chucklehead 2020-09-27T20:02:46.205700Z

unless we're all talking past each other using dispatch value/function to mean different things, as best I can tell from https://github.com/clojure/clojure/blob/clojure-1.10.1/src/jvm/clojure/lang/MultiFn.java at least, the return value of dispatchFn is always immediately used to lookup the associated fn, it isn't stored anywhere besides the method cache or exposed elsewhere.

Jim Newton 2020-09-27T20:17:52.206Z

Oh, I see. I thought there was a more clojurey way

(defmulti xyzzy (fn [x y] 42))
I see I can evaluate the following ((.dispatchFn xyzzy) 1 2) to get back 42.

Jim Newton 2020-09-27T20:18:27.206200Z

It would be nice if that were documented with defmulti

practicalli-john 2020-09-27T20:26:36.208900Z

Commas are whitespace in Clojure, so are used instead of spaces that would otherwise need to be managed on the command line. For example, https://github.com/practicalli/clojure-deps-edn/blob/live/deps.edn#L314

Jim Newton 2020-09-27T20:28:28.209100Z

I added https://clojuredocs.org/clojure.core/defmulti#example-5f70f927e4b0b1e3652d73c3. Did I use the correct description?

2020-09-27T20:55:17.209500Z

That looks correct to me. I wouldn't be surprised if it might be somewhat different for ClojureScript, but http://ClojureDocs.org tends to be focused on Clojure/JVM anyway.

zhuxun2 2020-09-27T21:06:02.209700Z

@jason358 Thanks! What if the param requires a space?

zhuxun2 2020-09-27T21:07:47.210800Z

@jr0cket What if the param requires a space? Here is an example I ran into: --error-format="::error file={{file}}::{{message}}"

practicalli-john 2020-09-28T09:28:25.249300Z

I was thinking :main-opts ["-m" "antq.core" '"--error-format=::error file={{file}}::{{message}}"'] I will try find time to look at this option for antq, I’m just using the default and piping it into an org file to give an interactive table

zhuxun2 2020-09-28T15:22:02.270600Z

@jr0cket Single quotes in edn do not "surround" they are syntactic sugar for (quote ...). If you meant :main-opts ["-m" "antq.core" "'--error-format=::error file={{file}}::{{message}}'"] then no, it does not work...

practicalli-john 2020-09-28T15:25:45.270900Z

I believe single quotes should work on the command line or in a script, but haven't had chance to test

zhuxun2 2020-09-28T16:39:45.274Z

@jr0cket Yes, it works in command line, but I was wondering if I could include it in the :main-opts. I mean for antq I can probably just make a Makefile or bash file and include the param, but I was wondering if :main-opts itself supports spaces or not. It seems not ...

zhuxun2 2020-09-27T21:08:10.211200Z

https://github.com/liquidz/antq

zhuxun2 2020-09-27T21:08:43.212100Z

In this case, --error-format is an arbitrary string that could have spaces them

jsn 2020-09-27T21:25:23.212200Z

I don't know. It looks like your problem is with shell, splitting at spaces, not with edn. So I'd suggest trying some standard shell escaping approaches (like \\ or "--param='{:a 1}'" )

practicalli-john 2020-09-27T23:06:58.212400Z

I believe strings are surrounded with single quotes. Does that help?