Fork me on GitHub
#beginners
<
2023-09-06
>
Benjamin J. Thompson19:09:52

I'm having a little luck writing a UI in Swing but would like to hear recommendations about what I could use to do the same thing in a more idiomatic Clojure way? Doesn't even have to be Swing, just a means of putting together a 2d GUI.

kennytilton19:09:58

Disclaimer: I offer reactive frameworks for JS, CLJS+HTML, and Flutter/CLJD so no horse in the race. The latter seems like a breath of fresh air. Flutter/Dart itself is a rich API so a lot to learn, but I imagine Swing is similar. The Flutter doc is great, and getting apps on Web, desktop, and mobile almost for free is amazing. Very reliable/predictable as well. And Google seems intent on a serious win -- they even replaced Skia with their own rendering engine created from scratch. That's a big Wow factor for me.

plus_one 2
👍 2
Chip19:09:36

I’ve found the #C03A6GE8D32 helpful. Both @U2N9GDB1U and @U3E46Q1DG are very attentive and thoughtful. The demo video posted in the channel helped me decide on ClojureDart as my first choice for UI, for whatever my inexperienced opinion is worth.

❤️ 2
Benjamin J. Thompson22:09:23

I tried seesaw, and I couldn't quite get the hang of it. Are there more recently written examples?

phill00:09:01

If you stick to Seesaw, be sure to check out miglayout. But Swing is a bit historical. If you would like to be "where it's at", have a look at ClojureDart.

👀 4
nikolavojicic09:09:17

After that check Wiki on the project's GitHub page.

hairfire19:09:31

You could consider using JavaFX via the https://github.com/cljfx/cljfx library. I've done some simple UIs with it, and it's fairly easy to learn and use. There's also https://github.com/Tensegritics/ClojureDart, described as ClojureDart is a recent Clojure dialect to make native mobile and desktop apps using Flutter and the Dart ecosystem. , which I have not used, but am interested in.

4
👍 4
huy20:09:15

Hi, I'm a total newbie to Clojure. I'm reading the Clojure Web Dev Tutorial by Eric Normand (https://ericnormand.me/guide/clojure-web-tutorial). However, I'm struggling to understand the explanation in "Q&A: Indirecting app". Everything has been clear, up until the point where he explains that in (jetty/run-jetty app ...), app is being looked up only once, but in (jetty/run-jetty (fn [req] (app req)) ...), app is being looked up every time the function is called. How is that, if app in the former case and the anonymous function wrapping around app in the latter case are both handlers and are called every time the server receives a request? http://ericnormand.me https://ericnormand.me/guide/clojure-web-tutorial Learn to build a Clojure web backend from existing components, step-by-step.

daveliepmann20:09:45

app is a symbol which resolves to a var. using the symbol app directly dereferences the var and sends that value (once) to the innards of jetty. wrapping app in a fn means that dereferencing of the var app is delayed until each evaluation of the fn, so changes over time to app are reflected each time.

hiredman21:09:12

run-jetty is a function, arguments to functions are evaluated before the function is called

hiredman21:09:59

therefore when (run-jetty ... app ..) is run, the symbol app is evaluated, producing some value, then that value is passed to the run-jetty function, and the run-jetty function uses that to handle requests

hiredman21:09:40

subsequent re-definitions of the name app don't change the value that has already been passed in to run-jetty

hiredman21:09:16

in js

var app = x => x + 1;
run_jetty(app); run_jetty does something async with app
app = x => x - 1;

huy21:09:09

@U05092LD5 does that mean the anonymous function is created on-the-fly every time and thus evaluates the symbol app lazily each time?

huy21:09:26

could you elaborate? I understand the first case where app is being resolved once, but why is the anonymous function being resolved multiple times?

hiredman21:09:27

this really doesn't have to do with clojure at all

hiredman21:09:31

> var app = x => x + 1;
undefined
> var old_app = null;
undefined
> var run = x => old_app = x;
undefined
> run(app)
[Function: app]
> app = x => x - 1;
[Function: app]
> app
[Function: app]
> old_app
[Function: app]
> app(1)
0
> old_app(1)
2
> 

hiredman21:09:40

for example is js

hiredman21:09:04

you would ask why does old_app not have the same value as app?

hiredman21:09:06

it is the difference between passing a function directly and passing a function that uses a mutable reference to invoke another function

hiredman21:09:33

a clojure example with more explicitly mutability instead of just the implicit mutability of vars

user=> (def x (atom 1))
#'user/x
user=> (def y (inc @x))
#'user/y
user=> y
2
user=> (reset! x 2)
2
user=> y
2
user=> 

hiredman21:09:29

y doesn't become 3 after x was changed to be 2

hiredman21:09:21

because x was deferenced and passed to inc before the value of x was changed

hiredman21:09:20

clojure has some tricks for dealing with this kind of thing, so people often treat it as a quirk of clojure or something, but basically all languages with mutable references and closures have this

daveliepmann21:09:23

> why is the anonymous function being resolved multiple times If I pass you a value, then you have a value. If I pass you a function, you call the function to get the value. I'm not sure if I'm confused here and hiredman is right to correct me, but as I understand it, (fn [req] (app req)) delays dereferencing of the value in the var #'app until each evaluation of the anonymous function.

huy21:09:39

@U0NCTKEV8 thank you very much for your explanation. I totally understand the first case where app is being deref'ed once. My question is why is it deref'ed every time it is referred in the anonymous function? Basically, what makes the difference between the two scenarios?

hiredman21:09:03

you are closing over the mutable reference app (the var #'app)

2
hiredman21:09:21

another way to write the two examples would be

hiredman21:09:37

(run-jetty .. (deref #'app) ...)

hiredman21:09:00

(run-jetty ... (fn [req] ((deref #'app) req)) ...)

daveliepmann21:09:49

@U0NCTKEV8 I think there's some confusion from you saying "the anonymous function [isn't] being resolved multiple times". The function closes over the reference/var app, which is another way of saying that the anonymous function is evaluated multiple times, no?

hiredman21:09:24

the anonymous function is evaluated once which produces a function object

👀 2
hiredman21:09:40

the function object can be called on arguments

daveliepmann21:09:20

yes, I think that's where the confusion came from

daveliepmann21:09:19

calling the function object on a bunch of request arguments dereferences app each time, correct?

🙌 2
hiredman21:09:42

correct, like the second of my examples using deref above

🙌 2
huy21:09:06

the last 2 sentences from both of you explain everything

👍 2
🙌 2
2
🎉 2
huy21:09:11

thank you, really appreciate it 🙂

clj 4
🎉 4
Nik23:09:07

Hi, I started out with Clojure for the brave and true (which is excellent guide and a fun read!). I noticed it is more catered toward a person who already has dipped his hands in world of programming (or atleast has some background in it). Does anyone has any recommendations for a complete newbie? My friend (Chartered Accountant) is interested to learn programming but she has zero knowledge about coding. I'm deciding between Python or Clojure (she mostly works with Excel files / tabular data) and leaning towards Clojure (easier to pick up programming concepts) along with a setting up a batteries included scripting environment for her (using Babashka). P.S. - I'm also new to clojure so any tips that helps her use case is appreciated simple_smile

Chip00:09:39

What does she want to do with the “Excel files/tabular data”?

phill00:09:38

Programming is a vexingly slippery thing to learn because nothing is real. It helps to brace yourself against an Immovable Obstacle - something you can pretend is bedrock. Now that Microsoft has introduced Python-in-Excel, perhaps that might be a dandy Immovable Obstacle to learn against. Get your friend (Chartered Accountant) a copy of "Think like a computer scientist" and alternate its examples with the examples of Python-in-Excel. Of course, Excel is dreadful and Python too, but if your friend (Chartered Accountant) shows genuine interest in programming, you won't be able to keep them (Chartered Accountant) away from Clojure anyway after they begin to question why Python is so hard.

2
2
👍 2
daveliepmann06:09:52

https://www.maria.cloud/is aimed at complete beginners, but be warned: the curriculum is extremely limited and some people don't like the light tone

2
Juan José Vázquez Delgado07:09:53

I love https://www.goodreads.com/book/show/548914.The_Little_Schemer. I wish I had read it when I was starting in programmimg.

4
gratitude-thank-you 4
Jason Bullers12:09:07

I've read parts of the Reasoned Schemer, which is in the same style as that book (Socratic questions). Personally not a fan of that style, but it definitely works for brains other than mine. I've wondered the same thing about the material out there. In general, I get the feeling that Clojure tends to be a language picked up by experienced devs as opposed to programming newbies. This is especially so of Java refugees. A lot of the material tries to sell or explain Clojure by comparison and contrast. Some other material, like SICP, don't assume a programming background, but they pick as their Immovable Obstacle (love that term) mathematics. This makes sense for people pursuing a computer science education, but try it with anyone outside of that world and they'll likely be very discouraged very quickly.

Nik14:09:05

I had the same observations @U04RG9F8UJZ. And I strongly believe that programming (at least scripting vs product development) is a essential life skill like cooking, driving, swimming etc.

Chip14:09:33

> I get the feeling that Clojure tends to be a language picked up by experienced devs > — @U04RG9F8UJZ IMHO, it is picked up by experienced devs because it was created by experienced devs. That origin and its ethos are why I’m here anyway.

Jason Bullers15:09:25

I agree on the point about scripting: basic coding knowledge unlocks some nice productivity boosters. While Clojure has a great scripting option with Babashka, I don't think that would be a first choice over say Python. It's a huge win for Clojure devs who also need to write scripts (and that's really the sales pitch). None of this is "good" or "bad", it just is. Different languages and different communities have different aims. I think Clojure does what it does well, it's just not a teaching language as far as I can tell (that's not going to stop me from trying to use it as such though 😄)

Nik15:09:30

Although not a great comparison, I tried teaching some kids (basic proficiency with computer) using python and they were struggling with syntax (they understood the concepts like loops and conditionals quickly but found difficult to write it) Meanwhile a friend with finance background (and no coding skills) did the basic clojure katas just after 5-10 mins of overview

daveliepmann15:09:28

> it's just not a teaching language the classic lisp for this purpose is a scheme, especially racket or even — gasp — pyret

Jason Bullers15:09:09

Have you seen those taught without a strong mathematical foundation? For example, SICP has examples around Newton's method etc. which I think are awful examples for kids or people from non-stem backgrounds