beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
omendozar 2020-10-04T00:09:07.195300Z

Hi, can anyone explain the difference (syntax) between clojure.string$upper_case and clojure.string/upper-case ? ๐Ÿ™‚

seancorfield 2020-10-04T00:11:52.197Z

@orlandomr27 clojure.string$upper_case is the name of the actual class in the JVM bytecode; it indicates an inner class upper_case inside the string class in the package clojure; clojure.string/upper-case is a Clojure symbol that identifies the namespace clojure.string and the named Var upper-case.

seancorfield 2020-10-04T00:12:58.197900Z

Each Clojure namespace compiles to a JVM class in a package, based on the dotted name. Each Clojure function is compiled to a class (with methods invoke and applyTo).

omendozar 2020-10-04T00:13:34.198Z

I understand, thank you Sean ๐Ÿ™‚

omendozar 2020-10-04T00:15:36.198500Z

Which one is more efficient to call or there is no difference?

seancorfield 2020-10-04T00:16:04.198900Z

That question doesn't make sense to me.

sova-soars-the-sora 2020-10-07T19:18:09.480900Z

can personally vouch for sean's awesomeness as well ๐Ÿ˜„ super kind and ใใ‚ใ—ใ„ (ku-wa-shii)... detailed/ thorough

1๐Ÿ˜Š
seancorfield 2020-10-04T00:17:09.200Z

You call Clojure functions. What they're compiled to in the JVM isn't relevant really.

1
seancorfield 2020-10-04T00:17:55.200800Z

(ns some.thing
  (:require [clojure.string :as str]))
(defn shout [s]
  (str/upper-case s))

seancorfield 2020-10-04T00:18:21.201300Z

so (shout "Hello!") returns "HELLO!"

omendozar 2020-10-04T00:29:56.201500Z

I was thinking about calling a compiled code or code to be compiledโ€ฆ I guess it doesnt make sense ๐Ÿ˜„

seancorfield 2020-10-04T00:33:22.203500Z

Clojure compiles code "on demand" so the actual call is always compiled, and calls into compiled code.

seancorfield 2020-10-04T00:33:40.203900Z

It looks like an interpreted language but it isn't ๐Ÿ™‚

omendozar 2020-10-04T00:35:19.204100Z

Good to know that. Thank you!

seancorfield 2020-10-04T00:40:03.204300Z

I had never thought of calling Clojure functions via interop on their compiled classes but your question caused me to try it out:

$ clj
Clojure 1.10.1
user=> (require 'clojure.string)
nil
user=> (clojure.string$upper_case/invokeStatic "Hello!")
"HELLO!"
user=>

seancorfield 2020-10-04T00:40:32.204500Z

(this is why I always tell senior developers that they can learn from beginners!)

4๐Ÿ‘
2020-10-04T01:57:02.204900Z

Sean, I appreciate the time you take answering questions on here. Your open (m|k)indness is applaudable.

4
Faris 2020-10-04T05:26:15.206900Z

Hi, Iโ€™m testing out destructuring and Iโ€™m having a bit if an issue, I created a method like so

(defn destructuring-test [coll]
 (let [[x y z :as rest] [coll]]
    (str "x:" x " y:" y " z:" z "total:" (count rest)) 
  ))

(destructuring-test [1 2 3 4 5 6 7 8])
I expected to get
"x:1 y:2 z:3 total:8"
but what I get is
"x:[1 2 3 4 5 6 7 8] y: z:total:1"
Anything Iโ€™m doing wrong?

2020-10-04T05:54:24.207300Z

Replace [coll] with coll in the let

2020-10-04T05:54:54.207800Z

[coll] evaluates to a vector with one element, and the one element is itself a vector with 8 elements.

Faris 2020-10-04T05:58:50.209300Z

oh dear, it was so obvious now that you've said it, thanks so much!

Jim Newton 2020-10-04T12:30:20.211300Z

I'm not sure how to correctly ask this question. I suspect my question contains a wrong assumption. But what is the correct way to resolve a symbol which or might not be in a namespace?

vlaaad 2020-10-04T12:39:01.211500Z

https://clojuredocs.org/clojure.core/resolve

vlaaad 2020-10-04T12:39:12.211700Z

resolve?

vlaaad 2020-10-04T12:39:52.211900Z

Not very common function to use during development, what do you want it for?

Cameron 2020-10-04T12:41:14.212100Z

Based off his wording, I wonder if he might be trying to resolve a symbol normally if its 'visible' from his current namespace, else try to search through other namespaces in the project to get a var/class bound to that symbol somewhere, although I'm not sure

Jim Newton 2020-10-04T13:51:26.212700Z

@vlaaad, yes I already have puzzled over the documentation in https://clojuredocs.org/clojure.core/resolve but I find it lacking.

Jim Newton 2020-10-04T13:52:38.212900Z

I understand what a call such as (resolve 'x) means. it is the same as (ns-resolve *ns* 'x)

Jim Newton 2020-10-04T13:53:33.213200Z

but what does it mean to ns-resolve a symbol such as my-ns/x in a namespace other than my-ns ?

Jim Newton 2020-10-04T13:55:11.213400Z

There is more motivation of this question which I wrote in a closure-verse post: https://clojureverse.org/t/need-help-to-resolve-symbols-programmatically/6642. I put the posting there as I thought the discussion risked getting more involved.

Jim Newton 2020-10-04T14:02:20.214Z

Where is the documentation for &env ? what it contains etc...

Cameron 2020-10-04T14:05:56.214100Z

resolving my-ns/x is going to get you the var/class for my-ns/x no matter what namespace you're in

Jim Newton 2020-10-04T14:07:45.214300Z

@zdot101, I think you're right. That what I see by experimentation, However, that's not what the documentation says if you read it carefully. The doc for ns-find says the following:

Returns the var or Class to which a symbol will be resolved in the
namespace (unless found in the environment), else nil. 

Cameron 2020-10-04T14:09:09.214500Z

Note that if the symbol is fully qualified, the var/Class to which it resolves need not be present in the namespace.

Jim Newton 2020-10-04T14:10:02.214800Z

hmm. yes it says that indeed, which seems like a contradiction, not a clarification, of the previous statement.

Jim Newton 2020-10-04T14:10:20.215Z

So the doc doesn't actually say what happens to a fully qualified symbol.

Jim Newton 2020-10-04T14:13:31.215200Z

So what is the correct statement of what happens when a fully qualified symbol is given as 2nd argument to find-ns. I suppose the question is what happens in the 2 arg version and the 3 arg version of find-ns ?

Jim Newton 2020-10-04T14:15:07.215400Z

I have added a comment to https://clojuredocs.org/clojure.core/ns-resolve, can someone check it and tell me if what I've written is correct?

Jim Newton 2020-10-04T14:15:24.215700Z

I have added a comment toย https://clojuredocs.org/clojure.core/ns-resolve,ย  can someone check it and tell me if what I've written is correct?

Cameron 2020-10-04T14:16:28.215800Z

I'm trying to think on the best way to word this to show the subtle difference, but I don't take the first line to be saying the var or class itself has to come from the current namespace, just that its giving you the var/class that a symbol refers (resolves) to from the current namespace. And it so happens that ns/blah, from any namespace, refers to the var in ns with name blah

Cameron 2020-10-04T14:18:00.216100Z

Similar to how a phone works, where typing in 123-4567 resolves to (current-area-code)-123-4567 but typing in <tel:5551234567|555-123-4567> resolves to the same phone number no matter where you are

Jim Newton 2020-10-04T14:20:57.216300Z

and how is the given name space used for a symbol like clojure.lang.Symbol ? That's also not addressed in the documentation.

Darin Douglass 2020-10-04T14:21:54.217200Z

A blurb about &amp;env can be found here : https://clojure.org/reference/macros

1
Jim Newton 2020-10-04T14:22:43.217400Z

What does it mean to say "resolves something in a namespace"? Is this expression defined somewhere?

Jim Newton 2020-10-04T14:26:59.217700Z

clojure-rte.core&gt; (let [a 100 b 200]
     (defmacro xyzzy [&amp; others]
                    (println &amp;env)
                    nil))
#'clojure-rte.core/xyzzy
clojure-rte.core&gt; (xyzzy )
nil
nil
clojure-rte.core&gt; (let [x 100 y 200] (xyzzy))
{x #object[clojure.lang.Compiler$LocalBinding 0x2f6640f4 clojure.lang.Compiler$LocalBinding@2f6640f4], 
 y #object[clojure.lang.Compiler$LocalBinding 0x877bb0e clojure.lang.Compiler$LocalBinding@877bb0e]}
nil
clojure-rte.core&gt; (xyzzy)
nil
nil
clojure-rte.core&gt; 

Jim Newton 2020-10-04T14:27:19.217900Z

It seems to contain info on local variables at the macro call-site, not the macro definition site.

Jim Newton 2020-10-04T14:28:18.218100Z

Does this mean that multiple uses of a macro with the exact same arguments must be expanded multiple times, as the &amp;env might be different each time?

Jim Newton 2020-10-04T14:31:14.218400Z

If I understand this correctly, if I'm resolving a symbol to get a class, then it doesn't matter which namespace I use, so I can actually use resolve rather than ns-resolve ... the value of *ns* plays no role, even if the caller intentionally rebinds *ns* before calling my function.

Jim Newton 2020-10-04T14:32:04.218600Z

so my code is correct, regardless of what the namespace is bound to when my function is called.

(and (symbol? type-designator)
     (resolve type-designator)
     (class? (resolve type-designator)))

2020-10-04T14:41:16.222Z

I Believe that every macro call is expanded independently from all others. There is no caching of results based on parameter values, as your question seems to be hinting at

1
Jim Newton 2020-10-04T14:42:50.222800Z

More questions about resolve. If I define a function foo as follows

(defn foo [s] (&gt; s 10))
then (foo 12) evaluates to true, and so does ((resolve 'foo) 12) However, (fn? (resolve 'foo)) evaluates to nil, as (type (resolve 'foo)) evaluates to clojure.lang.Var. What is the correct way to figure out whether a given symbol results to something callable? I see also that (fn? #{:a 100}) evaluates to false.

micahasmith 2020-10-04T14:45:12.223100Z

maybe https://clojuredocs.org/clojure.core/meta ?

Jim Newton 2020-10-04T14:46:10.223900Z

Ahh I see, (ifn? (resolve 'foo)) evaluates to true. This is explained in the documentation of fn. https://clojuredocs.org/clojure.core/fn_q

Cameron 2020-10-04T14:46:20.224Z

> What does it mean to say "resolves something in a namespace"?ย Is this expression defined somewhere? I'd say its the general meaning of the word in programming (here's the first example I could find, albeit not the most formal: https://laracasts.com/discuss/channels/laravel/what-does-the-word-resolve-mean where you'll find, among the definitions, this not yet helpful line: it means when you find out the answer, or find a resolution. In this case, I'd say the resolution we're interested in is name resolution (https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)) ; to take a not-necessarily unique name and find what it actually intends to refer to. If I say 'Jim', there are lots of Jims but we can infer I'm talking about you right now. If I say 'Jim Jones', even though you're the Jim in the room right now we know I'm talking about someone else, as I've also last-namespace qualified this name wut (I realize I'm about to repeat myself, and I'm sure you know how this part works, but to be thorough:) If you're in a namespace and write "a", you intend to refer to a var or class either inside the current namespace, or referred into the current namespace with something like (ns blah (:require [other-ns :refer [a]])) or even (ns blah (:require [other-ns :refer :all])) Likewise, if you explicitly write out the namespace and everything as other-ns/a, we know you're flat out trying to refer to a var/class in that namespace other-ns, no matter what the current namespace is.

Jim Newton 2020-10-04T14:51:19.224500Z

Thanks for the well intended explanation Cameron, But when I say "what does it mean", i really mean what does the expression mean in the closure documentation. To resolve a symbol in Common Lisp has different semantics than in clojure, vs emacs-lisp, and I suppose in many different lisps. Plus, it seems that symbol resolution in clojure is very subtle, and it very often trips me up in practice. I can imagine it may be less confusing to people who have only ever used one dialect of lisp.

Cameron 2020-10-04T14:53:44.225900Z

ifn? should be misleading here, because all Var s are ifn , even if the value they wrap isn't.

core&gt; (def a 1)
#'core/a
core&gt; (ifn? (resolve 'a))
true

1โœ”๏ธ
Cameron 2020-10-04T14:54:14.226500Z

so instead it'd just be (ifn? a)

Jim Newton 2020-10-04T14:58:33.228700Z

yes. What if I write a function such as

(def is-callable [x]
  (or (fn x)
      (and (symbol x) (resolve x) (ifn? (resolve x)) ... )))
what should I fill in at the ... to distinguish between just a Var and a var designating a callable something?

Jim Newton 2020-10-04T15:01:07.229200Z

seems like (deref (resolve x)) gives me the function object.

Jim Newton 2020-10-04T15:01:16.229400Z

perhaps

Jim Newton 2020-10-04T15:01:50.230300Z

(def is-callable [x]
  (or (ifn? x)
      (and (symbol x) (resolve x) (ifn? (resolve x)) (ifn? (deref (resolve x))))))
???

Jim Newton 2020-10-04T15:07:04.230700Z

again, (resolve 'a) tries to resolve a in the current namespace. This might be dangerous, because the person calling my function might be rebinding *ns* to something different. I guess I'd like to resove in the namespace of the calling function. But that's asking for the impossible.

2020-10-04T15:13:41.232600Z

In your is-callable, any Var given to it will return true because of the first call to ifn? But maybe that is what you want for behavior here. Not clear to me what cases you are trying to distinguish

1โœ”๏ธ
Jim Newton 2020-10-04T15:53:26.232800Z

I'm trying to determine if it is a callable or a symbol designating a callable. perhaps it should be

(def is-callable [x]
  (or (fn? x)
      (and (symbol x) (resolve x) (ifn? (resolve x)) (ifn? (deref (resolve x))))))

Jim Newton 2020-10-04T15:54:22.233Z

Perhaps if I limit the logic of my program to demand a symbol, it will work better?

(def is-callable [x]
   (and (symbol x) (resolve x) (ifn? (resolve x)) (ifn? (deref (resolve x)))))

2020-10-04T16:04:53.236100Z

Note that it is technically possible for a Var to change value over time from callable to not-callable, or vice versa. Clojure programmers tend not to do so in most programs, though. I realize I may be pointing out the obvious here.

1โœ”๏ธ
2020-10-04T16:05:58.237500Z

The JVM object representing the Var returns true for ifn? Independent of its current value

1โœ”๏ธ
2020-10-04T18:33:52.237700Z

Example of things that can be done, but most Clojure programs do not do:

user=&gt; (defn f1 [x] (inc x))
#'user/f1
user=&gt; (defn f2 [x] (* 2 (f1 x)))
#'user/f2
user=&gt; (f2 5)
12
user=&gt; (def f1 5)
#'user/f1
user=&gt; (f2 5)
Execution error (ClassCastException) at user/f2 (REPL:1).
class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')
user=&gt; (alter-var-root #'f1 (constantly (fn [x] (println "got here") 75)))
#object[user$eval146$fn__147 0x25d958c6 "user$eval146$fn__147@25d958c6"]
user=&gt; (f2 5)
got here
150

2020-10-04T21:00:06.238500Z

Callable or not is not the same thing as throws an error when called or not