Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Le #147] Names of functions defined in let are getting lost #57

Open
stanislowskij opened this issue Sep 11, 2024 · 6 comments
Open

[Le #147] Names of functions defined in let are getting lost #57

stanislowskij opened this issue Sep 11, 2024 · 6 comments
Labels
bug Something isn't working enhancement New feature or request

Comments

@stanislowskij
Copy link
Collaborator

stanislowskij commented Sep 11, 2024

⚠️ Imported from legacy repository. This issue is a duplicate of Clojure-Intro-Course/babel-legacy#147.

(let [myNeg (fn [x] (neg? x))] (myNeg "test")) lists the error as occurring within an anonymous function on the stack trace. Viewing the stack trace directly shows that the function on the stack is called as "myNeg__1172". Is it possible to determine if a dynamically assigned function has a "real" name, and if so, retrieve it?

@stanislowskij stanislowskij added enhancement New feature or request small bug Something isn't working right, but not fatal labels Sep 11, 2024
@stanislowskij
Copy link
Collaborator Author

When an anonymous function is on the call stack, it takes the form fn__####, with the number signs standing in for numerals. When a function defined within a let is on the stack, it takes the form name_####, replacing "name" with the name assigned to the function within the let.

@stanislowskij
Copy link
Collaborator Author

Stack trace sample, showing both the filtered trace, and the relevant section of the unfiltered trace:

In Clojure interactive session on line 1.
Call sequence:
[isNeg (ns:clojure.lang.Numbers) called in file Numbers.java on line 125]
[An anonymous function called dynamically]
[An anonymous function called dynamically]
[Clojure interactive session (repl)]

#error {
 :cause "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
 :via
 [{:type java.lang.ClassCastException
   :message "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
   :at [clojure.lang.Numbers isNeg "Numbers.java" 125]}]
 :trace
 [[clojure.lang.Numbers isNeg "Numbers.java" 125]
  [babel.middleware$eval1086$myNeg__1087 invoke "form-init7081259885597659217.clj" 1]
  [babel.middleware$eval1086$myNegWrapped__1089 invoke "form-init7081259885597659217.clj" 1]

The function was (let [myNeg (fn [x] (neg? x))] (let [myNegWrapped (fn [y] (myNeg y))] (myNegWrapped "a"))).

@stanislowskij
Copy link
Collaborator Author

Note that if the function name is defined in a destructured way, the name is lost entirely. These behave totally independently:

(let [[myNeg dud] [(fn [x] (neg? x))]] (let [myNegWrapped (fn [y] (myNeg y))] (myNegWrapped "a")))
Default Error: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')

In Clojure interactive session on line 1.
Call sequence:
[isNeg (ns:clojure.lang.Numbers) called in file Numbers.java on line 125]
[An anonymous function called dynamically]
[An anonymous function called dynamically]
[Clojure interactive session (repl)]

:trace
 [[clojure.lang.Numbers isNeg "Numbers.java" 125]
  [babel.middleware$eval1160$fn__1161 invoke "form-init7081259885597659217.clj" 1]
  [babel.middleware$eval1160$myNegWrapped__1163 invoke "form-init7081259885597659217.clj" 1]
  [babel.middleware$eval1160 invokeStatic "form-init7081259885597659217.clj" 1]

@stanislowskij
Copy link
Collaborator Author

Repeated function names don't change the behavior in any interesting way:

(let [myNeg (fn [x] (neg? x))] (let [myNeg (fn [y] (myNeg y))] (myNeg "a")))

Default Error: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')

In Clojure interactive session on line 1.
Call sequence:
[isNeg (ns:clojure.lang.Numbers) called in file Numbers.java on line 125]
[An anonymous function called dynamically]
[An anonymous function called dynamically]
[Clojure interactive session (repl)]

babel.middleware=> *e
#error {
 :cause "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
 :via
 [{:type java.lang.ClassCastException
   :message "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
   :at [clojure.lang.Numbers isNeg "Numbers.java" 125]}]
 :trace
 [[clojure.lang.Numbers isNeg "Numbers.java" 125]
  [babel.middleware$eval1166$myNeg__1167 invoke "form-init7081259885597659217.clj" 1]
  [babel.middleware$eval1166$myNeg__1169 invoke "form-init7081259885597659217.clj" 1]

@stanislowskij
Copy link
Collaborator Author

When the function defined in the let is called within a more standard named function, the name of the function is shown as the name of the function it was called within:


(sample-test-files.sample3/nestedLetDefinitions "a")
;;Note: nestedLetDefinitions was defined on line 56, with a let on line 57 and line 58, and the call on line 59.

In file sample3.clj on line 59.
Call sequence:
[isNeg (ns:clojure.lang.Numbers) called in file Numbers.java on line 125]
[nestedLetDefinitions (ns:sample_test_files.sample3) called in file sample3.clj on line 57]
[nestedLetDefinitions (ns:sample_test_files.sample3) called in file sample3.clj on line 58]
[Clojure interactive session (repl)]


:trace
 [[clojure.lang.Numbers isNeg "Numbers.java" 125]
  [sample_test_files.sample3$nestedLetDefinitions$myNeg__1117 invoke "sample3.clj" 57]
  [sample_test_files.sample3$nestedLetDefinitions$myNestedNeg__1119 invoke "sample3.clj" 58]
  [sample_test_files.sample3$nestedLetDefinitions invokeStatic "sample3.clj" 59]
  [sample_test_files.sample3$nestedLetDefinitions invoke "sample3.clj" 56]
  [babel.middleware$eval1132 invokeStatic "form-init445456965654135903.clj" 1]

@stanislowskij
Copy link
Collaborator Author

Similarly, anonymous functions are shown as having the name of the function they're called within:


sample-test-files.sample3/anonLetDefinitions "a")
Default Error: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')

In file sample3.clj on line 63.
Call sequence:
[isNeg (ns:clojure.lang.Numbers) called in file Numbers.java on line 125]
[anonLetDefinitions (ns:sample_test_files.sample3) called in file sample3.clj on line 62]
[anonLetDefinitions (ns:sample_test_files.sample3) called in file sample3.clj on line 63]
[Clojure interactive session (repl)]

babel.middleware=> *e
#error {
 :cause "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
 :via
 [{:type java.lang.ClassCastException
   :message "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
   :at [clojure.lang.Numbers isNeg "Numbers.java" 125]}]
 :trace
 [[clojure.lang.Numbers isNeg "Numbers.java" 125]
  [sample_test_files.sample3$anonLetDefinitions$myNeg__1173 invoke "sample3.clj" 62]
  [sample_test_files.sample3$anonLetDefinitions$fn__1175 invoke "sample3.clj" 63]
  [sample_test_files.sample3$anonLetDefinitions invokeStatic "sample3.clj" 63]
  [sample_test_files.sample3$anonLetDefinitions invoke "sample3.clj" 61]
  [babel.middleware$eval1178 invokeStatic "form-init445456965654135903.clj" 1]

The functions used above, for reference:


(defn nestedLetDefinitions [input]
  (let [myNeg (fn [x] (neg? x))]
    (let [myNestedNeg (fn [y] (myNeg y))]
      (myNestedNeg input))))

(defn anonLetDefinitions [input]
  (let [myNeg (fn [x] (neg? x))]
    ((fn [y] (myNeg y)) input)))

@stanislowskij stanislowskij added bug Something isn't working and removed small bug Something isn't working right, but not fatal labels Sep 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant