Fork me on GitHub
#tools-deps
<
2020-10-01
>
deactivateduser05:10:33

Apologies if this has been asked & answered before (I did search, but couldn’t find anything relevant), but in recent versions (specifically v1.10.1.697) the following occurs:

$ clj -e '(println "Hello, world")'
WARNING: When invoking clojure.main, use -M
Hello, world
$
I understand that this can be “fixed” with clj -M -e '(println "Hello, world")' , but is that intentional?

practicalli-johnny08:10:38

It seems so. The -M flag is required when invoking clojure.main.

deactivateduser16:10:37

That seems like an unfortunate UX decision…

octahedrion08:10:46

yes! it's a bit annoying. version 1.11.1.1165 still requires -M to eval in order to avoid the WARNING: Implicit use of clojure.main with options is deprecated, use -M clj -M -e '(+ 1 2)' rather than clj -e '(+ 1 2)' in this case the warning comes across as scornful even though you've nothing wrong

practicalli-johnny08:10:38

Without the -M execution option, the clojure tool has to infer (guess) that clojure.main is the execution option to use. As there is more than one execution option to choose from, the tool designer has deprecated this inference approach, so an explicit option is used to tell the clojure tool should do. (-M, -X, -T, -P) Depreciation is a common first step in removing an approach to using a tool, API, library, providing a clear migration step. In future this inference may no longer work and should not be relied upon. The depreciation warning has been presented for a relatively long time now, so surprised that the clojure tool is used without specifying an execution option.

octahedrion09:10:15

yes the warning makes sense from the tool designer's point of view

practicalli-johnny09:10:45

I am only a user of the tool and it makes sense to me. I appreciate the deprecation warning approach and updated my use of the tool after first seeing this useful warning message.

👏 1
Alex Miller (Clojure team)13:10:34

yes, all invocations of clojure.main should now be routed through -M

borkdude13:10:28

even when $ clj -- -e '(+ 1 2 3)' which is quite unambigious?

Alex Miller (Clojure team)13:10:10

it's unambiguous now but we're trying to open up arg space for repl execution

deactivateduser16:10:12

It seems to me that evaluation of a something provided on the command line should be considered at the same level of importance as running a REPL or invoking a main function, FWIW.

Alex Miller (Clojure team)17:10:17

expression eval is done by invoking clojure.main. -M is how you (now) invoke clojure.main.

vlaaad17:10:41

How are we going to invoke clojure.main in the future? :)

vlaaad17:10:41

Ah, I misunderstood your previous message

Alex Miller (Clojure team)17:10:13

yeah, I meant vs previous, not vs future

👍 3
Alex Miller (Clojure team)17:10:43

clj was originally built solely around clojure.main. we are in the process of making it bigger than that and this is part of segmenting off that part of the functionality.

deactivateduser18:10:05

I understand the improvements that brings to the implementation, I’m more making a comment about the (negative, imho) UX that creates, especially for newcomers.

deactivateduser18:10:47

i.e. why should a newcomer have to know that in order to evaluate an expression on the command line, they are actually invoking clojure.main? That seems like incidental complexity to me…

deactivateduser18:10:10

To non-Java/Clojure folks, clj is clojure.main.

Alex Miller (Clojure team)18:10:27

I don't think evaluating an expression on the command line is actually a thing most people do compared to running a repl

deactivateduser18:10:45

Sure, but that doesn’t mean that CLI evaluation isn’t worth supporting in a clear and concise (and backwards compatible, though I know we’re in a period of time where that is being consciously and deliberately broken) manner.

Alex Miller (Clojure team)18:10:21

is your complaint about the warning message mentioning clojure.main?

Alex Miller (Clojure team)18:10:20

ok, then what is the complaint?

deactivateduser18:10:36

My complaint is why does anyone need to know they’re invoking clojure.main in order to evaluate something on the command line. Shouldn’t this be a “first class” operation, regardless of how it’s implemented under the hood?

deactivateduser18:10:03

After all that’s how most other languages handle this - Principle of Least Surprise etc. etc.

$ python -c 'print("Hello, world")'
Hello, world
$ perl -e 'print "Hello, world"'
Hello, world
etc.

Alex Miller (Clojure team)18:10:45

ok, thanks for the feedback

👍 3
deactivateduser18:10:01

And to be clear, I don’t do this all that often, but it is a handy feature (e.g. in shell scripts).

Alex Miller (Clojure team)18:10:45

the most common use of it that I'm aware of is to trigger deps loading without doing something else, which you can now do with -P

deactivateduser22:10:13

Sure, but -P won’t evaluate an arbitrary expression. I like to (println a specific message to make build log searching easier.

borkdude18:10:00

> I don't think evaluating an expression on the command line is actually a thing most people do compared to running a repl I do this all the time on the command line

borkdude18:10:56

-M -m -M foo.clj -M -e, don't know if I can get used it ;)

borkdude18:10:41

A lot of things I do in my open source projects is testing out command line applications which are usually one shot. Yes, I also use a REPL, but actually more often I execute one time invocations

borkdude18:10:49

let me just do a zsh history thing

Alex Miller (Clojure team)18:10:14

(note new -P to prepare deps w/o executing, which is one prior use case for -e)

borkdude18:10:17

ok, I wrote this horrible script now:

#!/usr/bin/env bash

history | bb -iO '(->> *input*
                  (map #(as-> % x (str/trim x) (str/split x #"\s+") (rest x) (take 2 x)))
                  (keep #(when (and (str/starts-with? (first %) "cl") (second %) (> (count (second %)) 1)) (subs (second %) 0 2)))
                  frequencies (sort-by second >) (take 10))'
["-A" 326]
["-S" 208]
["-e" 172]
["--" 79]
["-M" 76]
["/t" 30]
["-J" 22]
["-m" 18]
["-X" 12]
["-R" 8]
which indicates I use -e way more often on the command line

borkdude18:10:36

but so far I haven't used -M a lot, usually -A

borkdude18:10:38

because instead of -m there's usually an alias for it. But with -e there isn't. So when invoking main directly, -e is my primary use case.

borkdude19:10:12

I think clj /tmp/foo.clj is also one of my primary use cases, this is where ["/t" 30] probably comes from

borkdude19:10:51

but because the filenames can change, it doesn't really show well here

seancorfield19:10:21

I just checked my history, my dot-clojure file, and my deps.edn at work and I almost never use -e without also using -m it seems. Just as a contrary data point to the above.

borkdude19:10:15

$ alias cljm='clojure -M'
$ cljm -e "(+ 1 2 3)"
6
it works

practicalli-johnny20:10:53

For my own brief experiences, I only every used -e once as a saw an example in the Clojure CLI docs. I am not aware of any use cases where I would want to evaluate clojure on the command line, especially if I can run the repl just as quickly. If I was going to script something with Clojure, then I'd try using Babashka, it looks great. I am fascinated as to what the scenarios could be for using the -e . If anyone has a link to examples, please let me know. The only thing I find a little strange is when running an application from the command line, eg. clojure -M -m namespace.main , from a usability point of view the -M looks a little redundant.. After thinking about this for a few days, I realize I don't actually run the application that way. I'll either run in the REPL or create a jar/uberjar and run it that way. I though about using an alias called :project/run that ran the unpackaged project, which I could include in a project template (eg. for clj-new), but not sure how valuable that would be. I find the -X flag more appealing (and more Clojurey) approach, as I've been writing command line -main functions to take hash-map as an argument for a while now. It seems an idiomatic approach to have all entry point functions in a project take a hash-map where possible.

dpsutton20:10:45

in fish i have these handy shell functions

function clj-doc --description 'Get the docstring of a function'
clj -e "(require 'clojure.repl)(clojure.repl/doc $argv[1])"
end
one clj-doc and the other clj-source. easy to update to -M -e though

👍 3
borkdude20:10:45

Well, sometimes I use -e to require some namespace or a compile invocation for example

borkdude20:10:47

No big deal, can be easily hidden in a script, Makefile or whatever, I just don't find -M -m aesthetically pleasing, which may not be an important argument. Whatever :)

lread22:10:34

For what it is worth, I am updating rewrite-cljc to use the new cli syntax, and updating from -A -m to -M -m is not causing me any terrible discomfort. simple_smile

😎 3
markbastian22:10:52

Out of curiosity, what is the purpose of the sourceDirectory tag addition in the pom target? I don't see where it is used by other mvn tasks and the clojure-maven-plugin puts the same data into its own config (which I realize is unrelated to tools.deps, but it's the only mvn plugin I can think of that is directly related to building Clojure). For example:

<build>
    <plugins>
        <plugin>
            <groupId>com.theoryinpractise</groupId>
            <artifactId>clojure-maven-plugin</artifactId>
            <version>1.8.4</version>
            <extensions>true</extensions>
            <configuration>
                <sourceDirectories>
                    <sourceDirectory>src</sourceDirectory>
                </sourceDirectories>
            </configuration>
        </plugin>
    </plugins>
    <!-- How does maven use this? -->
    <sourceDirectory>src</sourceDirectory>
</build>

deactivateduser22:10:40

Pretty sure Maven uses that to know where to go to build Java source. IOW it’s probably not relevant for a deployed artifact.

markbastian22:10:25

Ah, that makes sense - mixed language project.