Fork me on GitHub
#clojure
<
2018-03-09
>
qqq00:03:46

1. I have heard great things about Smalltalk's runtime / everything is an object / messages everywhere development environment. 2. I never quite got into learning Squeak due to it's "designed to look like a Toddler toy GUI" 3. I feel like clojure dev can be more dynamic/connected than just emacs+cider+C-xC-e send to repl 4. So why don't we have 'more dynamic / interacting' tools? Is it: a. such tools exist, I'm unaware of it b. Clojure's not smalltalk; everything's not an object, so we can't build this or c. This ca nbe built, but no one has done so. The closest thing to mind is http://cloxp.github.io/ which appears to have not been updated for 2.5 years

the2bears01:03:09

I'm curious what you mean by "more connected"?

the2bears01:03:02

I'll take a look at the cloxp video, have not seen that one before.

qqq01:03:00

I feel more connected to my running CLJ program than to my running C/C++ program, because REPL. With C/C++, I can't just 'hook in', poke around, call functions, ... unless I'm using gdb. I believe Smalltalk's supposed to be "even more connected" in this sense, in that we have a running vm, we can poke around, write code, and execute stuff, in a way that is 'more direct' (sorry, can't formally define this) than Clojure.

qqq01:03:09

Or maybe I'm not properly utilizing the full power of the REPL.

seancorfield01:03:53

Having used Smalltalk (a bit), I don't really feel that there's much difference in "connectedness" compared to a REPL (assuming you are running everything via your REPL). Any code you evaluate affects the live image, just like in Smalltalk.

seancorfield01:03:00

The main difference is that there's a lot of "system" in Smalltalk (all the UI and browser objects etc) and you can query and interact with/update all of that from your "repl". And of course, Smalltalk can save its image to disk and restore it later -- so you can pick up where you left off -- which is pretty cool.

qqq01:03:53

@seancorfield: Let's use the work 'workflow' rather than 'connectedness' -- so is the main difference then that: 1. in smalltalk workflow, possible to redefine ide via smalltalk 2. in clojure workflow, not possible to redefine emacs ide via clojure besides that, in your opinion, there isn't much difference in the power of the workflows ?

the2bears01:03:25

Sounds a little like Nightcode maybe, where the IDE is actually part of the project's REPL, and thus has access to the running system. https://sekao.net/nightcode/

the2bears01:03:25

Very direct access, as it's part of the system.

seancorfield01:03:48

@qqq Yeah, I'd say if you were working in an editor that was also running in your REPL, you'd have the Smalltalk workflow -- but, really, how many people want to modify their editor while it is running? Oh, wait, Emacs users 🙂 /cc @the2bears -- Is Nightcode actually running in the same JVM and built with Clojure so it can all be modified on the fly? I didn't realize that...

the2bears01:03:15

@seancorfield I believe it is, from reading Zach's original announcement. I haven't actually tried it yet, though. Comfortable with emacs 🙂

xiongtx02:03:34

@alexmiller Probably been brought up long ago, but any reason macroexpand{-1} doesn't take an (optional) env parameter? IIUC the environment is essential to correct behavior of macroexpansion of macros that use &env. CL"s versions do have env: http://clhs.lisp.se/Body/f_mexp_.htm

tbaldridge02:03:43

@xiongtx in CLJ the environment is stored in the compiler's dynamic vars. Almost all the contents of the environment is specific to the compiler and is a bunch of private classes.

tbaldridge02:03:19

the only thing I've ever used it for is to see if a symbol is defined, and that works fine because the env is a map of {symbol, <some opaque compiler thing>}

xiongtx02:03:04

So you’re saying it’s unusual enough for macros to make use of &env that it wasn’t worth making the environment (which is compiler internal) public for macroexpand?

xiongtx02:03:28

I can 💰 that

tbaldridge02:03:32

it just not much use at all, if you wanted to though, you could always rebind that var to something else.

tbaldridge02:03:46

But there's not much point in any of it since &env is pretty rarely used

noisesmith02:03:29

one example of using &env explicitly that I use when debugging:

+user=> (defmacro locals [] (into {} (map (juxt (comp keyword name) identity)) (keys &env)))
#'user/locals
+user=> (locals)
{}
+user=> (let [a 0] ((fn [x] (locals)) 1))
{:a 0, :x 1}
+user=> (macroexpand '(locals))
{}
+user=> (let [a 0] (macroexpand '(locals)))
{}

tbaldridge02:03:13

@qqq that sounds a lot like Lighttable back before it was rewritten 3 times and then abandoned

mogenslund06:03:02

That is what I am trying to achieve with https://github.com/mogenslund/liquid . But maybe it lacks something else important, or is too hard or confusing to use?

Empperi07:03:42

hmm, it's been a long while since I last had to write a macro. I want my macro to puke try-finally block, but it doesn't compile on macro expansion stage if I have finally in place. Works fine without it. It complains that it cannot find finally. Ideas?

Empperi07:03:29

no need anymore, figured out my problem

Empperi07:03:34

just being stupid

Empperi07:03:40

had actually nothing to do with macros

qqq15:03:32

Are there any native Java APIs for handling MP4s, or should I expect to use FFMPEG wrappers? I'm trying to build something like: input: blah.mp4 output: sample 1 frame every second to a BufferedImage

qqq15:03:59

by "native Java APIs", I mean "pure Java", not "depending on native .dll/.so libraries"

the-kenny16:03:04

Calling out to ffmpeg here too. Note that ffmpeg allows you to use pipes for input and output, so you can stream both without having to hit the filesystem.

tbaldridge16:03:17

@qqq if you use anything but FFMpeg "you're gonna have a bad time"

tbaldridge16:03:12

Most OS level APIs are pretty bad and really restrictive. So you can look for wrappers, but most conversion utilities simply call out to ffmpeg and use pipes like @the-kenny suggested

qqq16:03:27

@the-kenny @tbaldridge: thanks, will use ffmpeg

marco_m18:03:16

Is there a way to use spec quickcheck with a function that throws ? Consider the following:

(defn hello [x]
  (if (zero? x)
    (throw (ex-info "Cannot hello by zero" {}))
    (inc x)))
and it's spec
(s/fdef hello
  :args (s/cat :x int?)
  :ret int?
If I run
(stest/check `hello)
I get a stacktrace because of the exception when hello is fed with 0, making quickcheck useless. Any suggestions ? Or the only functions that can be generative-tested are functions that don't throw?

the2bears18:03:02

@marco_m I think a custom generator here, avoiding the '0', will work. You might try #clojure-spec too, for better (more idiomatic) solutions.

hiredman18:03:47

that is a case of an error in the spec, right? because hello can't be passed 0 and the spec doesn't capture that information

Alex Miller (Clojure team)19:03:23

agreed with @hiredman - the spec should not have a generator that produces invalid inputs. spec is about what’s valid.

marco_m20:03:53

@the2bears @hiredman @alexmiller thanks for the answer. Yes, in the simple example I posted it is easy to add to the spec :arg itself that 0 is invalid. But imagine a real function whose job is to validate a big data structure in input, maybe the logic depends on some other parameters to the function and a lot of computation. Then if I want to follow the "the spec should not have a generator that produces invalid inputs" approach, it means that I have to put in the :fn part of the spec the body itself of my function, otherwise the generator will always generate invalid input, and I have the impression this becomes complicated very quickly. So no way out ? 🙂

Alex Miller (Clojure team)21:03:07

No. :). Fwiw, I have not run into this in practice. You can always create a generator that covers a valid subset and you could even filter it by whether it passed the spec.

marco_m21:03:05

Ok, thanks for the confirmation and for the suggestion!

Alex Miller (Clojure team)21:03:13

All custom generated values actually are checked for that already but I think it throws in that case, not filters

noisesmith19:03:20

it means that you tried to put an object in a macro expansion

noisesmith19:03:42

a macro shouldn't create objects then put them into a form, they should create a form that generates (or operates on) the needed object

noisesmith20:03:34

typically the erroneous code is something like

(defmacro foo [] (let [x (get-some-obj)] `(bar ~x)))

noisesmith20:03:24

the corrected code is

(defmacro foo [] `(let [x# (get-some-obj)] (bar x#))

artenator20:03:49

ahhhh thank you so much!

staypufd20:03:54

I posted a question in the Immutant channel about the messaging queues if anyone has time to help and has used Immuant messaging

staypufd20:03:02

Help greatly appreciated

kurt-o-sys20:03:38

I just want to know if I get it right with the tagged literals: if the reader sees a tagged literal, it calls a function and actually already evaluates that tagged literal (with args). This means, that during this read phase, one 'extends' the reader with custom literals that are evaluated, right? When we have macro's, well, they extend the compiler, or how certain forms are expanded during compilation. The extend the functionality of the evaluator by adding new forms, right? I may be utterly wrong, but is it wrong to say that tagged literals are to the reader what macro's are to the evaluator?

noisesmith20:03:51

yes, but they are much less powerful (on purpose)

kurt-o-sys20:03:56

yeah, I don't want to replace them. I was just wondering if I get it right with tagged literals are to the reader what macro's are to the evaluator. If so, well, it is easier in my mind and to explain to others 😛

Alex Miller (Clojure team)21:03:04

Tagged literals actually only read (not evaluate) the value then evaluate the data reader function with it. They do not provide a way to read arbitrary strings as data - they still take data as input. So they are in some ways a little like macros, I guess.

Alex Miller (Clojure team)21:03:35

They don’t have repetitive expansion that macros do though

kurt-o-sys22:03:40

No, sure not. But they 'expand' some input to a data structure (read phase). Macro's expand a data structure to another structure/code (compile phase). Conceptually, they look a bit similar, but on a different level/in a different phase.

qqq22:03:04

Is there a list of all -> ->> variants somewhere? (especially the conditional ones). I feel it's time I start memorizing wht is builtin.

noisesmith23:03:55

Clojure 1.9.0
+user=> (apropos #"->>?$")
(clojure.core/-> clojure.core/->> clojure.core/as-> clojure.core/cond-> clojure.core/cond->> clojure.core/some-> clojure.core/some->>)
or a repl (edited .. .again)

noisesmith23:03:04

I mean, there's noise in there, but it works - fixed it with a regex

qqq23:03:14

so the full list s:

as->
->, ->>
some->, some->>
cond->, cond->>
anything else

noisesmith23:03:22

that's all that's built in

noisesmith23:03:43

there's also find-doc

noisesmith23:03:56

(for finding things by keywords in docs that is)