Suppose I'm a fool and have opened some resource (like a port/socket/DB connection) without binding it to a symbol, thereby preventing me from .closeing it by typical means. Is there another way for me to get a hold of/reference that open resource, or is a REPL restart the only option? (if there's no generic method and it depends on the host, assume JVM)
If it's within *1, *2, *3 range, you can (def resource *N) and get a handle on it. If it was further back than that, then no.
heartbreak! but understandable- I'm sure that *1|2|3 will save me someday though
it could be an interesting addition to something like ClojureStorm, to extend it to like "*100" and have a quick way of listing and clearing them
It won’t help you right now, but I recommend https://github.com/riverford/objection to prevent this kind of thing in the future - it’s a bit like a dynamic alternative / adjunct to component/integrant et al. The idea is it keeps a registry of all these object / resource like things.
So then you’d call (obj/status) and can get the object back and do whatever with it.
Ooh, Riverford! A friend of mine in England was a delivery driver for them for quite a while. May still be, in fact.
Yes! I worked there for a couple years, back in 2018. This library was one of the principal engineer’s ideas and I really liked it. Was such a lovely place to work, I still get the veg boxes many years on :)
Looks like she left in 2013, after driving for them for about a decade.
I want to capture key presses (and depresses) (and I am not experienced in doing this in JS, by the way), and I could follow the example here: https://github.com/ulsa/movedot-cljs/blob/master/src/movedot_cljs/movedot.cljs but that has these lines at the top,
(:require [goog.events :as events]
[goog.dom :as dom]
[goog.graphics :as graphics]
[goog.events.KeyHandler.EventType :as event-type]
[goog.events.KeyCodes :as key-codes]))
whereas so far I have been able to do all of my JS interop without needing any extra requires beyond CLJS itself.
Is there a way to do this without these goog require lines?
EDIT: 2nd question: Is there any way to do this in a way that works for ClojureScript as well as Clojure? I'm guessing no and that there's nothing that targets both JS and JVM for user inputs, but I may as well ask.
It's difficult to find explanations on this topic. I even went through the entire Brave Clojure book (Yes CLJ, not CLJS. I haven't found an equivalent resource for CLJS yet.) and I did not find a single mention of handling real-time keyboard input anywhere, only bit where command line inputs are handled.But why are you looking at that example in the first place? It states that it "has been translated from Google Closure into ClojureScript", so of course it will use everything from the GCL (Google Closure Library) that it can since it's also shipped with CLJS and is easily available from it.
But it doesn't meant hat it must be used, or even should.
The graphics import is not relevant to you at all.
dom is used only for dom/getElement and you can use (.getElementById js/document ...) instead.
The other imports are for keyboard event handling, and you can do it just fine with (.addEventListener js/document "keydown" ...).
GCL makes sense when you need to run your app on ancient browsers. In modern browsers, most of this stuff is standard, works in the same way, is easily available. So I'd suggest sticking to the browser JS API. Check out MDN docs and their examples on how to do things.
> Is there any way to do this in a way that works for ClojureScript as well as Clojure?
Key handling is not language-specific, it's platform-specific. So your guess is correct.
> It's difficult to find explanations on this topic. I even went through the entire Brave Clojure book
It's not in the book because it's a very specific topic that has nothing to do with CLJ. There's a practically infinite amount of such topics, you can't write a book that mentions them all.
It is easy to find explanations if you look for docs for your target platform/framework. Browser JS API for CLJS apps that run in browsers, UI framework docs for whatever you might end up using on JVM (maybe AWT, maybe JavaFX, maybe something else - they all have their own ways of handling keyboard events).
> The graphics import is not relevant to you at all.
> dom is used only for dom/getElement and you can use (.getElementById js/document ...) instead.
> The other imports are for keyboard event handling
Yes, I had narrowed it down that far.
> , and you can do it just fine with (.addEventListener js/document "keydown" ...).
^ This is what I've been searching everywhere to find. Well, actually a more complete simple example for capturing a couple of different keys and having them cause calling of functions would be what I'm really looking for, but even this little snippet of code is more than I've been able to find anywhere.
There's really nothing to it: https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event If you can't find something like this within a few minutes, I'd definitely suggest asking some LLM about it. They're great at searching for stuff like this and for generating simple code snippets of low complexity.
GCL makes sense when you need to run your app on ancient browsers. In modern browsers, most of this stuff is standard, works in the same way, is easily available. So I'd suggest sticking to the browser JS APIInteresting case of someone suggesting I use one less bit of tooling. Good to hear. 😀 > Check out MDN docs and their examples on how to do things. See this is where I'm being stymied. I know I can look up all kinds of info on and examples of JavaScript (for instance this: https://github.com/ulsa/html5-canvas/blob/master/src/index.html), but trying to figure that out while also needing to figure out how to rewrite the parts of that I want from JS to CLJS is a lot. It would certainly be useful to have basic things such as those covered on MDN for JS covered elsewhere for CLJS. That might sound silly if translating from JS to CLJS sounds easy or is easy, but it is not for me, at least right now while I am trying to figure a lot of other things out. Actually I just found this http://app.klipse.tech/ but it translates from CLJS to JS. The reverse would be useful to me, even though learning the concepts while only ever looking at CLJS in the first place would be a step better. EDIT: I just found this https://roman01la.github.io/javascript-to-clojurescript/ which does try to translate from JS to CLJS. I'll definitely be using this while all I can find is keyboard-related topics covered for a JS audience, but again something geared for a CLJS audience would be better.
I wouldn't call GCL "tooling". It's a library. To me tooling is something you execute in some way to achieve a goal. But semantics. :)
> needing to figure out how to rewrite the parts of that I want from JS to CLJS
There are three main things: property access, property value setting, function calling.
Property access: a.b.c in JS turns into (.-c (.-b a)) in CLJS. Or, more readably, (-> a .-b .-c).
Property value setting: a.b.c = x in JS turns into (set! (.-c (.-b a)) 1). You can also use -> here to make it more readable. CLJS-specific syntax that doesn't work in CLJ would be to use (set! (.-b a) -c 1).
Function calling: a.b.f(x) becomes (.f (.-b a) x). And yes, you can also use -> here - you can use it anywhere, in fact.
That's it, that's all you need to know to handle JS->CLJS conversion for like 95% of the browser API.
95% of the remaining 5% is async stuff.
And the remaining is something you'll probably never have to worry about.
> at least right now while I am trying to figure a lot of other things out
As I said early - do not do this. Do not try to figure a lot of things.
Figure things bit by bit, not heap by heap.
Well, I guess I'm oversimplifying JS->CLJ, given how there are things built into JS that aren't built into CLJS at the same conceptual level. Like creating and altering variables, or for loops, or early returns, etc.
But those all are still trivial, most of the time, if you think not about the syntax but about the behavior.
It's not in the book because it's a very specific topic that has nothing to do with CLJ. There's a practically infinite amount of such topics, you can't write a book that mentions them all.Like you said, I was guessing the workings would be different for Java versus JS. I wasn't actually expecting to see answers for my situation in that book (though I was holding out a bit of hope for that---maybe some kind of wrapper that uses Java vs JS branches (like in a cljc file) and can target both even though they are very different). My main point was that that is an example of a great book that nevertheless was missing something I consider very basic and worthy of including. One of the first things any programmer is going to want to do is take keyboard input and have it cause something to happen. I would not call it niche. To encourage adoption of CLJ/CLJS by not particularly me but kids and other new programmers, having a guide, a book or something shorter, that walks through a simple game design would be extremely good. If it's out there, I haven't found it.
> I wouldn't call GCL "tooling". It's a library. To me tooling is something you execute in some way to achieve a goal. But semantics. 🙂 I appreciate that feedback. I use tooling to mean anything external, but yes I guess I should use library when it's...not something I run but rather something my program calls to run?
Property access: a.b.c in JS turns into (.-c (.-b a)) in CLJS. Or, more readably, (-> a .-b .-c).
The distinction between things that take hyphens/dashes and things that don't is a hurdle I did get over a few days ago: properties versus methods. Glad to be past that.
For the record, (.-c (.-b a)) is more readable for me than (-> a .-b .-c). That may sound crazy, but (a) I'm not steeped in JS, and (b) l've only worked in CLJS lately so I'm all good with nested paren execution order. That's more intuitive to me now than JS's mish-mash of dots and parens etc.> I consider very basic and worthy of including
If you ask a different person about what's basic, you will get a different answer.
To some, querying a DB is basic and a must-know. To another, it's sockets. Or files. Or graphics. You get the picture, pun intended.
Keyboard event handling requires more than a language - it requires a platform. That would mean that any book would have to tie itself down to a particular set of platforms, with particular versions.
> a book or something shorter, that walks through a simple game design
The most basic CLJS game is as different from the most basic CLJ game as it can be. Even for plain-text-based games.
Text handling in browsers already requires you to know a whole bunch of stuff, whereas in CLJ you can just print text.
Same with reading keyboard input - in a JVM-based CLJ you can just create an instance of Console and read text from it. Nothing like this exists in browser-based CLJS (there is probably something in Node-based CLJS though).
And if you go beyond most basic plain-text games and add graphics, you're now tackling things of immense complexity. Few things can be farther from "simple" than games.
Of course, there are libraries and frameworks that can make things simple and/or easy. But then it stops being about a language. Why would you want to learn, say, Godot if all you wanted to learn was Go?
I hear you on Java and JS being too disparate to target with one set of things (keywords? The word escapes me. Whatever "def" and "and" are) common between CLJ and CLJS. I do have to point out, though, that even Scratch can take keyboard input (trivially, without any guide needed) and that is meant to teach young children programming. I agree that keyboard input capture is • more complicated than some other programming functionality and that • it may need to be implemented very differently between any two target platforms but I still say • it is basic (as in is a basic thing that a person wanting to pick up a programming language will want to do with it---especially a person less experienced in programming in general. I see a lot of value in Clojure and ClojureScript, which is why it is the language for me right now (despite it being more difficult to get going with than any other language I've used before!), but here I think the fact that it targets and transpiles to other languages, while really powerful in other contexts, leaves it being, more than other languages, the domain of more experienced programmers, and maybe specifically those experienced in those target languages, maybe even more so for CLJS than CLJ, which seems to end up with it being more difficult for others to get started with them.
> Property value setting: a.b.c = x in JS turns into (set! (.-c (.-b a)) 1). You can also use -> here to make it more readable. CLJS-specific syntax that doesn't work in CLJ would be to use (set! (.-b a) -c 1).
That last part is surprising. Not that it wouldn't work in CLJ, but that it would work in CLJS at all. How can (f1 (c (b a) d)) be the same as (f1 (b a) c d)? I know it's not exactly that, but I think I'll find it not much trouble to avoid that last form. 🙂
Function calling:> > That's it, that's all you need to know to handle JS->CLJS conversion for like 95% of the browser API. > 95% of the remaining 5% is async stuff. > And the remaining is something you'll probably never have to worry about. That is encouraging, though I think another piece of the puzzle is the initial declaration of things at the tops of programs (dependencies and assigning names to them, and maybe more?).a.b.f(x)becomes(.f (.-b a) x). And yes, you can also use->here - you can use it anywhere, in fact.
even Scratch can take keyboard inputThe word "even" is misused here. Scratch was designed for interactive things, it's not a general-purpose language. So of course it can take keyboard input. > the fact that it targets and transpiles to other languages, while really powerful in other contexts, leaves it being, more than other languages, the domain of more experienced programmers Once again - this only gets in the way because you're trying to tackle 15 things at once. Stop trying to learn both CLJS and CLJ, the toolings of both of them, the libraries of both of them. Learn CLJS by itself, if that's what you need. Focus on browser-only CLJS, if that's what suits you most. Find things that will help you in particular to approach it. But learn the basics of the language itself first, at the very least the syntax. Scratch doesn't even have syntax to speak of, but CLJS does - you cannot get by without learning it and hoping for the best. When the syntax is learned, if games is what you fancy, you can pick up e.g. https://github.com/oakes/play-cljc and learn its basics. > How can (f1 (c (b a) d)) be the same as (f1 (b a) c d)? Because
set! is a special form that's parsed differently based on the arity.
Which can also be done with functions and macros.
> another piece of the puzzle is the initial declaration of things at the tops of programs (dependencies and assigning names to them, and maybe more?)
Please, please, please learn the syntax of CLJS. It is incredibly basic compared to most other text-based languages.
Every such problem will vanish then.
The ns form allows for very few variations, all trivial. def forms are also as trivial as it gets, defn not being too far behind.there are two kinds of languages: ones where keyboard input is simple and universal, and ones you can use on many platforms. keyboard input is not simple or generalizable because platforms are not
more recent inventions like networking are much more portable
> Do not try to figure a lot of things. > Figure things bit by bit, not heap by heap. If by this you are suggesting to instead follow along with a structure book/guide (or maybe it was another clojurian who wrote that), well I did follow a few guides and some of Brave Clojure a while back but eventually I felt like I had to actually build something from scratch to really learn. I'm making a simple* game right now and I want to see it through before I go on to following another book/guide. *Well it should be simple. It has nearly static graphics and I'm only looking for a few keyboard inputs (some letter keys, maybe left and right arrow keys, and Enter). I'm good with the limited graphics (canvas drawing) I need, but I have to get through this keyboard gauntlet before I can really get into the logic of the game! It feels much more difficult than it should be.
> It feels much more difficult than it should be.
It's literally one form, as I showed above, with .addEventListener.
It's difficult to you for two reasons:
• You're looking for a CLJS-specific thing, instead of relying on the underlying JS
• You aren't familiar enough with JS interop
The first one is a matter of being used to reframing your questions. It's fine to start with looking for solutions in CLJS, but you don't need to persist when nothing pops up within a few seconds - just search for a JS solution instead.
The second one is a matter of getting familiar with CLJS. As I mentioned, basic interop is trivial. I've already described above all you have to know in order to be able to listen for keyboard events and handle them.
> Stop trying to learn both CLJS and CLJ, the toolings of both of them, the libraries of both of them. > Learn CLJS by itself, if that's what you need. Focus on browser-only CLJS, if that's what suits you most. No problem with this. Every time I use another---the word escapes me again, but "conj" or "mapv" for example---I check CLJS resources. I do a quick check of the CLJ cheatsheet just to see if it exists there too, but that's it. As for browser CLJS versus other options, I'm aware a person could use Node.js to make a CLJS app work as a desktop program (yes?), but I wasn't thinking there was much difference between that and targetting browsers so that isn't distracting me either.
> the word escapes me again, but "conj" or "mapv" for example
Those are functions.
Just don't think about CLJ at all while you're learning CLJS.
There are enough differences to make things painful when you know neither: https://clojurescript.org/about/differences (and this list is actually partial, it doesn't mention e.g. that allowed set! syntax difference).
Please, please, please learn the syntax of CLJS. It is incredibly basic compared to most other text-based languages.> Every such problem will vanish then. > The
ns form allows for very few variations, all trivial. def forms are also as trivial as it gets, defn not being too far behind.
I feel like I do understand most syntax other than those first lines (all within (ns _)?) I'm not sure what other syntax you mean I should learn. I learn how to use each new command/function (seriously what is the correct word for this? Is it really 'form'? EDIT: I see your message above. Function it is.) every time I reach for a new one.
I haven't had to change my ns expression yet except to add (:require react-dom). I'm not quite sure why I would sometimes need only that form but other times need to add :as ____, Is that simply to allow for shorter calls to things, or is it needed for calls to some things at all?> It's fine to start with looking for solutions in CLJS, but you don't need to persist when nothing pops up within a few seconds - just search for a JS solution instead. Once I get enough experience, I should write the guide I would myself have wanted to learn from but can't find. But yes, until then I guess I'll try to translate JS material. By the way, another reason I was trying to avoid that was in case there was something less Clojure-y or less functional to copying JS than I could otherwise opt for. But I guess it's mostly side-effects anyway for this stuff, so I shouldn't worry about that.
> I'm not sure what other syntax you mean I should learn.
You were confused about (.x y) and (.-x y) above, which is the most basic thing in interop.
I don't know what other syntax you don't know since you haven't asked about it yet. If it's only interop and ns forms that aren't known to you, you should still most definitely learn them.
> seriously what is the correct word for this? Is it really 'form'? EDIT: I see your message above. Function it is.
No, those specific instances were functions, because they're defined with defn. (Which is not the only way to define functions.)
There are also macros, like defn and let, that are defined with defmacro.
There are also special symbols, like let*, do, recur.
Stuff like (conj x y) is a function call, semantically.
But in general, stuff like (something ...) syntax-wise is indeed called a form. The problem with that word is that [] and "a" and 1 are also forms. A form is anything that the reader can read and return, a complete entity.
If you really want to have a separate word/phrase for (something ...) that doesn't focus on what something itself is, I'd probably still use "form" - usually the context is enough for the distinction. If it isn't, I'd use "a list form".
> I learn how to use each new command [...] every time I reach for a new one.
Just in case - by "learn syntax" I didn't mean learning the whole standard library.
> Is that simply to allow for shorter calls to things
When the thing you require is a simple symbol - yes.
In CLJS (well, at least with shadow-cljs, but probably in vanilla as well), separate things that you require might be strings that represent paths. Then :as or :refer are needed to be able to refer to that require by name, since a string is not a valid identifier.
As I mentioned, basic interop is trivial. I've already described above all you have to know in order to be able to listen for keyboard events and handle them.From what I've seen looking at the bit of JS code I have for dealing with keyboard inputs, it seems like there are multiple steps just to deal with a single key, but I'll take a look at the situation again tomorrow. Way late here now. Thank you again.
I can live with "list form". Halfway through reading that post of yours I was going to suggest "non-literal form", but both seem so clunky. There being no single-word term for a predefined word or structure that can operate on things (arguments/collections/etc) is pretty limiting.
Tomorrow I'll try to piece together the keyboard input suggestions, and take another look at the full story for (ns _) including :as and :refer. Cheers.
"predefined" in clojure is a pretty weird concept. as a lisp variant one of the main concepts is that everything can be implemented in normal code. even though it's rarely done with the primary clojure namespaces, it's all made via the same mechanisms your own code is made, apart from some weird things in the java impl that aren't used directly in top level code.
I was using "predefined" in the sense that it's something you get with a basic set-up of the programming language. I suppose I could have better put it as "part of the standard library"? (Would one say that "(conj ...)" and "(defn ..." and "[]" are part of the standard library, or is there a better way to say that?)
I'd say that, yeah.