Fork me on GitHub
#clojure
<
2020-08-18
>
introom03:08:31

just to confirm, smt in clojure (alter) only offers snapshot isolation, and still suffers write skew ?

noisesmith03:08:17

do you mean stm?

noisesmith03:08:05

the correct way to use stm is to write code that uses the snapshot value meaningfully (except the null case of unconditional rewrite...), and the retry mechanism plus ref capture will help that function keep things coherent

noisesmith03:08:42

that won't save you from the sort of error your function could make in a single thread, but makes preventing concurrency errors much easier

noisesmith03:08:59

@i to directly answer your question, the retry mechanism of transactions means write-skew doesnt' happen if you use it correctly

alexmiller03:08:03

You can use ‘ensure‘ on reads to prevent write skew if needed

noisesmith03:08:34

oh yeah, I should have name checked that instead of vaguely mentioning "ref capture", thanks

introom03:08:17

yup. ensure. I forgot that. so that indicates alter re-tries only if the ref it refers to have been updated, not the world state (all refs in a transaction).

alexmiller04:08:53

Only if the refs tracked in a transaction, which is all writes and reads you mark to include with ensure

noisesmith03:08:27

iirc the classic ants demo from Rich Hickey demonstrates that write-skew doesn't happen can be effectively prevented

alexmiller03:08:11

write-skew can definitely happen

alexmiller04:08:41

ensure prevents it but reduces concurrency, but have control to choose

noisesmith05:08:09

is rand-nth not working on sets intentional or accidental? if intentional what's the reasoning?

noisesmith05:08:16

I guess "nth" is in the name, but since it's point is to not care about the order, erroring on sets seems like a misfeature

Chandan13:08:33

how can we use ns meta to run tests using kaocha for example if I have (ns ^:foo file1-test) (ns ^:foo file2-test) how can I run just both of them using the ns meta There is a :focus-meta config we can specify in tests.edn but the problem I’m facing is it runs only the first match.

val_waeselynck13:08:54

Has anyone got an idea what on Earth is going on here?

(require '[co.ytems.model.money-amount])
=> nil

(require '[co.ytems.model.money-amount :as money])
Syntax error compiling at (/private/var/folders/62/3v4gckg15t706bjzkjw155n00000gq/T/form-init6286340574717549821.clj:1:1).
namespace 'co.ytems.model.money-amount' not found

val_waeselynck13:08:58

OK, looks like lein clean appeased the evil spirits.

noisesmith13:08:03

any chance you edited the file and it no longer declares the same ns symbol in the declaration as the one you required?

val_waeselynck13:08:44

No that wasn't it.

val_waeselynck13:08:29

I'm still quite at a loss as to what happened, because even though lein clean appears to have solved it, there's still quite a lot of garbage in target/

noisesmith13:08:46

I've avoided learning too much about these issues by not using aot or gen-class

noisesmith13:08:20

it's a corner of the language / tooling that I find wastes my time and energy, ymmv, it's not hard to ensure you never need aot or gen class then you rule out these sorts of errors

val_waeselynck13:08:31

I agree! Not necessarily up to me unfortunately 🙂

val_waeselynck13:08:37

Thanks for the advice

noisesmith13:08:08

there's also the technique of using a java shim - if your consumer is a java framework or app that needs a specific class / interface to load, you can make a very small java file that uses the Clojure api to load up your implementation eg. this is enough to use clojure via the jsvc service without gen-class or aot: https://github.com/noisesmith/clj-jsvc-adapter/blob/master/src/java/org/noisesmith/Cljsvc.java

noisesmith13:08:47

it uses convention over configuration (provide an ns name via system property, implement a series of "magic" functions) to be as minimal and streamlined as possible but still reusable

millettjon17:08:13

Is there an idiom for coercing a val to a collection if a collection was not passed?I'm using this at the moment:

noisesmith17:08:07

this should really be a FAQ, but the tl;dr version is that it intentionally doesn't exist because it's an antipattern to accept both colls and individual items in the same code path

noisesmith17:08:26

the best solution is to never accept colls and individual items in the same code path

noisesmith17:08:23

if some API you have to use forces you to do so, do this in exactly one dedicated API adaptor function, not a reusable converter - stop the duality in its tracks before it hits your actual codebase, it causes rippling complexity and mess

noisesmith17:08:40

every seq? is also a coll? and many data types can be (and usually should be) treated as collections - there's seqable? to check for them, and seq if you need to explicitly convert (but most collection functions already call seq for you)

noisesmith17:08:11

haha, that makes my rant redundant, thanks

Mark Gerard17:08:19

I was just perusing that article. Now I have to pay attention. thanks @U0FTV149X

millettjon17:08:00

(cond (coll? x) x (seq? x) x :default [x]))

hiredman17:08:46

coll? is true for everything seq? is true for

hiredman17:08:35

:else is the most common constant used for a else case in a cond

millettjon17:08:29

Thanks. I got tripped up since (coll? (seq [])) is false. But that is since (seq []) is nil not a seq. I was hoping for something simpler like (into [] x) but into doesn't support that usage.

Markus Kiili17:08:47

How about just (if (coll? x) x [x]) ?

millettjon18:08:30

Yep. I switched to that from the (cond. Now thinking about a more general into: (into* coll & args) that handles both collections and values.

noisesmith17:08:24

as mentioned in the thread above, there's also seqable? - depending on how you would treat eg. strings, hash-maps, arrays

noisesmith17:08:17

org.noisesmith.hammurabi.hold-my-beer=> (pprint (map (juxt identity seqable?) [nil [] "" () #
{} {} (byte-array 10) 1 (reify Object) (fn [])]))
([nil true]
 [[] true]
 ["" true]
 [() true]
 [#{} true]
 [{} true]
 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] true]
 [1 false]
 [#object[org.noisesmith.hammurabi.hold_my_beer$eval15945$reify__15946 0x130a3d99 "org.noises
[email protected]"]
  false]
 [#object[org.noisesmith.hammurabi.hold_my_beer$eval15945$fn__15948 0x22895cca "org.noisesmit
[email protected]"]
  false])
nil

Grant Isom17:08:26

Okay so I have this method that applies highlights to hiccup and cannot figure out how to get the highlighted vector to not be in a seq

(defn find-body-text
  [hiccup rule]
  (into []
        (for [element hiccup]
                (cond
                  (string? element) (highlight-text element (:regex rule) (:color rule))
                  (vector? element) (find-body-text element rule)
                  (some? element) element))))

Call=>
(find-body-text (labelmaker.views/playground) {:regex #"quick" :color "#333"})

Returns =>
[:div
 [:span.p-3]
 [:p ("The " [:mark {:style {:background-color "#333"}} "quick"] " brown fox jumps over the lazy dog")]]

Grant Isom17:08:08

I feel like I am missing something on getting the highlighted text from ("The" ...) to just items in the outer vector.

noisesmith17:08:59

that should blow up and tell you that "The" isn't a function

Grant Isom17:08:57

Sorry edited to show the defn, call, and return

Grant Isom18:08:40

I want the highlight-text to return just "The " [:mark {:style {:background-color "#333"}} "quick"] " brown fox jumps over the lazy dog" instead of ("The " [:mark {:style {:background-color "#333"}} "quick"] " brown fox jumps over the lazy dog")

noisesmith18:08:54

what does highlight-text do?

noisesmith18:08:08

you can't return multiple items without some collection around them

Grant Isom18:08:38

Applies a regex to some text string and returns a vector of strings and hiccup :mark items

noisesmith18:08:39

if you don't want it to be a list, you can use vec to make it a vector instead, which hiccup should do the right thing with here

noisesmith18:08:49

that's clearly not a vector of strings

noisesmith18:08:44

perhaps you are using the result of a regex split that is in a list or lazy-seq? anyway, vec in the caller or in the function itself would both suffice surely

Grant Isom18:08:28

The other two cond options only return 1 item which I think is my issue, is there some way to pull each item out into the parent vector?

isak18:08:27

Yea, you can use (into [:p] children)

Grant Isom18:08:48

@isak my last case was just returning the keywords, but seems like I need to treat them different and start each new vector after seeing one.