Fork me on GitHub

After some bad experiences in high school programming classes, my son is showing some interest in learning how to code. His frustration threshold is a little low because of those classes. What's a low-friction site or tool he could use to learn some basic clojure?


clojure is probably pretty bad to start with, without a mentor or some support. javascript is a lot better as it has almost no demands of it's users (just a web browser + F12), but even that's not enough for most people. incentives drive people, and languages tend to be low on satisfying high level incentives. also "learning how to code" is probably not really what you son wants to do, i suspect that something higher level that likely requires learning how to code is the main incentive here.

pppaul01:10:17 that is a good clojure learning site

Daniel Craig01:10:13

I tend to agree, Clojure is not a low-friction language for beginners; they will hit speed bumps rather frequently unfortunately. Calva with VS code is the most low friction path into Clojure in my opinion, and definitely embark on this learning journey with the help of a book (perhaps Programming Clojure 3rd edition). Web resources won't be enough; there are few Clojure resources compared with Python and Java


i have a feeling that a generic tutorial site is going to make your son bored to tears. there is some clojure integration with mono which lets you interact with unity, which is probably something he'll be more interested in. but i really think clojure is attractive to people who have been frustrated with the more mainstream programming experience, and who are willing to endure a bit of a struggle to see what a different paradigm of programming offers.

Bob B01:10:25

• might be a bit too elementary, but has a decent amount of prose introducing functions, and most of the common error messages are overridden to be more friendly • 4ever-clojure (<>) has more of a difficulty gradient (from elementary to hard), but doesn't have much in the way of "teaching", and is more just about filling in blanks with a function; and less about defining constituent functions and building up a program • sites like codewars have an online clojure environment with tons of different challenges, but again, not really a teaching site, more of an 'exercises' site. It does have unit tests and so on, so it can have a decent "real world" feel to it, but the trade-off there is that clojure is being used more directly, so errors are not going to beautified or explained or anything • exercism (<>) offers exercises and mentoring to get feedback on those exercises none of these will really "teach" clojure (beyond the library that facilitates - not sure if you're looking for something like a structured course, or an online environment that'll provide a runtime where you can help your son solve the challenges


I think Clojure is an excellent starting language. There is not a ton of friction to just try it. • Install Java • Install VS Code • Install Calva • Fire up the Getting Started REPL (The first three steps can be skipped if you run it in the web browser, but I’d go for installing the minimum stuff.) The Getting Started REPL will guide your first steps. Personally I had a wonderful experience with #exercism . You can run that in parallel with the Getting Started REPL Clojure guide. And you can also run 4Clojure in the editor with

❤️ 1

If you're going to be teaching, I've found an extremely useful tool. We use it at work to help teach programmers coming from other languages. Might not be as useful for new starters.

Sam Mokracek02:10:29

Hey everyone, I’m experimenting with some basic macros and below I’ve pasted code to test my acceptor macro.

(deftest acceptor-test
  (testing "Basic input of a two-state acceptor that decides if a binary string
            has an even number of 0s."
    (acceptor even-zeroes {:states {:s1 :s2}
                           :transistions {{:s1 1} :s1
                                          {:s1 0} :s2
                                          {:s2 1} :s2
                                          {:s2 0} :s1}
                           :start :s1})
As it happens, Calva calls the name even-zeroes of the returned function from the macro an “Unresolved symbol.” The code runs fine, and this is really more of a linting thing. Any Calva users who know a solution?


Calva doesn't know about user-defined macros by default -- or rather clj-kondo doesn't, which is what Calva uses for those warnings. You can add .clj-kondo/config.edn to your project, containing a :lint-as clause to tell clj-kondo that your acceptor macro should be treated like some sort of def (which would then introduce the symbol even-zeroes for you).


Something like:

{:lint-as {your.namespace/acceptor clj-kondo.lint-as/def-catch-all}}


Feel free to ask follow up questions in #CBE668G4R and #CHY97NXE2 for more details @U042V3ZG33Q

Tomasz Kontusz10:10:26

Hi! I'm trying to add some system libraries to the classpath. I have a fresh Leiningen project, and I've tried to add :jvm-opts ["-cp" "/usr/share/java/dbus.jar:/usr/share/java/unix.jar"] to defproject, but that stopped REPL from starting - it looks like :jvm-opts replaces the default options. Is there a good way of doing this? I'm not concerned with packaging at this moment, I just want to play with DBus

Tomasz Kontusz11:10:10

I've found I can use :resource-paths to add system .jars. It works, but I'm open for better suggestions :-)


just for reference :jvm-opts are the options you pass to the JVM. Things like heap settings, garbage collection params etc and not commands like you were trying to. have a look at for some jvm option examples. hence its an invalid option and prevents the jvm from starting at all 🙂

Tomasz Kontusz11:10:01

I've tried to pass the -cp (as in -classpath) option, not run the cp command 🙂


like you discovered, :resource-paths is pretty much the way to go for locally available jars. also i can see not sure it thats the same, but you can add this in the normal :dependencies can make it simpler maybe

Tomasz Kontusz11:10:58

Ohh, they even have a Leiningen snippet! Thank you!


are the interceptors connected? i use interceptors in yada and in that framework a resource has a list of interceptors that it runs in order, is there something similar in pedestal?


Hmmm, I am not sure about it, even I have not used yada, and do not know how that works

pppaul17:10:52 you need to look for this in your app & pedestal. this is one of the unfortunate things of using a framework (any framework), it's more often than not that you have to learn a hell of a lot about how the framework actually operates in order to use it.


i think if you are a bit new to clojure/web frameworks (either one), you would be better to avoid the more complicated ones. probably best to start with ring & . these are old, have a lot of stackoverflow, quite simple. it'll give you a good foundation for getting into pedestal/reitit/kit/whatever.


@U0LAJQLQ1, Yeah I was going through the chain interceptor some time back, BUt I am just thinking how output one inteceptor is passed to the another inteceptor


and how we handle if one of teh interceptor fails ?


interceptors are functions, they are managed by an async dispatcher, in the case of pedestal the dispatcher expects to also handle functions or interceptor chains as output of an interceptor. when an interceptor fails if can provide an error chain, or error interceptor, or the dispatcher can handle this case in a special way (in yada the dispatcher does everything)


in yada the interceptors are glued together via something like manifold/chain


Yes \, Thanks you, will go through it


Is there a built in way to coerce string-of-1-character to a char? I'm using (first (str foo)). This isn't exactly long or complicated. But I might already have a char, in which case this converts a char to a string just to turn it back into a char. (The way Clojure's equality semantics works, I would have expected (= \c "c" ) to be true. But alas...)

Bob B18:10:46

check if it's a char? first


Make a protocol and extend it to string, char, and object? Have it return identify on char, first on string , and call the protocol on the str of the object otherwise?

💯 2

I'm not 100% following. (Note that I have read about protocols, but not had reason to write any yet).


Ah, that's a good suggestion @U11BV7MTK! I don't tend to think of protocols for "small" things like that but it makes a lot of sense -- a la carte polymorphism!


Like this?

user=> (defprotocol ToCharacter (as-char [_]))
user=> (extend-protocol ToCharacter
         Character (as-char [c] c)
         String (as-char [s] (first s))
         Object (as-char [o] (as-char (str o)))
user=> (as-char \a)
user=> (as-char "a")
user=> (as-char 123)
(with better names, I hope!)

🙌 1

Ahhh. You did all the work for me! Now I still haven't written any protocols. 😹 Actually looking at this though, I'm honestly left wondering why this is better than just a function.

(defn as-char [c]
    (char? c) c 
    (string? c) (first c)
    :else (as-char (str c))))


Could you enlighten me?

Bob B19:10:28

in the small, they're roughly the same, but if there was some other type that you (or someone using that function) wanted different behavior for, the protocol could be extended to new types (with different behavior) without "re-opening" the function


☝️:skin-tone-2: Yes, this. Protocols are "open for extension" but conditionals inside a function are not. At work, we have some code that works with buffers of encoded data and the action taken depends on what the decoded "first" character is, so we could extend a protocol like the above to the encoded buffer type and then use as-char with it -- which we couldn't do with that as-char function containing cond.


Ok. So I guess the idea is you come back later and say

(extend-protocol ToCharacter
   clojure.lang.Keyword (as-char [k]
                          (as-char (fnext (str k)))))

(as-char :a) ;; \a
:thinking_face: At what point in the design process would you normally start to consider adding this complexity, instead of just conforming the function source to new requirements?


That's a good question! As I said above "I don't tend to think of protocols for "small" things like that but it makes a lot of sense" so it's something I still don't consider in situations like that but I probably should. Clojure's polymorphism is often a lot more fine-grained than you'd see in Java and also very "lightweight" so it's more applicable in more situations.


One issue that comes to my mind (for the case of "small" things like this) is that, to meaningfully benefit from this, you need to make a point of actually sharing the protocol across namespaces. It's easy to write a quick function to coerce strings in one ns, where that is needed, and then write another quick function somewhere else where it's keywords that matter.


Or have something like a ns (which is what we have at work for this sort of stuff) and then the protocol could just be internal to that.


What does "ws" stand for there?


World Singles. Where I work. Well, technically it's World Singles Networks but we also own and generally use ws as an abbreviation for most stuff relating to the company.


(when we open source stuff, we use worldsingles or com.worldsingles to be more clear)


I guess (first (name k)) is bit more clear than (fnext (str k) from my example.

Tomasz Kontusz19:10:36

Can I declare a Java interface in Clojure? I want to use a Java library that creates dynamic proxies for user supplied interfaces. I've looked at the Java interop page, but it only shows how to create normal classes for existing interfaces.

Tomasz Kontusz19:10:37

Thank you! I see it's even in clojure.core, I really should look through core some time >_>


Learning core takes a lifetime -- there are hundreds of useful functions in there! 🙂


I'll be interested to hear how you get on with this -- why are you using Java code to produce proxies and what exactly is it producing?

Tomasz Kontusz19:10:01

I'm trying to use java-dbus which (as far as I understand it) generates the proxies

Tomasz Kontusz19:10:08

dbus is an "object-oriented RPC" thing broadly used on Linux desktop, but the official libraries are... less than ergonomic 🙂


Just reading the docs... interesting... good luck!