Fork me on GitHub
#clojure
<
2022-04-15
>
Nom Nom Mousse05:04:46

I have a folder of babashka scripts in my project folder: ≤project>/bb Is there a way to access them from my project? I guess only stuff in the classpath (`<project>/src/...`) is visible to the project?

Nom Nom Mousse05:04:09

Access them without knowing the full path that is.

phronmophobic07:04:55

If you're trying to load them as code, you can add them to your paths. The paths are under https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L311 for lein and :paths for deps.edn. If you're just trying to read their contents, then the current working directory is typically the project dir, so you can load them using something like (slurp "bb/filename.ext")

👍 1
p-himik08:04:46

Note that the latter will work only if you run your project from sources - it won't work if it's packed in a jar.

Nom Nom Mousse09:04:17

That was going to be my next question! 🔮 I've never made an überjar before.

borkdude10:04:02

@U0232JK38BZ Maybe you can give a bit more context: are you reading bb scripts from the JVM and why?

Nom Nom Mousse10:04:00

I have a program that runs scripts. I want to include some predefined scripts in my program. Of course, the predefined scripts could just be implemented with regular compiled Clojure code since they are predefined.

pinkfrog10:04:39

I’ve a macro named macro-a defined in (ns a) , now I want to expose that name in another namespace ns b . What’s the recommended approach?

p-himik10:04:41

No differences from other vars.

p-himik10:04:06

Or by expose, do you mean that you want for it to be available via b and not just used in b?

pinkfrog10:04:03

be exposed from b.

p-himik10:04:02

It's available in its API as import-vars although in general people don't seem to be in favor of that technique. Personally, I would probably just use the macro via a.

pinkfrog10:04:59

It uses some hidden gens: setMacro

p-himik10:04:54

Not hidden, but internal, yeah. Why do you not want to use the macro simply via a, without exposing it via b?

pinkfrog10:04:44

Wanna make things more organized so only expose names from a single public ns

p-himik10:04:12

Alright, in this case - why is the macro defined in some other ns? :) If something belongs together - just put it together. And if the implementation takes a lot of space - just move the implementation to separate namespaces. Clojure does it as well, although via a much older technique - by using load in combination with in-ns. But I believe it's been said that if the core team were implementing that functionality nowadays, they would've used a different approach. So you can have stuff like

(ns b
  (:require [a]))

(defmacro m []
  (a/m-impl))
where a/m-impl is a function that implements the macro. Or another macro, but the usage would be slightly different.

pinkfrog10:04:09

Right. That is another approach.

noisesmith14:04:57

this kind of indirection is extremely annoying when trying to read code or debug

👍 1
p-himik14:04:15

By "this" you mean Potemkin or "impl in a separate ns"?

noisesmith14:04:04

impl in a separate ns, potemkin being one way to do it

noisesmith14:04:22

perhaps your IDE makes it trivial, but I'd like to not need an IDE

noisesmith14:04:41

(I've gotten away with it for a while...)

p-himik14:04:29

But that's a problem with every single require then, no? E.g. you need to debug a specific usage of clojure.core/into from your namespace. That's already indirection.

noisesmith14:04:19

no, require is simple - I go find the required file, it's the extra indirection (that rarely limits itself to one layer once it starts) that gets tedious

p-himik14:04:13

Ah, so it's N vs N+M, alright. :)

noisesmith14:04:44

and don't get me started on trying to figure out which file you put a multimethod extension in...

noisesmith14:04:37

it's not a demand, but a polite request to minimize this style of spreading out codebases - there's a reason clojure's so much easier to read than java or ruby, and I'd like our conventional style to keep it that way

p-himik14:04:48

I get it, although I don't get the desire to shun away an IDE. I'd definitely find it incomparably more annoying to not have IDE features than to have to navigate an extra file with a text editor.

noisesmith14:04:28

I wasted too many days that should have been productive on stupid cider bugs

noisesmith14:04:13

also, I was working as a mentor on my team to programmers that were new to clojure, and found it extremely useful to be able to give advice and debugging hints that didn't require they use my setup

noisesmith14:04:56

so I learned how to do everything with the clojure.repl namespace, and the various introspection features that come with the language

noisesmith14:04:45

I admit it takes a little longer, but if the time it takes to get code onto the screen is your bottleneck I have severe doubts about your code quality

p-himik14:04:19

Alright, so it's not IDE in general by Cider - I don't have an opinion there since I've never used it. But just the simplest "navigate to definition" already makes so many things incomparably easier and streamlined that I'd definitely never consider going full on IDE-less. And if there's ever a (albeit strange) choice between "make something easier for any IDE users" and "make something easier for plain editor users", I'd definitely go for the former. As long as it's not tied to some specific IDE, of course.

noisesmith14:04:09

clojure.repl/source shows the source and meta shows the location, and any useful editor can open the jar file pointed to in meta

noisesmith14:04:52

and it is IDE in general - I saw no evidence that cursive users were wasting less time to broken config or scrambled setups

noisesmith14:04:23

it's a difference in speed, not capability

noisesmith14:04:53

I'm using the same info the IDE uses, clojure makes it easy to access

p-himik14:04:14

Right, and all I have to do is Ctrl+B. :) That's the only reason I'm not migrating from Cursive to Calva - the latter can't seamlessly navigate from Clojure code into Java code. I read a lot of code - both my own and thirdparty, - so I have to navigate it a lot. Having to constantly type in commands for that would definitely put me off from exploration.

noisesmith14:04:19

I must be different, I read code slowly enough that my time is not dominated by typing in file / jar names or finding javadoc

noisesmith14:04:29

I spend most of that time reading

noisesmith14:04:01

or perhaps I'm stunting myself and I could be doing a lot more with an IDE?

pinkfrog14:04:02

> That’s the only reason I’m not migrating from Cursive to Calva - the latter can’t seamlessly navigate from Clojure code into Java code. Totally concur. How do you solve the js issue? Does cursive support jump into js (node module) sources?

p-himik14:04:23

I see. Yeah, I read code significantly faster than natural languages, including my native one. At least, when it comes to reasonably good code in reasonable languages.

p-himik14:04:02

> How do you solve the js issue? Does cursive support jump into js (node module) sources? I keep a stiff upper lip and do it manually. It's a pain.

noisesmith14:04:43

this is getting philosophical now, but I trust reading quickly in natural language (outside domains like law...) because what the statement means is determined by a human consensus and human norms I do not trust reading code quickly because while writer intent will be shaped by human norms, what the code does is determined by something much less forgiving

p-himik14:04:50

Somewhat related note - I absolutely despise, perhaps beyond any reason, long local names. E.g. when instead of

(let [c (make-collection-of-all-my-things)]
  (do-stuff c))
people write
const collectionOfAllMyThings = makeCollectionOfAllMyThings();
doStuff(collectionOfAllMyThings);
That makes code reading so much harder. It's like climbing stairs while putting both of your feet on one stair at a time.

noisesmith14:04:26

100% agreed - I am trying to remember where I heard this idea - maybe Rob Pike? - the larger the scope of a variable, the more important it is that it be fully descriptive. so if it's local to a two line funciton, a name like x or the classic i might suffice. if it escapes the current file, you need a proper sentence of a name

p-himik14:04:24

We might easily have different mental processes going on. It's the exact opposite for me. I read text in natural language slowly exactly because I have to consider all the norms that I know. And with code, I know what map does, I know what into does, I know what (into coll (map ...) ...) does - immediately, without having to think that "map" also means a model of a territory and stuff like that.

p-himik14:04:20

> the larger the scope of a variable, the more important it is that it be fully descriptive Something like that yeah - I remember it from reading some paper on cognitive load but I wouldn't be able to recall which one exactly it was.

noisesmith14:04:38

but I'm not reading for developer intent alone, I'm also reading for what the code does, and most importantly I'm looking for where that diverges from developer intent. so I need to keep track of the common misconceptions that people have about what map does (in fact I have, effectively a relative "red flag" score for every function in clojure.core, and map is higher than average...)

noisesmith14:04:04

where 1.0 red flag is for things like flatten and pmap

p-himik14:04:31

That makes sense. Still, it's a very robust and rigid set of things relative to what happens in a natural language.

p-himik14:04:47

And I concede - I might be overthinking reading in a natural language. :) But that's not something I'd want to change. I make enough mistakes with reading plain text as it is - speeding it up would only make things worse.

didibus21:04:27

What you can do is this:

(ns a)

(defn macro-a-impl [a b]
 ...)

(ns b)

(defmacro macro-a [a b]
  (b/macro-a-impl a b))

emccue12:04:37

Does anyone have a snippet that will "find all files on the classpath matching some pattern or named in a certain way" Trying to find all the config.edn and schema.edn files on the classpath to merge them

p-himik12:04:35

So you'd want to find both config.edn and some/dir/config.edn?

p-himik13:04:52

There's https://github.com/weavejester/resauce And if you need just config.edn, then it has resources. But if you need to take directories into account, then it has resource-dir which you could use as a building block. It's probably worth using given that the distinction between files and jars is annoying. Unless there's a Java-only easy solution to this which I couldn't find.

Søren Sjørup15:04:07

Am I alone in finding regex difficult to read? Instead of something like #"\"(?:\\.|[^\\\"])*\"?" I would prefer something much more verbose:

[:concat
 \"
 [:star
  [:union
   [:concat \\ :any]
   [:negated-character-class \\ \"]]]
 [:optional \"]]
Is there a library that does something like that?

2
1
Søren Sjørup15:04:11

Thank you both for the quick response! 🙂

Noah Bogart15:04:35

you're welcome!

noisesmith17:04:37

java regex (and therefore clojure regex) supports free-spacing mode, a multi line format with embedded comments:

(def re1
   #"\"(?:\\.|[^\\\"])*\"?" )

(def re2
   #"(?x)\"               # just  a quote
         (?:\\. |         # \\ followed by any single token OR
          [^\\\"])        # something that isn't in \\ or \"
         *\"?             # optionally a final \"
   ")
(ins)user=> (re-find re1 "\"-\"")
"\"-\""
(cmd)user=> (re-find re2 "\"-\"")
"\"-\""
https://www.regular-expressions.info/freespacing.html

👀 1
noisesmith17:04:46

my comments there are incorrect, but the layout makes it easier to see what the regex is

Søren Sjørup21:04:51

Thanks @U051SS2EU didn’t know about free-spacing.

Søren Sjørup10:04:28

After looking at regal a bit, now I wish there was a lexer generator that uses regal syntax for patterns.