Fork me on GitHub
#clojure
<
2022-01-27
>
Thierry08:01:24

Why can't I check if 1643273131567 equals a long? user=> (type 1643273131567) java.lang.Long user=> (= java.lang.Long 1643273131567) false user=> (= Long 1643273131567) false user=> (= long 1643273131567) false user=> (= 1643273131567 java.lang.Long) false

magnars09:01:00

(= java.lang.Long (type 1643273131567))

👀 1
Thierry09:01:58

Right, thanks! that works 🙂

👍 1
Linus Ericsson11:01:23

(instance? java.lang.Long 1643273131567) or (instance? Long 1643273131567) is probably what you are looking for.

Linus Ericsson11:01:20

(the function type also tries to look for at keyword :type in a clojure objects metadata map). The equal sign is not aware of heritage (maybe that's what you want). In the case of Long its java class is of type public final so in this case instance? vs (= Long (type ...)) would give the same result.

Thierry11:01:30

That looks better then converting it to a type first. I have C and Python background but am new to Clojure, hence the mistake 🙂

👍 1
quoll20:01:12

In Clojure, all numbers are either Long or Double. Clojure doesn’t use Integer, Short, Byte, or Float. The only reason you’ll see integers that are of type Integer, Short, or Byte is when you are using Java interop. So, when you’re in Clojure, you can anticipate integer values to all be long values, unless you happen to get a number given to you by a Java library.

👍 1
quoll20:01:32

What this means is that most of the time, you can use the int? function

quoll20:01:09

What does this do? Here is the implementation:

(defn int?
  "Return true if x is a fixed precision integer"
  {:added "1.9"}
  [x] (or (instance? Long x)
          (instance? Integer x)
          (instance? Short x)
          (instance? Byte x)))

quoll20:01:48

Those other types will almost never happen, and even when you get them, most operations will end up expanding them to a Long anyway

quoll20:01:29

user=> (def i (Integer. 5))
#'user/i
user=> (type i)
java.lang.Integer
user=> (type (inc i))
java.lang.Long

respatialized15:01:26

is there an easy way to convert from an existing regex pattern to a string that doesn't have escape sequences for the regex control characters? for example:

(.toString #"\n") ;; => "\\n"
(str #"\n") ;; => "\\n"
what I'm hoping for:
(something #"\n") ;; => "\n"

dpsutton15:01:41

“\\n” is a very different string from “\n”. And they will print quite differently. I think the toString is doing exactly what you want

manutter5115:01:16

Bear in mind that the REPL itself will escape special characters like \.

manutter5115:01:58

(map str (.toString #"\n"))
=> ("\\" "n")

dpsutton15:01:32

Keep in mind that control characters are not characters in the string but a type of metalanguage to enter special characters in the string. If you are matching newlines, you are looking for the one character “\n”. If you want a visual representation of that, you want two characters, a slash and an n. You can’t enter a slash in a string literal because that’s the character for the meta language. So to indicate you want one slash you use the string “//” which is a single character. So the string that is two characters, the first the slash \ and the second an n is the string literal "\\n"

respatialized18:01:28

XY problem: I'm looking to make the following expression work: (.endsWith "abc\n\n" (.toString #"\n\n")) ;; => false It appears as though the representation in the REPL of newlines doesn't explain the issue here.

dpsutton18:01:22

yeah i wouldn’t expect that to work in general

dpsutton18:01:02

the match of a regex isn’t really related to its string representation. Consider #"(.*a)+$"

dpsutton18:01:48

that does not have stars or dollar signs that it matches against and its string version is a bit misleading

manutter5119:01:20

Yeah, strings and regex patterns are different things, any match between them outside of the regex engine is more or less coincidental. But back up a step. Why do you want to make that .endsWith expression work? Maybe you could use something like

(boolean (re-matches #"(?s).*\n\n$", "abc\n\n"))
=> true
(boolean (re-matches #"(?s).*\n\n$", "abc\n"))
=> false
Forgive me if I’m just repeating stuff you already know, but I thought I’d take a guess in case you were having trouble matching the newline character.

respatialized19:01:14

The issue is that the regex pattern in question is not necessarily known in advance (it's an input to a pattern matching function I'm writing), and the regex needs to be handled differently based on whether it occurs in the middle of or at the end of the string it's found in. If there's some way I'm not aware of that lets me take an existing regex and "patch" it with the appropriate end of string control chars then I'm happy to do that instead and bypass this string conversion.

respatialized19:01:08

As far as I can tell regexes in Java largely seem to be a compile time thing, so I may need to step back and take a different tack with the problem I'm facing.

quoll20:01:24

No, they’re not compile time. You’re just looking at the reader macro which creates a regex as it’s read (ie. usually at compile time). You just need to get a string and create a regex out of it. This is what the re-pattern function does

quoll20:01:07

user=> (re-pattern "\\n\\n")
#"\n\n"

quoll20:01:26

In that case, the pattern contains 4 characters: \ n \ n The string representation needs the double backslash to tell it that a backslash character is needed

quoll20:01:30

incidentally:

r=> (.endsWith "abc\n\n" (.toString #"

"))
true

quoll20:01:16

That’s a string with 2 newline characters in it (represented with the escape sequence \n\n) and a regex with 2 newline characters in it

quoll20:01:34

> If there’s some way I’m not aware of that lets me take an existing regex and “patch” it with the appropriate end of string control chars then I’m happy to do that instead and bypass this string conversion. Regex patterns are immutable, meaning that you need to compile a new one out of a string. That can be done by extracting a string representation, adding the appropriate pattern, and then calling re-pattern. So if you have a regex like #"abc" but you need to match it to the “end of the string”, then you can say: (re-pattern (str #"abc" "$"))

quoll20:01:38

Or if you need to change it to "abc" followed by newline-newline, then: (re-pattern (str #"abc" "\\n\\n"))

pinkfrog15:01:20

Can I redefine a special form? E.g., redefine throw. Sounds like I couldn’t, but asking here to confirm

dpsutton16:01:30

You cannot.

pinkfrog16:01:16

Hi. What’s this syntax

(let [{:keys [::data]} m]
  (println data))
For the ::data part

dpsutton16:01:44

destructuring. (let [{:keys [::data]} {::data 1}] (inc data)) -> 2

Alex Miller (Clojure team)16:01:05

in modern times, I would instead do (let [{::keys [data]} m] ...)

👍 1
pinkfrog16:01:45

I changed to this and fails

user=> (let [{:keys [::data]} {:usesd/data 1}] (inc data))
Execution error (NullPointerException) at user/eval143 (REPL:1).
Cannot invoke "Object.getClass()" because "x" is null

dpsutton16:01:40

xslx-test> [::data :usesd/data]
[:metabase.query-processor.streaming.xlsx-test/data :usesd/data]

dpsutton16:01:52

auto resolved keywords resolve their namespace in the current namespace when using ::. so ::data -> current-ns/data versus :usesd/data would have a namespace of usesd

pinkfrog16:01:39

Which means for {::keys [data]}, the passed in map must have keys right in the same namespace.

Alex Miller (Clojure team)16:01:41

keyword support in :keys destructuring existed specifically to support :: autoresolve keywords, but you can now get that same support on :keys itself, and that's preferable b/c then you are naming the locals that are being bound

Nom Nom Mousse16:01:41

I want to add started processes (`java.lang.ProcessImpl`) to an atom: (def running (atom [])). ProscessImpl change state. Are there any gotchas when adding a mutating object to an atom?

emccue16:01:39

atoms are meant to store immutable data

Nom Nom Mousse16:01:13

If this is bad practice, how else can I keep track of running processes? Surely not a (def running2 []).

emccue16:01:35

that would be okay

emccue16:01:45

and then you conj on processes

Alex Miller (Clojure team)16:01:08

the vector is immutable here - I think you're probably ok with an atom

emccue16:01:20

its just that if you do this

(swap! processes (fn [process] (.someMethodThatMutates process)))
Then you will run into issues

emccue16:01:43

since an atom swap! can retry arbitrarily

Alex Miller (Clojure team)16:01:00

it's retrying the change to the vector though, which is immutable, and that's fine

Nom Nom Mousse16:01:00

Hmm, the reason I want to have a handle on them is that I want to be able to kill them.

emccue16:01:02

so make sure you are just operating on the container and not the inner mutable objects in a swap

emccue16:01:33

you can deref the atom, kill all of them, then swap to remove the ones you killed

emccue16:01:38

but you are responsible for how you kill them in a multi threaded context

Nom Nom Mousse16:01:44

I guess I can pop from the atom and kill the popped ones. But thanks for the help both of you 😄 .

emccue16:01:58

(do you lock on each process before killing?, etc)

Nom Nom Mousse16:01:17

Do you have any keywords I can search to understand what can happen when killing in a multi-threaded context? These are processes, not threads, but I guess multiple threads in my app might potentially refer to the same process. I'll just try to do it the naive way and see if it works.

jmckitrick22:01:37

Is there any good reason not to use CLJS and to stick to CLJ and server rendered pages for a CRUD app? After quite a few re-frame and reagent apps, I’m thinking of going pure server side, but I don’t want to paint myself into a corner. The app is a dashboard of tables and forms for updating entries. Most of the business logic is in scheduling and calling out to another system.

bridget22:01:31

I have done this multiple times to good ends. If you're not doing anything complicated/don't need React in the UI, you might be more efficient with just CLJ on the server.

bridget22:01:15

By more efficient, I mean productive and quicker dev time

jmckitrick22:01:54

That’s a really good point. As easy as CLJS makes it to do AJAX and React, it’s still a lot of overhead wiring things up.

jmckitrick22:01:55

In your experience, what are some features that would require React and/or AJAX? The first things that come to mind are partial page refresh and async or live search, etc.

jeff.terrell22:01:31

I just switched back to server-rendered pages, and for this app at least, I'm glad I did. I have about 80 lines of Javascript providing some dynamic functionality, and so far that's been a better approach than using CLJS. So I'd say go for it. 👍

jmckitrick22:01:43

I’ve just been defaulting to re-frame because it’s so powerful and flexible, but that is overkill, and not a good reason to choose a tech.

jeff.terrell22:01:36

:thinking_face: I guess I don't know of anything that would require React/AJAX. It's really just a question of how complex the dynamic page functionality is. At a certain point, the complexity of CLJS/React/whatever tooling becomes worth it because of the headaches and friction saved.

bridget22:01:47

My personal experience choosing CLJS/React has only been when end users needed rich clients... lots of data manipulation ahead of calls to the server. But I'm generally not a UI person, so my perspective is limited.

1
jmckitrick22:01:12

I almost think we’ve just come to expect pages to have that functionality, even if it isn’t required. This new app I’m starting I’m looking at my notes and everything I need just for a basic table: web service on the back end, front-end calls to the service, rendering the view, managing state, etc.

jeff.terrell22:01:25

I've really enjoyed in this current project not having to do as much shuffling of data between backend and frontend. My last re-frame app was fun, but there was quite a bit of boring data transformation code just to get data in the right shape for the frontend.

jmckitrick22:01:24

Yep, that’s true. I think I’m convinced. Especially since I have several things on my plate right now and efficiency and speed are paramount.

mjw23:01:51

I've been predominantly a front-end dev for the past 10+ years, and single-page apps definitely are used more often than they need to be. If you have a lot of complicated user interactions or UX requirements, need to maintain a lot of state in the UI, and have developers who are capable enough to maintain the additional complexity over time, then using something like React will possibly pay off in the long run. If, however, most of your data is read-only and there are only a few limited use cases where a rich, interactive UI is truly beneficial, then there is absolutely nothing wrong with a server-rendered app that uses the native DOM capabilities where necessary to add extra interactivity to the UI.

jmckitrick23:01:13

I think I’m going to go for it. Server-side only, that is. My second and last big decision for now is selmer vs hiccup. Thoughts?

jmckitrick23:01:22

The nice thing about client side apps and SPAs is I rarely need to touch raw html.

seancorfield23:01:25

@U061KMSM7 I'm a big fan of Selmer for SSR app because you have an HTML page that you can edit with syntax support from your editor (mostly) and if you need to tweak things, you can edit the HTML template while the app is running in dev and it will pick up the changes automatically with needing to worry about app state etc.

upvote 1
seancorfield23:01:16

For us at World Singles Networks, having our emails and our SSR pages in Selmer templates allows designers to work with them much more easily. Hiccup would make that virtually impossible.

jmckitrick23:01:07

Good point. As a one-man consultant, I like the appeal of hiccup and styling elements with bootstrap or bulma, etc.

jmckitrick23:01:28

I want to clearly understand, though, what difficulties I could run into with that approach.

jmckitrick23:01:23

I’m starting to think already that I’d have to write wrapper functions or macros for the basic html structure outside the body. That might be a lot of work.

jmckitrick23:01:55

Simply copying html pages as needed (or nesting them) might be the way to go.

jeff.terrell23:01:22

Nah, you can easily have one (or more) base views that you plug a body into. Hiccup data and functions make this really natural.

jmckitrick23:01:23

The clojure shop I’m at now using templates for some parts that aren’t react enabled, and it seems pretty scalable and slick.

jeff.terrell23:01:10

The main pain point I hit with hiccup was, coming from markdown, it's pretty tedious to have to stop your string, start a new [:em] tag or [:code] tag or whatever, and get back to your string.

seancorfield23:01:17

Having Selmer templates means that you can often check the HTML using "standard" tooling. I tried using Hiccup but it's just an uphill battle for anything larger than small bits of embedded data. And, yeah, the parent/child block stuff in Selmer allows for a huge amount of reuse -- at the expense of losing the ability to process pages with "standard" HTML tooling.

jeff.terrell23:01:38

...So I wrote this:

(defn md
  "Convert a string with markdown style inline formatting into hiccup data where
  underscore-, asterisk-, and backtick-delimited strings are converted to their
  appropriate HTML tag. Assumes no nesting of such strings."
  ([str] (md :p str))
  ([tag str]
   (letfn [(chop<> [str]
             (let [n (count str)]
               (subs str 1 (- n 1))))]
     (let [regexp #"[^_*`^]+|_[^_]+_|\*[^*]+\*|`[^`]+`|\^[^^]+\^"
           pieces (re-seq regexp str)]
       (apply vector tag
              (for [piece pieces]
                (case (first piece)
                  \_ [:em (chop<> piece)]
                  \* [:strong (chop<> piece)]
                  \` [:code (chop<> piece)]
                  \^ [:sup (chop<> piece)]
                  piece)))))))

1
jeff.terrell23:01:16

I loathe writing HTML when I can write hiccup or markdown. If I had designers I was working with, I might choose Selmer, but not if it's just me (and maybe other devs).

seancorfield23:01:25

We've "converted" our UI/UX designer to working with Selmer templates and he loves the block reuse stuff (to the point where I have to think very carefully about his templates whenever I work on them! 🙂 ).

jmckitrick23:01:49

@U056QFNM5 I’m in the same position you are, but I’ve become exposed to Selmer templates and I’ve been impressed. I hate leaving Clojure for any other coding as well, lol. But @U04V70XH6 is making a compelling case.

seancorfield23:01:20

(`markdown-clj` is from the same author as Selmer itself)

jeff.terrell23:01:00

Cool, yeah, go with whatever works for you. And I'm reluctant to be arguing against Sean. simple_smile But the only "standard tooling" I use for HTML is the browser, so I don't feel like I'm missing anything with Selmer. shrug Maybe I should look before I dismiss it, but I'm happy with hiccup.

jmckitrick23:01:07

@U04V70XH6 I like that idea of tweaking the html and reloading the page without worrying about app state. What was that part about parent/child blocks in Selmer? Are you for or against them?

jmckitrick23:01:51

@U056QFNM5 I’ve done almost exclusively hiccup on front and back end until recently, so this is new to me as well. I’m looking for fastest dev time on this side project. Since I’ve learned Selmer at work, I can do server side only and dramatically simplify this new app.

👍 1
seancorfield00:01:16

@U061KMSM7 parent/child blocks are useful for reuse, for example an HTML wrapper can be written once and then content pages can just reuse it and supply their own body, but they can be overused (just like inheritance!) and make it hard to reason about the finished page.

seancorfield00:01:16

In addition, the block markup isn't recognized by HTML editors etc so you won't get assistance about HTML5 compliance or whatever, and you can't use "HTML linters" etc with them.

seancorfield00:01:31

So I'm vaguely for them in moderation 🙂

jmckitrick01:01:30

Ok, cool. I’ll try to keep it simple, with a base template and a content block that’s replaced, not much more complexity than that.

jmckitrick12:01:16

Any suggestions on modern websites with minimal client-side coding? I need some ideas for a modern look and feel after years of writing SPAs.

mjw13:01:11

A lot of news sites (I think) are still built with mostly server-side rendering. Basecamp still use RoR for most of their heavy-lifting, but also have a TypeScript-based framework that they use to add functionality to server-rendered HTML when they need to. I'll see if I can find more examples.

jeff.terrell14:01:09

There's always Boostrap. I've heard that kids these days are using Tailwind. I'm kind of a minimalist myself, so I actually wrote my own decent looking template. It's really not hard with flexbox these days. (And check out Flexbox Froggy if you want to learn it.)

mjw15:01:05

If you're interested in continuing your front-end learning, now's also a good time to learn/experiment with CSS grid. https://ishadeed.com/articles/ has some nice articles on this.

jmckitrick14:02:32

@U04V70XH6 For the record, I went with server-side and selmer. Wow, I’m glad I did. And here’s why: 1. Huge reduction in complexity (client/server communication, build tooling, etc) 2. Very fast feedback (refresh of a page recompiles code, of course) 3. Killer feature: filters in selmer

1
👍 1
seancorfield16:02:36

@U061KMSM7 Yeah, all our marketing emails are built with Selmer and the business folks have learned how Selmer works so they can do all sorts of stuff with the data available to them. We store email templates in the database in a dozen languages and engineering almost never has to tweak any of the email system since business have full control of the content 🙂

❤️ 1