Fork me on GitHub
#beginners
<
2022-09-14
>
oskarkv06:09:12

Is there a convenient way to develop two libraries at the same time, where one of them depends on the other, without having to update the dependencies and restart the REPL of the first one constantly?

domparry06:09:59

Check out polylith

oskarkv06:09:07

Alright, I will. Thanks!

pavlosmelissinos07:09:19

> without having to update the dependencies and restart the REPL of the first one constantly You can also check out the https://github.com/clojure/tools.deps.alpha/tree/add-lib3

pavlosmelissinos07:09:06

polylith is mostly about working on multiple projects (libraries/applications) in the same repo. If your libraries are in separate repos then it might not be what you want. With add-lib3 you'll still have to update the dependencies but without restarting the REPL

delaguardo07:09:12

clj -Sdeps '{:deps {lib1 {:local/root "./path/to/lib1"} lib2 {:local/root "./path/to/lib2"}}}' ... over args to start a repl.

πŸ‘ 5
pavlosmelissinos07:09:08

That's probably the simplest solution, for some reason I thought local/root still checks out the repo in .gitlibs.

oskarkv07:09:44

Thanks guys, I will check out everything later.

Ben Sless09:09:42

Local root with deps.edn is πŸ’―

πŸ‘ 2
Rupert (All Street)09:09:16

@U4DNSU5NE - Two approaches we use at https://sevva.ai. 1. if you use emacs you can run sesman-link-with-buffer to link a library file to another REPL 2. As @UK0810AQ2 suggested, update the src paths in lein/deps.edn to include the library's src directory.

Adham Omran14:09:27

I'm studying the https://clojure.org/guides/threading_macros and I'm using Anki along the way. I'm finding it difficult to make questions about these macros. Other than what each symbol represents, what should I commit to memory?

Adham Omran14:09:03

What I've got so far..

dpsutton15:09:48

I question if this is more helpful than

(doc ->)
-------------------------
clojure.core/->
([x & forms])
Macro
  Threads the expr through the forms. Inserts x as the
  second item in the first form, making a list of it if it is not a
  list already. If there are more forms, inserts the first form as the
  second item in second form, etc.
nil

Adham Omran15:09:47

I'd argue it's more helpful long term because I'd avoid running (doc) for common symbols and functions.

pppaul17:09:04

avoid looking up docs for common symbols? i do this all the time and i've been using clojure for more than 10 years. though i've never really found the threading macros something i've looked up, cept for cond-> some-> i think that if you are finding the macros hard to understand, don't use them. when i first saw them it was obvious to me what their value was, but i already had a lot of experience with languages that needed these types of macros but didn't offer them.

pppaul17:09:10

maybe after writing a lot of code without the macros, their value will also become obvious, and as well as their use-cases. then you wont have to try to come up with ways of remembering them.

seancorfield19:09:01

I think the example for as-> in the guide is terrible. as-> works much better inside a -> pipeline (so that it's (as-> sym (some-expr-with sym :in-it)) -- and the example in the guide doesn't need as-> anyway:

(-> [:foo :bar]
  (->> (map name)))
  (first)
  (.substring 1))
and it would be more idiomatic to use (subs 1) in that last line as well.

seancorfield19:09:24

The advice about thread last and the pipeline of sequence functions is probably a bit outdated too -- since transducers are often the better way to deal with such pipelines, especially when the last step is reduce...

seancorfield19:09:16

(->> (range 10)
        (filter odd? ,,,)
        (map #(* % %) ,,,)
        (reduce + ,,,))
could be
(transduce (comp (filter odd?) (map #(* % %))) + (range 10))
(which doesn't create intermediate lazy sequences)

Adham Omran03:09:58

pppaul, I'm not finding the macros hard, on the contrary I think they are simple, you just push the result down the stack of expressions, I do think you are right on this being a matter of use rather than memory

Adham Omran03:09:08

sean, I assume the best way to be up to date is to read recent Clojure code from active projects? Thank you for the extensive answer I'll be reading it again later today, got work now!

seancorfield03:09:38

@U03QTHYKXK7 I'm not sure. I stay up to date by being very engaged here and trying to always stay on the latest versions of Clojure itself and all the official core tooling.

seancorfield03:09:54

(disclaimer: I first learned Clojure in 2010 and have used prerelease builds ever since, as soon as they appear, to stay current on new features in the language)

Adham Omran13:09:34

Amazing, I only started seriously learning Clojure this month, still I'm having a lot of fun

Adham Omran13:09:56

I don't know about transduce, I'll give its doc a read!

Sam Ritchie01:09:13

same here (clojure in 2010, maybe 2009??) and I can confirm that @U04V70XH6 was just as friendly and active at the beginning!

😊 1
Sam Ritchie01:09:36

back in the IRC days

seancorfield02:09:33

Back when we all knew each other on IRC πŸ™‚ Clojure has grown a lot since those days!

clojure-spin 1
Sam Ritchie02:09:48

I worked at Google for a stretch a couple years ago now and was startled to see Alan Malloy in chat one day. Haha he got a full dose of memories and β€œthank you for everything!!” From me. He is deep in Haskell mode now

Epidiah Ravachol15:09:17

A Namespace Mystery! I'm working on a ClojureScript project and I have a file that, at the moment, is just the ns form, nothing else. In the repl, find-ns returns nil. All the other files in the project seem fine. I can get into the namespace with in-ns, but once I'm there, if I try something like (def abc "abc") I get a TypeError that says the namespace is undefined. But the plot thickens! In the repl, I can use in-ns to create and enter all sorts of nonsense namespaces and they work. But if I make a new file and enter that file's namespace in the repl, it's undefined again. I can trick it by enter the namespace in the repl first and then creating the file, but the next time I restart the repl, we're back to the undefined namespace. I feel like I'm making a very trivial, newbie mistake, but cannot wrap my head around it.

dpsutton15:09:49

(doc in-ns)
-------------------------
clojure.core/in-ns
([name])
  Sets *ns* to the namespace named by the symbol, creating it if needed.
in-ns creates a namespace if it doesn’t already exist. It does not add any bindings like clojure.core

dpsutton15:09:45

(macroexpand '(ns foo)) will show you what the ns macro does

dpsutton15:09:21

But the workflow you want is to require the namespace before you in-ns it, or just evaluate the (ns foo) form

πŸ‘ 1
Epidiah Ravachol15:09:11

Doing require first seems to have worked, which is weird because I feel like I haven't been doing that and things were working just fine until this morning. Unless... If I've got a project with two files and one of them is requiring the other, that was just handling it for me without me realizing it.

dpsutton15:09:30

Yeah. Things have to be required once. That creates the namespace and the forms in it

Eugene Mosh18:09:09

Hello friends!! β™₯️ (max "s" "d") => "s" why??

hiredman18:09:58

user=> (max "s" "d")
Execution error (ClassCastException) at user/eval144 (REPL:1).
class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
user=>

hiredman18:09:36

clojurescript is more loosey goosey about that stuff, but might say max on non-numbers has undefined behavior

hiredman18:09:12

the ascii code for s 115 and for d is 100

dpsutton18:09:44

"s" < "d"
false
"d" < "s"
true 
strings just seem to be comparable with < operations in javascript

hiredman18:09:59

https://cljs.github.io/api/cljs.core/max says it compares nums or numbers, so likely anything else is considered undefined

William LaFrance18:09:25

I just tried this in non-js clj and was kind of surprised that (max \s \d) doesn’t coerce java.lang.Character to java.lang.Number

hiredman18:09:41

user=> (doc max)
-------------------------
clojure.core/max
([x] [x y] [x y & more])
  Returns the greatest of the nums.
nil
user=>

hiredman18:09:46

characters are not numbers

βž• 1
Eugene Mosh19:09:11

so how to use max with Unicode?

dpsutton19:09:07

probably compare. Can you give an example?

hiredman20:09:14

depends what you mean by "with unicode"

hiredman20:09:08

a single character in java isn't actually enough for a unicode character, sometimes you need two

hiredman20:09:46

but if you don't care about that you can easily turn a character into a numeric value

user=> (int \a)
97
user=> (short \a) ; chars are 16 bit values in java
97
user=> (byte \a)
97
user=>

hiredman20:09:50

(javascript also uses utf16 or ucs2)

Eugene Mosh20:09:17

If in form (max "s" "d") insteed s and d will be Arabic letters encoded in Unicode, how REPL will calculate result?

dpsutton20:09:03

can you put them in your repl and tell us?

hiredman20:09:58

so in clojure you will get an error (you get an error with "s" and "d" as well) with clojurescript the behavior is likely considered undefined, even though you don't get an error

dpsutton20:09:15

❯ clj -A:cljs -M -m cljs.main -re node -r
ClojureScript 1.10.773
cljs.user=> (max "Ψ£Ω‡Ω„Ψ§" "Ω…ΨΉ Ψ§Ω„Ψ³Ω„Ψ§Ω…Ψ©")
"Ω…ΨΉ Ψ§Ω„Ψ³Ω„Ψ§Ω…Ψ©"

dpsutton20:09:30

no idea if that makes sense or not though

hiredman20:09:34

undefined behavior means it could return anything

dpsutton20:09:01

compare should be well-defined though

cljs.user=> (compare "Ψ£Ω‡Ω„Ψ§" "Ω…ΨΉ Ψ§Ω„Ψ³Ω„Ψ§Ω…Ψ©")
-1

Eugene Mosh20:09:22

undefined behavior ?? damn... where is precision of LISP??

hiredman20:09:56

dunno what gave you the impression that lisp is precision

hiredman20:09:32

(is it not precise to say, the function operates on numbers and all else ub?)

hiredman20:09:19

I don't know of a place that gathers together all the undefined behavior in clojure and clojurescript (it can be tricky to tell since neither has a formal spec). https://notes-and-tips.hexstreamsoft.com/themes/unspecified-behavior/ is a neat list for the common lisp hyperspec

hiredman20:09:07

in general, ub is more likely to throw an error in clojure because the host (jvm) is stricter about types and has fewer polymorphic operations than clojurescripts host (js)

hiredman20:09:50

so max on clojure throws an error when passed things that are not numbers, but in clojurescript you get some kind of result

Eugene Mosh20:09:53

Thanks! β™₯️

Jakub Arnold19:09:28

hey guys, I'm looking through options to make a desktop UI but with something that can hot-reload the UI (like in react) ... so far I've found cljfx which seems interesting and able to do this, but a little complicated ... I've also found HumbleUI but the readme says Work in progress. No docs, and everything changes every day. ... soo, I'm wondering if there's any other options, or do I just go with cljfx?

walterl20:09:16

@U7RJTCH6J's #membrane is also WIP, but active, and implements some cool, Clojurey ideas.

phronmophobic21:09:44

πŸ‘‹ I think the "safe" bet for a clojure desktop UI is still Electron+cljs+your-favorite-cljs-ui-lib which is what it is. There are a couple options on the horizon that you may find compelling. Someone recently asked about the current state of https://github.com/phronmophobic/membrane and I answered here, https://clojurians.slack.com/archives/CVB8K7V50/p1662707131845219. If you have a specific use case in mind, I'd be happy to give you a more detailed answer. Also, based on recent feedback, I plan on making some improvements to docs and implementation next week (which should be backwards compatible). https://www.clojuriststogether.org/news/q3-2022-funding-announcement/ recently announced that they would be funding development on #cljfx There are some people already doing interesting things in https://github.com/HumbleUI/HumbleUI (for example, https://twitter.com/LuisThiamNye/status/1517874472681943043?s=20&amp;t=FmczT8XVYjWuNcBor3n1Og)

Jakub Arnold00:09:38

@U7RJTCH6J thanks for the detailed answer! the app I want to build is a image (and maybe audio) dataset builder/organizer for machine learning - and ideally with a canvas where I can manipulate individual pixels to make a very basic layered image editor - it doesn't have to be super fancy, being able to layer a few images and erase/draw some pixels (and maybe draw some super basic controls like a rectangular selection) would be probably all that I need I've used electron (with JS/react) in the past but tbh haven't really liked it due to the increasing complexity of interaction between the renderer/main process, making things like "list images in a folder and server them directly via a path" quite cumbersome due to the security policies in electron ... I guess most of them can be turned off, tho there's still the ipc stuff 😩 ... but ofc if this is the only way I'll probably do it πŸ˜„ this is partly why I started looking at desktop solutions like cljfx, though I've never used JavaFX and last time I wrote a java desktop app was something with Swing about 15 years ago so I guess for the app I want to build I don't need that complex state management/UI, there might be a few lists/grids and might need fast scrolling through data, but I think the most complex part would be the "image editor" --- not sure if it's a good idea to build this in javafx/cljfx hmm

phronmophobic14:09:47

@U042BPMDR0V To me, it seems like it would be much easier to build that on the JVM rather than JS/react. It seems like any of https://docs.oracle.com/javase/9/docs/api/javafx/scene/image/WritableImage.html , https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html, or something fancier like https://github.com/HumbleUI/Skija/ would be suitable for the image operations. On the UI side, it doesn't seem like it would matter too much if it's mostly responding to mouse/keyboard events on a canvas. I would obviously prefer my own membrane library, but using cljfx should work pretty well. https://github.com/phronmophobic/membrane/blob/master/src/membrane/cljfx.clj#L339 a clojure example of setting a cljfx canvas. https://github.com/phronmophobic/membrane/blob/master/src/membrane/cljfx.clj#L579's an example of drawing an image onto the canvas. I'm not too familiar with the cljfx components, but I'm sure there's some sort of list/grid component.

Jakub Arnold19:09:55

@U7RJTCH6J thanks for the info! I'm looking at membrane and I'm probably misunderstanding, but wouldn't membrane be more complex for me to use if I just want to target one backend? I guess in theory I like the idea of being abel to pick and choose, but on the other I'm targetting primarily windows, so not sure if membrane is a good idea if windows support is experimental? maybe I'm misunderstanding how membrane works, but if you're providing a common API for all these backends don't you have to somehow implement this for every single backend as a least common denominator? or maybe a better question, as I'm looking through the tutorial https://github.com/phronmophobic/membrane/blob/master/docs/tutorial.md I'm not sure if I understand how I could for example add a component from the backend that's not implemented in membrane? or maybe I'm misunderstand how this fundamentally works, since the canvas example you linked in cljfx.clj in membrane just uses the cljfx component directly, but I'm not sure if that's something internal only, or if it's exposed too? I don't see the canvas in the component listing in the tutorial tho

Jakub Arnold20:09:03

fwiw I'm trying out membrane right now and it feels a bit simpler than cljfx, tho the java2d backend doesn't look the best on windows (antialiasing probably?) but I guess that would be fine if I can get the canvas stuff to work though, also not sure if the java2d backend is the one I should be using, or if it's just for demo purposes? sorry if I'm asking too many questions, the amount of UI options in clojure is a bit overwhelming hehe

phronmophobic20:09:30

Yea, I don't have a good windows setup so it's hard for me to test how well things work on Windows. It should work, in theory, but I wouldn't be surprised if there were Windows specific quirks (like the quality issue you're noticing with java2d). Besides skia (which I haven't built for windows yet), java2d is the most complete and tested backend. I like using the java2d backend for demos since it doesn't require any dependencies and has the broadest support. > sorry if I'm asking too many questions, the amount of UI options in clojure is a bit overwhelming hehe All good questions and it's kind of a jungle out there!

phronmophobic20:09:57

> maybe I'm misunderstanding how membrane works, but if you're providing a common API for all these backends don't you have to somehow implement this for every single backend as a least common denominator? I often get that question, but it's the same problem for most of the other alternatives (eg. web, swing, javafx). Portability was never really a primary goal, but if you build your user interface out of text, shapes, and images, then it's actually not a hard problem to support multiple platforms. I would argue building your user interface in terms out of text, shapes, and images is a good idea regardless of which platform you target. > I'm not sure if I understand how I could for example add a component from the backend that's not implemented in membrane? This should be possible, but I haven't thought about it very much. It would depend on which backend you're using. It's much easier to embed membrane components in other frameworks than the other way around. > I don't see the canvas in the component listing in the tutorial tho Yea, I wasn't being clear. I was sharing the canvas link as an example of how to use the JavaFX Canvas via cljfx. Even if you don't use membrane, the various backend implementations can be good starting clojure examples for swing and javafx.

phronmophobic20:09:31

> java2d backend doesn't look the best on windows (antialiasing probably?) Hmm, there probably is a simple config fix for this. I'll try to look into it, but if you stumble upon a fix, it would be great to hear what you find.

Jakub Arnold22:09:07

thanks for the answers! > Besides skia (which I haven't built for windows yet), java2d is the most complete and tested backend. I like using the java2d backend for demos since it doesn't require any dependencies and has the broadest support. do you mean that skia is more featureful than java2d? I guess having more power in terms of custom components/rendering could be useful to me, though in terms of UI I think I still need something that can do basic form elements like buttons/textboxes/images/dropdowns, and some basic layouting, and maybe most complex part being a scroll view of some sort? I guess it could be possible to build this as a custom component, though it'd be nice to use a backend that can do something like a grid of 100 images that I can scroll through "natively", but if everything else is amazing it's not a dealbreaker to do this myself > I would argue building your user interface in terms out of text, shapes, and images is a good idea regardless of which platform you target. I kinda agree with this, I've used https://egui.rs/ in the rust land in the past and really liked the ability to just bulid custom things on top of a very simple UI system - looking at skija it seems its' basically a 2d vector shape/text renderer right? so I'd assume if there aren't component implementations in membrane I'd have to roll my own --- maybe the only scary part here is the layout calculation though, as in it's probably not that difficult to make a completely custom component drawn with basic shapes, but I'm not sure if I'd want to dive into things like calculating the layouts too --- but maybe I'm misunderstanding at what layer membrane would operate here, I'm maybe thinking of it more like a "reactive state propagation on top of custom components"? > This should be possible, but I haven't thought about it very much. It would depend on which backend you're using. It's much easier to embed membrane components in other frameworks than the other way around. hmm maybe I'm misunderstanding membrane's role here, I was thinking of it a bit like the immediate mode libraries (dear imgui, nuklear, egui), where it handles the input/layouting/"state" and delegates to a backend layer for rendering (and in the case of these libraries also needs input passed in) --- but lets say I use skija to have its flexibility, looking at this <https://github.com/phronmophobic/membrane-skija-example/blob/main/src/com/phronemophobic/issues.clj> I guess membrane exposes the necessary APIs to build a "custom drawn" components?

phronmophobic04:09:56

> > do you mean that skia is more featureful than java2d? The skia backend (which is different from skija) is just the backend that I personally use most of the time which means it's the most polished. It's also the place I start if I'm adding a new backend feature. However, most of the builtin components are in pure clojure and should have the same features regardless of backend. > https://egui.rs/ This is really neat! > buttons/textboxes/images/dropdowns, and some basic layouting, and maybe most complex part being a scroll view of some sort There are some builtin versions of these components, but they are pretty basic. > I'm not sure if I'd want to dive into things like calculating the layouts too There are some layout helpers in membrane (eg. membrane.ui/vertical-layout, membrane.ui/table-layout, membrane.ui/center, etc), but generally, I don't think layout is actually that bad. I just think people have been scarred by CSS which makes everything 10x harder than it should be. > but maybe I'm misunderstanding at what layer membrane would operate here, I'm maybe thinking of it more like a "reactive state propagation on top of custom components"? Membrane is actually a collection of libraries to help build user interfaces. All of the pieces are meant to work together, but most of the pieces are both optional and stand-alone. Some of the different pieces are Input (eg. handling keyboard and mouse events), a View Model (ie. specifying what to draw), Graphics (specifying how to draw), and state management. > I guess membrane exposes the necessary APIs to build a "custom drawn" components? For most part, membrane's builtin components ignores "native" components and builds everything out of shapes, text, and images. The event handling is pure clojure, so it can work with any method that provides or simulates user input (this seems similar to https://github.com/emilk/egui#integrations). Since most UI frameworks provide some option for custom drawing, that's usually how membrane embeds itself.