(source) in Clojure giving "not found" for REPL-defined functions [duplicate] - clojure

This question already has answers here:
How can I display the definition of a function in Clojure at the REPL?
(5 answers)
Closed 7 years ago.
I defn a function in a REPL. The function works fine and all is well. But my REPL window is small and after exercising my function for a while I wanted to just look at the source. There is a source function, great. But wait...
(defn print-seq [s]
(when (seq s)
(prn (first s))
(recur (rest s))))
=> #'user/print-seq
(source user/print-seq)
Source not found
=> nil
What went wrong here? (source source) works fine, so its not that I can't execute source. There's something I don't get here. Please explain.

Quoting the documentation:
Prints the source code for the given symbol, if it can find it.
This requires that the symbol resolve to a Var defined in a
namespace for which the .clj is in the classpath.
Functions defined in the REPL don't have an associated .clj file in the classpath.
If you want to verify this, consider reading the output of (source 'source-fn); on its face, this function works if and only if there is a .clj file in the source path.

Related

What does the - (minus) symbol in front of function name within Clojure mean?

I can't get my head around the following. When defining the main function in Clojure (based on code generated by Leinigen), there's an - symbol in front of the function name main.
I went to the original documentation on clojure.com and found defn and defn- among other things, see https://clojuredocs.org/search?q=defn. I also searched on Google and found a source that said that the - in front of main indicated that the function was static (http://ben.vandgrift.com/2013/03/13/clojure-hello-world.html).
Does the - truely mean that the function is static? I couldn't find any other sources that confirmed that. Also I can use both (main) and (-main) when calling the main method without any problem.
Given the following code...
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
(defn main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
I get the following output...
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
Loading src/clojure_example/core.clj... done
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
I noticed no difference. Output is the same for both functions. Any help is appreciated!
First, an aside.
Regarding the macros defn vs defn-, the 2nd form is just a shorthand for "private" functions. The long form looks like:
(defn ^:private foo [args] ...)
However, this is just a hint to the user that one shouldn't use these functions. It is easy for testing, etc to work around this weak "private" restriction. Due to the hassle I never use so-called "private" functions (I do sometimes use metadata ^:no-doc and names like foo-impl to indicate a fn is not a part of the public-facing API and should be ignored by library users).
The "main" function in a Clojure Program
In Java, a program is always started by calling the "main" function in a selected class
class Foo
public static void main( String[] args ) {
...
}
}
and then
> javac Foo.java ; compile class Foo
> java Foo ; run at entrypoint Foo.main()
Clojure chooses to name the initial function -main. The hyphen in the function name -main is not really special, except it makes the name unusual so it is less likely to conflict with any other function in your codebase. You can see this in the definition of the function clojure.main/main-opt.
You can see part of the origin of the hyphen convention in the docs for gen-class (scroll down to see the part about :prefix). Note that using the hyphen is changeable if using gen-class for java interop.
Using the Clojure Deps & CLI tools, the name -main is assumed as the starting point of the program.
If you are using Leiningen, it is more flexible and allows one to override the -main entrypoint of a program.
In Leiningen projects, an entry like the following indicates where to start when you type lein run:
; assumes a `-main` function exists in the namespace `demo.core`
:main ^:skip-aot demo.core
so in a program like this:
(ns demo.core )
(defn foo [& args]
(newline)
(println "*** Running in foo program ***")
(newline))
(defn -main [& args]
(newline)
(println "*** Running in main program ***")
(newline))
we get the normal behavior:
~/expr/demo > lein run
*** Running in main program ***
However, we could invoke the program another way:
> lein run -m demo.core/foo
*** Running in foo program ***
to make the foo function the "entry point". We could also change the :main setting like this:
:main ^:skip-aot demo.core/foo
and get behavior:
~/expr/demo > lein run
*** Running in foo program ***
So, having the initial function of a Clojure program named -main is the default, and is required for most tools. You can override the default if using Leiningen, although this is probably only useful in testing & development.
Please keep in mind that each namespace can have its own -main function, so you can easily change the initial function simply by changing the initial namespace that is invoked.
And finally, the hyphen in -main us unrelated to the hyphen used for pseudo-private functions defined via defn-.
All clojure functions are "static" (digression below). Putting a - as the first character in the name of a function does not have any effect on the behaviour of the function. Using the defn- macro instead of defn makes a function private. -main is ~~by convention~~ the name of the main entry point for a clojure program, if you specify an ns in your project definition as the "main" namespace, the clojure runtime will look for a function named -main and invoke it.
It's not really "by convention" now I think about it. As it's not configurable for the standard tools. It is the one and only name that clojure.main will look for.
https://clojure.org/reference/repl_and_main
All clojure functions are actually an instance of a java object AFunction, with an instance method invoke. So they're not static from a java perspective, but while in clojure land I'd say that they are, as they have no instance that you see. There is also the special case of gen-class, where you define a java class using clojure. In this case you can mark clojure functions as ^:static for the generated java class. This creates a static method in the generated java class that refers to the instance of AFunction.

a binding in a macro isn't resolved

I'm creating a library for an API server, here's a simpliefied version of I have:
(defonce ^:dynamic *my-token* nil)
(defmacro def-my-token
[token1 & body]
`(binding [*my-token* ~token1] ~#body))
And the main "post" method:
(defn my-post-request [url1]
(try
(let [res (client/post (str "api/url/base" url1)
{:body (json/write-str (:secret my-token)) ; my-token should come from the macro
;......
And here's how I want to use it:
(defn -main [& args]
(def-my-token "fdsfdsfdsfds"
; now "my-token" should be created and visible in "my-post-request", shouldn't it?
(print
(my-post-request "/some_end_point"))))
But it says "Unable to resolve symbol: my-token in this context"
I wonder why? doens't def-my-token, being a macros, define it? why not? And how to fix that?
UPDATE:
Also without (defonce ^:dynamic *token* nil) it doesn't work. Why not?
Why isn't defining the macro enough?
Answer to your UPDATE:
According to the documentation for binding, you can only override already existing vars. That's why your solution doesn't work without establishing a root binding to your dynamic var.
Sidenote:
I would recommend doing what jmargolisvt said and use a plain def instead of defonce, as I've never seen any dynamic var definition in the wild using defonce.
EDIT:
doens't def-my-token, being a macros, define it? why not? And how to fix that?
Macros by themselves don't define things, they are small programs transforming your source code in the macro-expansion step of most Lisp REPL's. It could define anything you want it to, but then you should've wrote the def special form. What you used instead was binding which deals with already existing vars.
You might get more insight by toying with it in the REPL and/or reading the answer of this stackoverflow answer.
If you need some further explanation why overriding is needed:
It's practical to conceptualize vars as stacks. The root binding that you establish with using def is the first layer. Everything in your program will see this value unless you put "something" over it. As you can imagine in your example having *my-token* seen as nil from your functions would cause issues.
binding to the resuce!
It allows you put anything "on top" of the root binding (in your case nil) thread-locally inside of the body it, like so:
you bound *my-token*, not my-token. Try:
{:body (json/write-str (:secret *my-token*))
The asterisks are just a naming convention for dynamic vars, they are still part of the actual var name.

Why can't I instantiate a defrecord-generated class after use'ing its namespace?

I'm relatively new to Clojure and going through the Clojure chapter in Seven Languages in Seven Weeks, and I can't figure out why this code from the book isn't working for me. I'm using Leiningen and Clojure version 1.5.1. As far as I can tell after careful checking, I typed the code exactly as it reads in the book.
Here is the code:
(ns seven-languages.compass)
(defprotocol Compass
(direction [c])
(left [c])
(right [c]))
(def directions [:north :east :south :west])
(defn turn [base amount]
(rem (+ base amount) (count directions)))
(defrecord SimpleCompass [bearing]
Compass
(direction [_] (directions bearing))
(left [_] (SimpleCompass. (turn bearing 3)))
(right [_] (SimpleCompass. (turn bearing 1)))
Object
(toString [this] (str "[" (direction this) "]")))
I'm running "lein repl" from within the directory ~/clojure/seven-languages (created by running "lein new seven-languages" in ~/clojure). Relative to this directory, my .clj files are in src/seven_languages. So far I've been able to successfully import and use them from the repl by typing (use 'seven-languages.filenamehere).
So, after saving the code I listed above as src/seven_languages/compass.clj, I run this from the REPL:
user=> (use 'seven-languages.compass)
nil
But then when I try to define an "instance" of the SimpleCompass, typing it exactly like in the book, this happens:
user=> (def c (SimpleCompass. 0))
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: SimpleCompass, compiling:(NO_SOURCE_PATH:1:8)
I also tried loading the file using (load-file "src/seven_languages/compass.clj"), but got the same results. Since the actual loading seemed to work as expected, I wonder if there has been some change in how defprotocol or defrecord works in versions of Clojure subsequent to when Seven Languages in Seven Weeks was written. In the introduction to the Clojure chapter, the author writes, "I’m using a prerelease version of Clojure 1.2, and it should be fully ready by the time this book is in your hands."
Can anyone tell why this code isn't working properly? If it's a version issue, how would you update this code for Clojure 1.5.1?
EDIT: Aha! I figured it out after finding this:
Clojure - deftype ignored - unable to resolve classname on tests
It's a namespace issue. I'm guessing this is a change since version 1.2 when 7LI7W was written. For whatever reason, while functions in imported files are "automatically handled" so that you can just use them directly, types are not automatically handled. You have to include the full path to the type, and make sure you use the actual path with underscores, not hyphens. I got my code to work by substituting SimpleCompass with the full path, seven_languages.compass.SimpleCompass:
user=> (def c (seven_languages.compass.SimpleCompass. 0))
#'user/c
user=> c
#seven_languages.compass.SimpleCompass{:bearing 0}
user=> (left c)
#seven_languages.compass.SimpleCompass{:bearing 3}
user=> (right c)
#seven_languages.compass.SimpleCompass{:bearing 1}
Apart from always fully qualifying the class name, you can import it and use the short name afterwards:
(import seven_languages.compass.SimpleCompass)
;; (SimpleCompass. 0) etc. will work now
Also, it's worth pointing out that defrecord creates to factory functions for you, one positional and one taking a map:
(defrecord Foo [x])
(->Foo 1)
;= #user.Foo{:x 1}
(map->Foo {:x 1})
;= #user.Foo{:x 1}
These are just regular functions and so will have been pulled in by your use call.
Relatedly, deftype, as of Clojure 1.5.1, creates the positional factory only.

My clojure function works when defined in the repl but not when loaded from a script

I am using Clojure 1.4.0 on Windows XP (JVM=1.6.0).
My help.clj script contains obscure snippets of Clojure code that I find useful.
In the Clojure repl I can access it from the current directory with (load-file "help.clj").
Trying to be fancy I write (defn clojure-help [] (load-file "help.clj")). Now a simple (clojure-help) loads it.
Then I tried putting the clojure-help function in a repl startup script I use.
But now calling (clojure-help) results in the following Exception:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: clojure-help in this context
What am I missing?
Thanks for posting the code in the comments above! Without the code it's impossible to know what's actually going on. Making one simple change seems to fix the problem:
(defn my-prompt [] (printf "\n[%s]> " (ns-name *ns*)))
(defn p1 [] (clojure.main/repl :prompt my-prompt))
(defn clojure-help [] (load-file "help.clj"))
(p1)
The change was moving the (p1) call to the end of the script. If the call isn't at the end of the script then Clojure drops into the REPL before evaluating the rest of the functions in the script, and thus they are not available in the REPL. Since clojure-help was defined after the (p1) call in your script it was not being evaluated until after exiting the REPL.
If you're not using the repl to load other scripts you could do something like this:
clojure --init replstartup.clj --repl
Where replstartup.clj would contain your closure-help function.
Alternatively you could just create a batch file, named clojure-repl.bat (or some such thing) that looks like this.
#echo off
java -cp %userprofile%\clojure-1.4.0.jar clojure.main --init repl-startup.clj --repl
#echo on

clojure behavior of def

I have a lein project (using cascalog--but that's not particularly important). I'm trying to externalize properties like paths to files, so I end up with code that looks something like this:
(defn output-tap [path] (hfs-textline (str (get-prop :output-path-prefix) path) :sinkmode :replace))
(def some-cascalog-query
(<- [?f1 ?f2 ?f3]
((output-tap (get-prop :output-path)) ?line)
(tab-split ?line :> ?f1 ?f2 ?f3)))
In the example above, assume the function get-prop exists; it's just using standard java to read a property value (based off this example: loading configuration file in clojure as data structure).
Now I have a main method that loads the property values, e.g. something like:
(defn -main [& args] (do (load-props (first args)) (do-cascalog-stuff)))
But when I lein uberjar I get a compile time error saying:
Caused by: java.lang.IllegalArgumentException: Can not create a Path from an empty string
at org.apache.hadoop.fs.Path.checkPathArg(Path.java:82)
at org.apache.hadoop.fs.Path.<init>(Path.java:90)
at cascading.tap.hadoop.Hfs.getPath(Hfs.java:343)
Are defs always compile time evaluated (rather than runtime evaluated)? Or am I misunderstanding this error?
So, you want the property lookup to occur at run-time? Then yes, you'll need to define some-cascalog-query as a function or macro. A bare def causes the expression to be evaluated when the code is loaded, not when the var is dereferenced.
This can be illustrated pretty simply in the REPL:
user=> (def foo (do (println "Hello, world!") 1))
Hello, world!
#'user/foo
user=> foo
1
From the documentation (emphasis mine):
(def symbol init?)
Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (ns). If init is supplied, it is evaluated, and the root binding of the var is set to the resulting value.
that error looks like (get-prop :output-path) (get-prop :output-path-prefix) are is returning nothing which is getting wrapped into an empty string by str. perhaps the property is not being found?
does get-prop work as expected?
your understanding of defs is correct, they are are compile time, not (usually) runtime.