Fork me on GitHub
#beginners
<
2020-02-18
>
bartuka01: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

bartuka01: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

@UBSREKQ5Q 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

Piotr Brzeziński09: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.

hindol10:02:51

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

Bobbi Towers10:02:05

Looks like you could accomplish that with a lookahead:

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

👍 4
hindol10:02:35

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

Piotr Brzeziński10:02:50

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

Frederik14: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:45

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

Alex Miller (Clojure team)15:02:30

println auto flushes, but print does not

Frederik16: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 🙂

Alex Miller (Clojure team)16:02:10

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

zlrth21: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

zlrth21: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 ?

zlrth21: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

@U0HJ4RAGY 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...

zlrth21: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...

zlrth21: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

zlrth21: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.

zlrth22: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).

zlrth22: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.

zlrth22: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.

👍 4
seancorfield22:02:53

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

zlrth22: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?

zlrth22: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

zlrth22:02:00

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

hindol05: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.

hindol05: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 @UJRDALZA5

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

👍 4
hindol05: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

@UJRDALZA5 The REPL is your friend here 🙂

Michael Stokley21: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?

Michael Stokley21: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

Michael Stokley22: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))))

Michael Stokley22: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?

Michael Stokley22:02:34

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

Michael Stokley22:02:45

a way to validate my code as i develop it

Michael Stokley22:02:07

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

Michael Stokley22: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.

mloughlin22: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))

Michael Stokley22:02:15

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

Michael Stokley23: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`)?