Fork me on GitHub
#beginners
<
2020-02-18
>
iagwanderson01:02:08

which is the best approach to provide a single namespace with several interfaces (`defmulti` definitions) to a client-user require from and have all the implementations already being loaded. I was using potemkin import-vars (https://github.com/ztellman/potemkin) and a combination of at least 3 namespaces. i) the one where import-varsexposed the interfaces and I required all implementations, ii) the namespace with de defmulti definitions and iii) all the implementations of the interfaces

iagwanderson01:02:28

however I need this approach for a cljc project. For now, this library does not have support for it.

andy.fingerhut02:02:24

There might be more people with experience developing code that works in both Clojure and ClojureScript in the #clojurescript channel, who may know an answer for your question.

pithyless07:02:32

@ There are a couple of versions of a cljs-import-vars floating around github. If it's just a question of a CLJC version of potemkin/import-vars you can try to do something like: https://gist.github.com/pithyless/20939406045e2bb2ccd8a64075b458cb

peb.brzezinski09:02:17

Hey 🙂. I’m working on some katas and have ran into a problem I’m not sure how to approach. Say I have such string as an input -> "100001X0X1100X1X0" . I’d like to split it so I have something like ["100001" "X0X" "1100" "X1X" "0"] as a result. I thought I could use str/split but it looks like it only splits by the first ocurence (regex I used is #"X.*X") so I think I should probably reduce over that string somehow? Not sure, maybe there’s an easier method. Any help appreciated.

hindol.adhya10:02:51

X.*X can potentially capture more than intended also. I suggest X[^X]+X.

porkostomus10:02:05

Looks like you could accomplish that with a lookahead:

user=> (str/split "100001X0X1100X1X0" #"(?=X)")
["100001" "X0" "X1100" "X1" "X0"]

hindol.adhya10:02:35

To your original question, did you look at re-seq?

peb.brzezinski10:02:50

I did not. I will check it out, thanks to both of you!

frederikdieleman14:02:33

Hi! Small java jar question: I made small interactive game in the terminal. When I do "lein run" or run the code in a repl, the printing of the game happens like expected (linebreaks, some colours, etc). When compile everything to a standalone jar and then run "java -jar name-of-the-jar.jar", the program still runs, but none of the string formatting works. Are there typical gotchas when compiling into a standalone jar that can change the behaviour of your output? Happy to give more info if needed, but maybe there's simple things that I didn't realise 🙂

borkdude15:02:29

@frederikdieleman Are you using print?

borkdude15:02:45

You might need to call flush afterwards or especially at the end of your program before it exits.

alexmiller15:02:30

println auto flushes, but print does not

frederikdieleman16:02:18

Using println, any good approaches to try to debug this? No prior experience with Java, so sorry if my questions are very beginner-ish 🙂

alexmiller16:02:10

"none of the string formatting works" is not a helpful description - making that more precise would be a good start

mfm21:02:10

goldplating question: is there a built-in function or idiom that’s nicer than:

(when (#{"foo"} a) "bar")
;; returns "bar" or nil
i often need to test for something, but then return something else

mfm21:02:00

something like: ($fn test val return-value) and maybe i’m missing an obvious idiom

andy.fingerhut21:02:47

Where in your expression test is a function of exactly 1 argument, which is val ?

mfm21:02:12

($fn pred val return-value)

andy.fingerhut21:02:18

Because if and when are exactly what you want if the pattern is ($something predicate return-value)

andy.fingerhut21:02:35

and that works for a predicate that takes an arbitrary number of args.

andy.fingerhut21:02:05

well, I probably should have written ($something (predicate arg1 ...) return-value)

andy.fingerhut21:02:09

but you already know about when and if . What you are asking for sounds like a dead simple one-line function that you can define, and I am not aware of its existing in Clojure's core library. There might be something equivalent already in a 'utilities' library like medley, plumbing, or useful

andy.fingerhut21:02:05

(when (pred val) ret-val) and ($fn pred val ret-val) differ by exactly two parentheses, and every slightly experienced Clojure programmer knows what if and when do

seancorfield21:02:13

@ I'm confused about what you're trying to do. Is ret-val independent of val?

seancorfield21:02:55

I can't see how anything could be simpler than (when (pred val) ret-val) so I think I'm missing something about your question...

mfm21:02:56

i find it a little harder to read (when test val) than one of the higher order functions like filter or keep because the norms are much more tightly defined around filter and keep than when. they operate on sequences, they produce results according to their semantics, etc. whereas with when, simply because i have to inspect the function application, i’m slower to read it wwhereas

seancorfield21:02:07

Like Andy, I'm struggling to see a "simpler" construct here...

mfm21:02:41

> is ret-val independent of val? yes. i agree that you can’t reduce the number of semantic units very much.

andy.fingerhut21:02:05

When you see a call to filter where the first argument is a function you are unfamiliar with, you need to learn something about it to understand the overall behavior, too, yes? Not sure how that is different than when here

mfm21:02:07

it’s certainly possible that this is a “me problem.” filter tells you what kind of results will be returned. when (the lexeme) tells you nothing. (granted, until you look at the body expression

andy.fingerhut22:02:14

The way I think of it, filter returns a sequence that is a sub-sequence of its second argument. A sequence "of what"? Whatever the input sequence is a sequence of.

andy.fingerhut22:02:53

(when condition expr1) returns whatever expr1 evaluates to, only if the expression condition evaluates to logical true. What type of thing? Whatever the type of expr1 is.

mfm22:02:26

even that filter returns subsequences is helpful

andy.fingerhut22:02:26

The only additional 'regularity' I can think of from filter is that it is sequence in, sequence out, whereas when doesn't have that.

andy.fingerhut22:02:42

Sure, but subsequence "of what"? Whatever the input sequence has in it. It could be a sequence of integers, lists, maps, sets, mutable objects, whatever, all jumbled together. filter doesn't care -- it takes them all.

andy.fingerhut22:02:57

When takes everything, too, without a restriction that it is a sequence of anything.

andy.fingerhut22:02:23

Sorry, not trying to blast you with text here. I only say these things in case it uncovers any misunderstanding of what when is actually doing (which isn't a whole lot, admittedly).

mfm22:02:58

i agree with everything you’re saying, and i believe that the following is compatible with what we are both saying: most clojure functions (haven’t thought about macros) suggest more narrowly what they’ll return than when. i have in mind just basic stuff: +, filter, merge, etc.

mfm22:02:26

totally may be in fact a “me problem”, but even though i agree that there aren’t many semantic units in (when (test val) 'thing), i still disprefer it to an imagined higher order function. agreed that i could write it.

andy.fingerhut22:02:59

Understood. Yes, when and if are pretty general beasts that can take just about anything, and still return a well-defined value, whereas most other Clojure functions have a more constrained "shape" to what they accept and return.

seancorfield22:02:53

@ If you saw (if (test val) 'thing) instead, would that seem more readable to you?

mfm22:02:48

no (because i’d still have to look at 'thing ) i do appreciate both of you engaging me on this, my previous-previous message is my “actual” problem

seancorfield22:02:51

Interesting. So what about other languages? How is (if (test val) 'thing) in Clojure different to if ( test( val ) ) return 'thing; in some other language?

mfm22:02:55

to me, the salient difference is how suggestive filter is, compared to for loops in other languages. i think other languages and clojure are the same as regards if

mfm22:02:00

in for (stuff) body-exprs in other languages, for tells you not much

hindol.adhya05:02:49

I am wondering if some will be useful here. But you will need to create a fn with the pred and ret-val baked in, i.e. you are pushing the complexity outside. That is arguably the opposite of simpler.

hindol.adhya05:02:28

(defn f [x] (when (pred x) ret-val)

(some f val)

seancorfield05:02:09

some expects a collection, not a value, so that won't work @

seancorfield05:02:12

You'd have to do (some f [val]) -- and it won't work if ret-val is false.

seancorfield05:02:01

user=> (defn f [x] (when (even? x) false))
#'user/f
user=> (some f [2])
nil

hindol.adhya05:02:16

"won't work if ret-val is false" - that's something I did not know. Thanks for pointing it out. And today my brain is not functioning as it should. Had to attend a training in a different timezone, so pretty much awake through the night. I should stop commenting, 🤐

seancorfield05:02:46

Consider

user=> (some identity [false])
nil
user=> (some? false)
true
some? and some do not treat false the same way.

seancorfield05:02:46

@ The REPL is your friend here 🙂

michael74021:02:19

how can i define a spec for a map but distinguish between the name of the spec and the names of the keys i expect to find in the map? the map has generic sounding keys and i'd rather use more specific names when i register the spec

seancorfield21:02:43

@michael740 Can you provide an example?

michael74021:02:19

what i'd like to do is this:

(s/def ::twitter-access-token-response-body (s/keys :req-un [::twitter-access-token]))
but the actual response i get back has a field called simply "body"

seancorfield21:02:20

(s/def :twitter-access-token/body ...)
(s/def ::twitter-access-token-response-body (s/keys :req-un [:twitter-access-token/body]))

seancorfield21:02:02

The key in the data will be :body but its spec will be :twitter-access-token/body

michael74021:02:14

thanks @seancorfield !

michael74022:02:10

i find myself repeating the name of the parameter when i do pre-checks, like this

(defn person-name
  [person]
  (let [p (s/assert ::person person)]
    (str (::first-name p) " " (::last-name p))))

michael74022:02:00

person is the name for the parameter and the spec. is there a way to imply that, i.e. not repeat the parameter name?

seancorfield22:02:58

It depends what you're really trying to do. Do you want the check in production? Just for testing? Are you validating input data and doing anything constructive for invalid data?

michael74022:02:34

right now i'm just using it like i'd use static type checking

michael74022:02:45

a way to validate my code as i develop it

michael74022:02:07

maybe that's not a typical use of spec or contract-libraries in general

michael74022:02:47

it's not that important - it just struck me that with destructing, the syntax will sometimes allow you to be brief/implicit about repeated names. i wondered if the same might be true of spec

seancorfield22:02:33

If you're doing this just for dev/test, you probably want to instrument the functions and let the system take care of checking:

(s/def ::person ,,,)

(s/fdef person-name :args (s/cat :person ::person))
(defn person-name
  [person]
  (str (::first-name person) " " (::last-name person)))

(st/instrument) ; clojure.spec.test.alpha/instrument

seancorfield22:02:09

Then if you call person-name with something that doesn't conform to ::person, the instrumentation system will throw the assertion failure.

seancorfield22:02:51

> right now i'm just using it like i'd use static type checking Bear in mind that Spec is not a type system and Spec'ing "everything" is usually the wrong approach.

michael.e.loughlin22:02:51

This blog post helped me get started using spec at least a little bit. Now I have fdefs for major functions and turn on instrumentation during development and try and keep something like the following at the bottom of my files for dev-time testing:

(comment (st/instrument)
         (def blah (init {:foo :bar})
         (baz blah)
         (st/unstrument))

michael74022:02:15

interesting. i'll have to think about this, thank you for sharing it.

michael74023:02:26

(s/def ::api-key string?)
(s/def ::access-token string?)
(s/def ::consumer-secret string?)
(s/def ::oauth-token-string string?)
(s/def ::secrets (s/keys :req-un [::api-key
                                  ::access-token
                                  ::consumer-secret
                                  ::oauth-token-secret]))

(s/fdef get-recent-tweets
  :args (s/cat :user-id int? :secrets ::secrets))
(defn get-recent-tweets [user-id secrets]
so, i really like how s/fdef lets you "inline" a lot of the specs. I have no need for a named user-id spec; can i do the same for the map (`secrets`)?