Fork me on GitHub
#clojure
<
2022-04-08
>
slipset07:04:21

So, walking around in the Clojure source code with my foot gun, I saw clojure.lang.PersistentVector/adopt which seemed to be exactly what I was looking for. Until it wasn’t. Because it doesn’t “work” for arrays containing more than 32 elements. Thanks to @chris441 and his work on speeding up json and csv parsing I’ve become aware of clojure.lang.LazilyPersistentVector/createOwning which does The Exact Right Thing(TM) But the question still remains for me, why do we have adopt? A quick grep through the Clojure source seems to indicate that it’s not used?

p-himik07:04:15

It used to be used by Clojure itself, for tuples. Now Clojure doesn't use tuples anymore, and the implementation has changed dropping the need for adopt. But the functionality is still there to avoid breaking potential code that uses it.

p-himik07:04:46

Correction - Clojure does use tuples, but in a very narrow context, and just as a class with static methods that end up creating vectors. And looking at the dates, I'm not actually sure why the relevant functionality that was created and then abandoned in a week wasn't completely removed, given that some other functionality co-located with it was removed. Maybe just a forgotten piece of code.

slipset07:04:07

Perhaps it would be reasonable to let adopt delegate to LazilyPersistentVector/createOwning ?

p-himik07:04:30

Why? It does what it was designed to do. It sounds like you simply don't need that method at all.

slipset07:04:54

Well, yes it does, until it doesn’t. Like it seems to work when you test with smaller collections, and then exceptions starts being thrown once you’re over 32 items in your collection.

p-himik07:04:19

Because it wasn't designed to work with larger collections. :)

slipset07:04:01

I guess we’re into the age old gigo discussion 🙂

slipset08:04:43

And it’s fair that it wasn’t designed for larger collections, but it doesn’t state that in any way, and you have to bang on it to figure it out, right?

slipset08:04:02

And of course, you could consider spelunking around the clojure sources with a foot gun is not something one should do, and that adopt should be considered an implementation detail. I get that.

p-himik08:04:02

> but it doesn’t state that in any way Right, because it's not public API. So there be dragons. > you could consider spelunking around the clojure sources with a foot gun is not something one should do I recommend at least adding git blame or something similar to your foot-shooting arsenal. :) It helps clear out many things.

Alex Miller (Clojure team)12:04:45

If you look at our dirty laundry, it might be messy. This is all internal stuff that you shouldn't use directly. BUT if you have a use case where you want to do something you can't, that's a great reason for an ask Clojure question

slipset13:04:55

I’ll refrain from bringing my foot gun the next time I walk into someones dirty laundry 🙂

emccue15:04:32

Maybe a package private Annotation should be added to signal parts of the interface that are there for backwards compatibility

James Amberger11:04:52

I’m trying to port a shell script. What should I do if I need to yield the terminal to an interactive program/command?

1
👍 1
enn12:04:11

the tldr was:

(-> (ProcessBuilder. ["/some/command"])
    (.inheritIO)
    (.start)
    (.waitFor))
and this works for me for basic readline-type interactive subprocesses, but I never got it to work fully for commands that use the terminal in more sophisticated ways (specifically, Emacs)

plexus13:04:37

A terminal is more than stdin/stdout. There's also a tty device involved. Some cli tools will want to deal with this tty directly through the ioctl syscall.

James Amberger13:04:35

Thanks all. These should definitely cover me

James Amberger13:04:01

> basic readline-type interactive subprocesses,

quadron12:04:41

how to turn a lazy sequence to a core async channel?

p-himik12:04:01

Note the docstring: > If accessing coll might block, use to-chan!! instead

quadron12:04:18

what if it's infinite?

quadron12:04:41

ok gotta enter the loop again

p-himik12:04:33

Then you should create a channel yourself with a buffer of the right size and use it with onto-chan!.

p-himik13:04:23

What "what"? :)

p-himik13:04:34

When you can't tell how large your input is, Clojure can't tell that either. That's exactly why buffers of different kinds exist, to implement different strategies of dealing with data that comes faster than it can be processed.

quadron13:04:57

how large is a river?

p-himik13:04:15

Exactly - when you can't tell how large it is, and yet you need to keep getting water, you have to figure out the size of a barrel and how many barrels you need.

quadron13:04:03

why would I do things I can't?

quadron13:04:45

ok, ima dew it

quadron13:04:50

how does this look to you:

quadron13:04:15

(manifold.stream/->source (repeatedly rand))

p-himik13:04:13

If you're already using manifold, then sure, why not. Note that it will be (I think, judging by the source) equivalent to just using to-chan!. I should add to my messages above about buffers and limits - just using to-chan! with an implicitly created channel is alright when you want to process elements on "as needed" basis, without looking ahead. Because (chan) will have no buffer - any put! will wait for a take!.

✔️ 1
quadron13:04:48

ah, thanks, to-chan! is what i was looking for

👍 1
Nom Nom Mousse12:04:04

Is there a way to get a string as a file object with the string as the contents in java?

(print (slurp (StringIO "abc"))) ;; outputs abc

Nom Nom Mousse13:04:03

(with-open [r (io/reader (char-array "hello"))] (slurp r))

Joshua Suskalo13:04:14

Yeah, so readers can have contents, file objects don't have contents though, you can think of them like just storing a file path. You could make a temporary file and store the contents in it and then the file object would "contain" those contents. But the reader way that you've done is better.

thheller20:04:13

(slurp (io/file "your" "file.txt"))?

dpsutton15:04:09

Does anyone ever find they want to use transduce not for the xform arg, but for a reducing function which can have a completion step?

Augustus16:04:05

Yes. I first saw this in the kixi library readme (https://github.com/MastodonC/kixi.stats) but have since used it occasionally

Joshua Suskalo16:04:28

I usually just use a -> with reduce honestly. I think the main purpose of actually using transduce for it would be if your reducing function was stateful.

Joshua Suskalo16:04:32

it could be nice for reducing functions provided in a library though to keep the two conceptually linked steps together

dpsutton16:04:15

yeah. I just like that completion arity. I think racket has some good stuff around this

kwladyka21:04:11

Probably it can be useful for async, but I use it very rarely and I am always not sure if it is good choice