Fork me on GitHub
#clojure-dev
<
2020-07-31
>
vlaaad06:07:05

Shouldn't Clojure have some reader macro to requiring-resolve symbols? That way we wouldn't have to use resolve-fns like in clojure.core.server for every function that might be invoked both from code and from clj -X:alias

Alex Miller (Clojure team)12:07:27

We’ve slowly working towards making vars effectively do this

Alex Miller (Clojure team)12:07:59

So if you read a var quote it would resolve locally and be invokable. We now do this for serialization of vars but haven’t yet made the reader change but I have it prepped in a ticket somewhere

vlaaad12:07:26

ah, that’s wonderful

Alex Miller (Clojure team)12:07:00

A very slow motion plan, maybe will come to fruition in 1.11 :)

🤞 3
vlaaad06:07:59

Ah, they are read by edn, macro wouldn't work

vlaaad06:07:57

Problem statement: clj -X:alias puts a requirement on entry-point functions to be able to accept only edn-read data, thus making their use both from code and from entry point clunky if they are designed to accept non-data as arguments.

cgrand08:07:33

What do you mean by non-data? A resolved symbol (var or class or static field)? I think it’s a niche usage and you can work around it by having your own generic caller -X:call that will perform any resolution you wish before calling your actual target.

vlaaad08:07:28

functions, for example

vlaaad08:07:44

I think it’s super common to configure functions with other functions. It would be nice if I didn’t have to invent 2 different APIs for the same thing because one useful context of invoking my code has no way to pass a function

vlaaad08:07:35

For example, -X (both in deps.edn and on the command line) could use reader tag val that does (comp deref requiring-resolve) … That would not compromise on simplicity — it’s still just edn data — and will help library authors to not complect their code with resolve-fn -s

seancorfield07:07:12

What is "non-data" @vlaaad? I'm not sure that even makes sense...

seancorfield07:07:33

And these are not "main" functions. -main accepts a sequence of strings. -X is for regular Clojure functions, which, last I checked, accept regular Clojure data... which is what you get from reading EDN... what am I missing?

vlaaad07:07:58

I want to create a function for people to use both as main and from code

seancorfield07:07:21

Why? What problem are you trying to solve with that?

seancorfield07:07:48

You can already invoke -main functions via the -m argument to clojure.

seancorfield07:07:21

-X is a way to invoke additional functions -- non-main functions.

seancorfield07:07:06

-m lets you invoke -main functions with strings. -X lets you invoke non-main functions with data.

seancorfield07:07:23

Yeah, I've read it. Several times.

vlaaad07:07:24

-X is entry point

vlaaad07:07:32

it's a main

seancorfield07:07:40

No. Not a "main".

vlaaad07:07:44

a different kind of main

vlaaad07:07:56

okay, we have slightly different definitions of main

vlaaad07:07:07

let's stick to entry point

seancorfield07:07:13

-X lets you invoke any function -- even private ones -- with data.

vlaaad07:07:16

both -X and main are entry points

seancorfield07:07:25

No. You're wrong.

seancorfield07:07:46

You think there's a problem here because you're starting from an incorrect set of assumptions.

vlaaad07:07:21

why -X is not an entry point?

vlaaad07:07:50

Alex's post literally says that...

seancorfield07:07:14

"entry point" just means you can call any function. You're ascribing too much significance to that.

seancorfield07:07:28

-main != "entry point" in this case.

seancorfield07:07:16

Also bear in mind that -X allows you to call your -main function with strings from the command line (with appropriate quoting) -- this is a more general feature, based on Clojure-is-about-functions-and-data. -main is the old-school world of command-lines-are-strings thinking.

seancorfield07:07:59

(it's 1 am here -- I'm off to bed!)

vlaaad07:07:12

no, -X does not allow to call -main, because it will pass it a map, when -main expects a seq of strings

seancorfield08:07:55

-X passes a single argument -- not just a map. It can pass a string. -main expects zero-or-more strings. Sorry, just had to test that before I could go to sleep:

(! 1024)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args "test"}}}' -X:foo
"test"
(! 1025)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args [1 2 3 4]}}}' -X:foo
[1 2 3 4]
and if it's a keyword in the :args it treats that as an alias to other data:
(! 1027)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args :bar} :bar [1 2 3 4]}}' -X:foo
[1 2 3 4]
and the [kvpath v]* args format supports associativity by index:
(! 1030)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args :bar} :bar [1 2 3 4]}}' -X:foo 1 :a
[1 :a 3 4]
(OK, now I can actually go to sleep!)

Alex Miller (Clojure team)12:07:56

Disagree on the top here -X should pass only 1 map to a function (that this works here is a bug)

vlaaad07:07:33

good night 🙂

seancorfield07:07:38

Oh yeah... It's almost a superset. It's certainly a more general feature tho'...

seancorfield07:07:44

And good night.

seancorfield08:07:55

-X passes a single argument -- not just a map. It can pass a string. -main expects zero-or-more strings. Sorry, just had to test that before I could go to sleep:

(! 1024)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args "test"}}}' -X:foo
"test"
(! 1025)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args [1 2 3 4]}}}' -X:foo
[1 2 3 4]
and if it's a keyword in the :args it treats that as an alias to other data:
(! 1027)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args :bar} :bar [1 2 3 4]}}' -X:foo
[1 2 3 4]
and the [kvpath v]* args format supports associativity by index:
(! 1030)-> clojure -Sdeps '{:aliases {:foo {:fn clojure.core/prn :args :bar} :bar [1 2 3 4]}}' -X:foo 1 :a
[1 :a 3 4]
(OK, now I can actually go to sleep!)

seancorfield08:07:39

So you could call -main if you only want to pass a single string 🙂

vlaaad08:07:08

Although I’m not surprised this works, I would expect it to be undefined behavior that we shouldn’t rely on :D

seancorfield08:07:47

That is an interesting question -- is this defined/supported behavior. Hopefully @alexmiller can comment on that tomorrow.

Alex Miller (Clojure team)12:07:45

It’s a bug -X should only invoke functions of 1 map

3
Alex Miller (Clojure team)12:07:10

It’s not a superset of clojure.main

dominicm12:07:37

I suppose ":arg" is a more appropriate name, with there only being one

Alex Miller (Clojure team)12:07:00

Well the idea is that it is a map of args

Alex Miller (Clojure team)12:07:16

Kv args, not positional

seancorfield16:07:02

Thanks for the clarification @alexmiller -- but if it's really "Kv args" as opposed to positional, shouldn't it be calling the function like (f :k 42 :foo "bar")? If you want to make it clear that it really is intended to pass a single argument :arg would make more sense than :args (I agree with @dominicm on that).

seancorfield16:07:25

And given the intent is to call the function with just a single hash map, you probably want to enforce that before people start abusing it (exactly as I was doing, apparently, and in particular by using it to call -main with a single string argument)...

seancorfield16:07:49

And to @vlaaad: I was wrong and I apologize. We still disagree on "main function" as a definition I think but we agree on "entry point" and now it seems that they are disjoint features since you're not supposed to be able to use -X to call -main with a single string.

vlaaad16:07:13

No problem! It's hard to admit mistakes — you are a good strong person :)

3
vlaaad16:07:48

I didn't want to call -main from -X btw, just tried to come up with an api for my function that is accessible from both these entry points... And from code... All at the same time

seancorfield16:07:46

Yeah, now Alex has clarified the intent of -X it's clear they are disjoint entry points which is both good and bad. I think it means you're stuck with your cli in 10 lines approach to -main to allow calling into a common function.

vlaaad16:07:47

I'm currently at 5 lines already :rolling_on_the_floor_laughing:

vlaaad16:07:09

Gave up to simplicity of just edn

seancorfield16:07:47

At work we have a similar entry point -main in our namespace: we pass in the fully-qualified name of a function to call and positional string arguments that are then packaged into a single hash map in -main which then calls the fq function. Although we parse the string arguments and use them are configuration to start a system Component usually, and those fq functions accept a system map -- they can't quite be called via -X at this point.

seancorfield16:07:03

Deleting lines is always good 🙂

seancorfield16:07:28

The other place, I can think of, where Clojure already uses :fn / :args is for function specs and :args there is explicitly a sequence of arguments (it catches beginners out that even for single-argument functions you need s/cat) -- so I really do think the singular :arg would be better here (or something more indicative of this being a single hash map argument). But I know we can often bikeshed on names so I'll leave it at that.

Alex Miller (Clojure team)16:07:58

yeah, I am unswayed, not going to change

😸 6