Fork me on GitHub
Drew Verlee05:12:21

Anyone have an experence report Here is my impression after reading the docs (not much i know 🙂 ) Comment blocks with eval notes are clear but not programmable (you can't auto automate running them). Tests are programmable but tend to be far (different files) and require extra wrapper code. This looks like the narrow road between the two:

(ns example
  (:require [hyperfiddle.rcf :refer [tests ! %]]))

  (inc 1) := 2

  {:a :b, :b [2 :b]} := {:a _, _ [2 _]}

  {:a :b, :b [2 :b]} := {:a ?b, ?b [2 ?b]}

  "unification on reference types"
  (def x (atom nil))
  {:a x, :b x} := {:a ?x, :b ?x}

  "REPL bindings work"
  (inc 1)
  := 2
  (dec *1)
  := 1

    "nested tests for convenience"
    1 := 1))
I'm curious what other people think though.


What you've posted of RCF reminds me a bit of Midje. Which, um. I kind of instantly dislike it 😞

Drew Verlee05:12:49

I havent' used midje so i don't know what that means to you, whats the intuition / overview ?


It's a DSL that is too far from Clojure's syntax so it makes my gears grind trying to read it. Intermixing strings for labels, expressions, results and then := where we'd see ;=> in a lot of written material for a comment indicating REPL output -- but := is a mutable assignment statement in some languages. And overloading _ -- which has is a well-defined convention in Clojure as a pattern matcher. The list goes on. It's just too "clever" for its own good. I just really don't like stuff like that. RCF basically has all the things I dislike about Midje.

Geoffrey Gaillard10:12:38

@seancorfield thank you for the time you took to explain why. I’d like to improve RCF, and it would help me a lot if we could disagree further 🙂 Let me address each point: 1) strings for labels. These are comments about the expression, the simplest way to capture the value to report it alongside the expression is a string. In (comment …) blocks, we use ;; label. Do you see a better way? Is it an incorrect assumption? 2) := I talked about it in my other message. It is true that := is a mutable assignment statement in other languages. But the argument also applies to =, ; and =>. RCF can’t (shouldn’t) redefine =, though it could use => to mimic (comment …) blocks. We decided => was more ambiguous then :=. We might be wrong. 3) overloading "_": _ is wildcard, as "ignore". The semantics are the same as in clojure. If it’s not, then it’s a bug and should be addressed. The list goes on please share if you’ve got the time :thumbsup:


i think for the example you got there, it all works well


but here is just a slightly more complicated test


(let [name       "Paul Bunyan"
      all-uppers (string/upper-case name)]
  (t/is (= name (name-case all-uppers)))


where in here do we put the :=


> The semantics are the same as in clojure. Technically _ doesn’t have any special semantics in clojure


but im okay with it being special in a macro

Geoffrey Gaillard15:12:21

> Technically _ doesn’t have any special semantics in clojure Right, I should have said same convention.

Geoffrey Gaillard15:12:40

  (let [name       "Paul Bunyan"
        all-uppers (string/upper-case name)]
    (= name (name-case all-uppers))) ;; => true
 (let [name       "Paul Bunyan"
       all-uppers (string/upper-case name)]
   (= name (name-case all-uppers))) := true
 (let [name       "Paul Bunyan"
       all-uppers (string/upper-case name)]
   name := (name-case all-uppers)


okay so thats confusing for me


is it reaching in to the let?


does it reach into all macros?


(let [name "avc"
      assertion name := name]
  1 := 1)

Drew Verlee16:12:13

i read := as equals the same way i read the comment convention of ;;=>, So this convention has a very natural appeal for me because i feel i can just switch my comment blocks to test blocks and my => to := and be done with it. The theoretical issue is whether i would put my time into RCF or a quick spec based solution like But from a practical perspective i'm not going to put much energy into which testing framework my team uses, as i would rather put the effort into design.

Geoffrey Gaillard16:12:54

This is an interesting example. It is not valid clojure code. If it doesn’t run at the REPL, it shouldn’t run as an RCF form. The let body is valid clojure code. > does it reach into all macros? It rewrites before macroexpansion, like t/is. Another example is [1 := 1]. This is just a vector. [(do 1 := 1)] on the other hand, will evaluate to [1], and RCF should assert. It’s missing. I’m on my way to open an issue. Thank you!

Geoffrey Gaillard16:12:33

> from a practical perspective i'm not going to put much energy into which testing framework my team uses, as i would rather put the effort into design. 💯


I think any macro that introduces a DSL is going to induce very subjective reactions. Why it reminds me of Midje:

;; RCF:
  "this is a test"
  (+ 1 2 3 4) := 10
  (* 1 2 3 4) := 24))
;; Midje
  "this is a test"
  (+ 1 2 3 4) => 10
  (* 1 2 3 4) => 24))


You don't have to squint too much to see that.


I hadn't even read much about RCF because of that apparently similarly and my gut reaction to Midje. Seeing you say you also dislike Midje for the same reasons (as me) but you like RCF made me take a second look and there were a couple of things I didn't realize: a) tests expands to nothing by default, just like comment b) tests can expanded to actual deftest expressions via a JVM option c) tests can be run on load (or run on eval-block) if you dynamically enable them for REPL usage


I use comment blocks a lot for code setup and ad hoc "tests" to illustrate how functions work and having a way for those to actually be executable with some sort of inline check against the stated result would certainly be valuable.


I think I had considered primarily a "testing framework" in the same way Cognitect's transcriptor is -- and I don't like that for other reasons (the REPL session -> file of tests -> custom loader/runner).


I am going to try RCF and see what I think of it in practice as opposed to just the look of it and my gut reaction to it.


I am definitely going to have a hard time with := because my first programming language (at school) was Algol 60 and I spent a lot of time with Algol 68 at university and variable := expression is Algol's assignment statement. I would get a lot less cognitive dissonance with => which looks more like Clojure's REPL prompt and it closer to what I already have in READMEs and documentation (and even in some of my existing comment blocks.


I have some follow-on comments and questions but I'll ask those in #testing (for now).

Geoffrey Gaillard18:12:06

> You don't have to squint too much to see that. Definitely. I consider the visual resemblance with Midje to be an issue. > I would get a lot less cognitive dissonance with => which looks more like Clojure's REPL prompt and it closer to what I already have in READMEs and documentation (and even in some of my existing comment blocks. I agree with your point of view. This is something to consider. Also, @seancorfield please know that we do not consider RCF to be done or to be "the truth". It just fits our use case for now.

Dustin Getz20:12:31

(let [name "avc"
      assertion name := name]
  1 := 1)
@U3JH98J4R Agree that handling deep := by rewriting the ast is conceptually problematic and muddy, it is kind of nice in practice so we may try to do something more rigorous, please open an issue if you have any ideas It can also just be rewritten to (def) which is what you'd do at the REPL. See for a cool idea we're considering to make unification do something useful and notebook-like @seancorfield we use := over => because keywords highlight better in editors with zero config RCF's best feature is the async support, afaik there is no other good way to work with async at the REPL (and this is highly problematic for frontend development where the status quo is hot reload the page and test app live - that's just not ok)


@U09K620SG Interesting point about keyword vs symbol in editors. I guess I'd still lean to :=> than := even with that consideration.


I don't use core.async enough to comment on RCF in that area (and I do zero cljs work right now so those problems don't exist for my workflow 🙂 )

Geoffrey Gaillard10:12:44

Maintainer of RCF here 👋 Thank you for trying it. Feedback is welcome! We use it extensively, but being biased I don’t qualify as "other people", so I’ll refrain myself from stating the obvious "yes it works for us". @seancorfield said RCF reminds him a bit of Midje. I don’t like Midje for the very same reasons. Thank you for sharing what you feel about it, this is highly valuable. RCF is different, it’s a tool for communication. It is not meant at all to replace clojure.test or be an alternative to it. I would consider rewriting tests to RCF or migrate from clojure.test to RCF to be yak shaving. We want to talk about ideas, precisely, with examples, without any visual or conceptual noise. We want a tight feedback loop, to point at stuff, and focus on the essence of a problem. We do that all day long on Zoom/Discord, clojure.test and Midje are not a good fit. It turns out Clojure developers naturally converged to this practice with comment blocks, because it just looks like a capture of the REPL:

  ;; 1 evaluates to 1
  1 ;; => 1)
How do you run it? How do you keep it consistent? How do you find which expression do not match your expectations? And since it asserts something, why not integrate it to your tests? YMMV. We want all of that, and by introducing the smallest amount of changes: 1. tests behave like comment when disabled, evaluate sequentially when enabled, mimicking the REPL. 2. 1 ;; => 1 would be (is (= 1 1)) in clojure.test. The essence is equality, but = is clojure.core/=, the closest thing is :=. 3. to ignore something in Clojure is _, same in RCF. 4. infix vs prefix is opinionated. Not by us, but by thousands of (comment …) blocks in the wild, and because tooling made it so. It’s not that because everyone is doing it that it must be good, but it’s intuitive, and we want intuitiveness. @drewverlee shared an example of RCF just above, and we could spend days talking about concepts, pointing at stuff and disagree, without having to change a single line, scroll, or focus on the unnecessary. Because it’s about communication. Everything I said could be challenged, and I’d like to debate about it.

Drew Verlee16:12:30

I think it's a great addition, i suspect it will see some friction as it's likely not worth having to many ingredients in the stew (even if they are all good) but over time this idea, or another will become more common.


any suggestions for tooling that can turn text markdown into pretty uml like graphs or swimlane graphs ?


i want to keep process flows in repository next to code and i want it to be diffable just like code ... but yet to have nice renderings of it when needed ...


and it should run off line without sending my business flows to third party servers for rendering 🙂


Would PlantUML be okay?


The language to describe the diagrams is all textual, and it's very easy to run a local plantuml server that does the rendering


At work, we are experimenting with using Antora to do all the document generation for us (which lives at the project/repo level). It uses Asciidoc (which I prefer over md). Maybe there might be a md equivalent.


will look into plantuml ... as for the text source, don't really care for dialects, as long as humans can write it and understand it


I did a small thing wich lets you edit an "doc.edn" file which can then generate an html document with plantuml (or dot) diagrams in it...


Purely for amusement / horror value. Ignore the Twitter commentary. This shows how 40% of Maven Central requests for log4j jar files are for known insecure versions. It’s an interesting thought exercise to explore how one could/should/shouldn't enable problem and solution when a central distribution point exists.


There are also different patching mitigations that exist (removing class files, method patching via a Java agent) that show up as downloading the effected versions

👍 1

A super good point. (But also reminding myself that most of the bell curve usually doesn't work like that. 😂😂)


If I was in ops at a large org, I very likely would have chosen the java agent route, since it would allow for patching all java software the same way without waiting for releases

🔥 1
Michael W21:12:54

If anyone needs help mitigating log4shell I am available.

❤️ 1

Im sure you’re good, but i dont think you can beat

Michael W21:12:44

Is this a joke I don't get or some sort of spam?


joke you don’t get