Clojure

Class name clash between top-level functions and defn'ed ones

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Critical Critical
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: Release 1.7
  • Component/s: None
  • Labels:
  • Patch:
    Code
  • Approval:
    Ok

Description

Named anonymous fn's are not guaranteed to have unique class names when AOT-compiled.

For example:

(defn g [])
(def xx (fn g []))

When AOT-compiled both functions will emit user$g.class, the latter overwriting the former.

Impact: this affects apps like Cursive, which has been using a patched version of Clojure to get around this issue for quite a while.

Demonstration script: demo1.clj

Patch: 0001-CLJ-1093-v3.patch

Approach: Generate unique class names for named fn's the same way as for unnamed anonymous fn's.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

code before after note
(defn a []) user$a user$a same
(fn []) user$evalN$fn__N user$evalN$fn__N same
(fn a []) user$evalN$a__N user$evaN$a__N same
(let [a (fn [])] a) user$evalN$a__N user$evalN$a__N same
(let [a (fn x [])] a) user$eval1N$x__N user$evalN$a_x_N IMPROVED - contains local binding name
(def a (fn [])) user$a user$a same
(def a (fn x [])) user$x user$a_x_N FIXED conflict with (defn x [])
(def ^{:foo (fn [])} a) user$fn__N user$fn__N same
(def ^{:foo (fn a [])} a) user$a user$a__N FIXED conflict with (defn a [])
(def a (fn [] (fn []))) user$a$fn__N user$a$fn__N same
(def a (fn [] (fn x []))) user$a$x__N user$a$x__N same

See also: This patch also fixes the issue reported in CLJ-1227.

Screened by: Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.

  1. 0001-CLJ-1093-v3.patch
    25/Sep/14 7:08 AM
    2 kB
    Nicola Mometto
  2. 0001-CLJ-1093-v3-no-locals-improv.patch
    06/Oct/14 11:54 AM
    2 kB
    Nicola Mometto
  3. demo1.clj
    23/Jan/14 1:10 PM
    0.6 kB
    Stuart Sierra

Activity

Nicola Mometto made changes -
Field Original Value New Value
Attachment 0001-CLJ-1330.patch [ 12713 ]
Nicola Mometto made changes -
Attachment 0001-CLJ-1330.patch [ 12713 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch [ 12714 ]
Alex Miller made changes -
Patch Code [ 10001 ]
Approval Triaged [ 10120 ]
Labels aot compiler
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch [ 12714 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch [ 12715 ]
Stuart Sierra made changes -
Description When aot compiling a named top-level function, this gets compiled to the same file name as defn'ed functions using the same name.

E.g.
{code}
(defn x [])
(fn x [])
{code}

Those two functions will both compile to user$x.class, the latter overwriting the former.
This is the root-cause of http://dev.clojure.org/jira/browse/CLJ-1227

A proposed solution is to compile top-level functions prefixing their name with a gensym, as gets done for anonymous functions.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Attachment demo1.clj [ 12717 ]
Alex Miller made changes -
Comment [ There is consensus that this is a problem, however this is an area of the code with broad impacts as it deals with how classes are named. To that end, there is some work that needs to be done in understanding the impacts before we can consider it.

Some questions we would like to answer:

1) According to Rich, naming of (fn x []) function classes used to work in the manner of this patch - with generated names. Some code archaeology needs to be done on why that was changed and whether the change to the current behavior was addressing problems that we are likely to run into.

2) Are there issues with recursive functions? Are there impacts either in AOT or non-AOT use cases? Need some tests.

3) Are there issues with dynamic redefinition of functions? With the static naming scheme, redefinition causes a new class of the same name which can be picked up by reload of classes compiled to the old definition. With the dynamic naming scheme, redefinition will create a differently named class so old classes can never pick up a redefinition. Is this a problem? What are the impacts with and without AOT? Need some tests. ]
Rich Hickey made changes -
Fix Version/s Release 1.7 [ 10250 ]
Approval Triaged [ 10120 ] Vetted [ 10003 ]
Stuart Halloway made changes -
Approval Vetted [ 10003 ] Incomplete [ 10006 ]
Alex Miller made changes -
Approval Incomplete [ 10006 ] Vetted [ 10003 ]
Alex Miller made changes -
Assignee Alex Miller [ alexmiller ]
Alex Miller made changes -
Approval Vetted [ 10003 ] Incomplete [ 10006 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-refactored.patch [ 13335 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-refactored.patch [ 13335 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-refactored.patch [ 13336 ]
Nicola Mometto made changes -
Attachment 0001-CLJ-1093-v2.patch [ 13338 ]
Alex Miller made changes -
Approval Incomplete [ 10006 ] Vetted [ 10003 ]
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Nicola Mometto made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
See [this comment|http://dev.clojure.org/jira/browse/CLJ-1330?focusedCommentId=35700&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-35700] for a comparision between pre and post patch naming scheme.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
See [this comment|http://dev.clojure.org/jira/browse/CLJ-1330?focusedCommentId=35700&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-35700] for a comparision between pre and post patch naming scheme.

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{{(fn [])}}|user$evalN$fn__N|user$evalN$fn__N|same|
|{{(fn a [])}}|user$evalN$a__N|user$evaN$a__N|same|
|{{(let [a (fn [])] a)}}|user$evalN$a__N|user$evalN$a__N|same|
|{{(let [a (fn x [])] a)}}|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|{{(def a (fn []))}}|user$a|user$a|same|
|{{(def a (fn x []))}}|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|{{(def ^{:foo (fn [])} a)}}|user$fn__N|user$fn__N|same|
|{{(def ^{:foo (fn a [])} a)}}|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|{{(def a (fn [] (fn [])))}}|user$a$fn__N|user$a$fn__N|same|
|{{(def a (fn [] (fn x [])))}}|user$a$x__N|user$a$x__N|same|
|{{(let [x (fn [])] (def a (fn [] x)))}}|user$evalN$x__N|user$evalN$x__N|same|
|{{(let [x (fn a [])] (def a (fn [] x))) }}|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Nicola Mometto made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{{(fn [])}}|user$evalN$fn__N|user$evalN$fn__N|same|
|{{(fn a [])}}|user$evalN$a__N|user$evaN$a__N|same|
|{{(let [a (fn [])] a)}}|user$evalN$a__N|user$evalN$a__N|same|
|{{(let [a (fn x [])] a)}}|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|{{(def a (fn []))}}|user$a|user$a|same|
|{{(def a (fn x []))}}|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|{{(def ^{:foo (fn [])} a)}}|user$fn__N|user$fn__N|same|
|{{(def ^{:foo (fn a [])} a)}}|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|{{(def a (fn [] (fn [])))}}|user$a$fn__N|user$a$fn__N|same|
|{{(def a (fn [] (fn x [])))}}|user$a$x__N|user$a$x__N|same|
|{{(let [x (fn [])] (def a (fn [] x)))}}|user$evalN$x__N|user$evalN$x__N|same|
|{{(let [x (fn a [])] (def a (fn [] x))) }}|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|
|(let [x {color:red}(fn []){color}] (def a (fn [] x)))|user$evalN$x__N|user$evalN$x__N|same|
|(let [x {color:red}(fn a []){color}] (def a (fn [] x)))|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Nicola Mometto made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|
|(let [x {color:red}(fn []){color}] (def a (fn [] x)))|user$evalN$x__N|user$evalN$x__N|same|
|(let [x {color:red}(fn a []){color}] (def a (fn [] x)))|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|
|(let [x {color:red}(fn []){color}] x)|user$evalN$x__N|user$evalN$x__N|same|
|(let [x {color:red}(fn a []){color}] x)|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|
|(let [x {color:red}(fn []){color}] x)|user$evalN$x__N|user$evalN$x__N|same|
|(let [x {color:red}(fn a []){color}] x)|user$evalN$a__N|user$evalN$x__a__N|IMPROVED - contains local binding name|

*See also:* This patch also fixes the issue reported in CLJ-1227.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(def a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(def a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Nicola Mometto made changes -
Attachment 0001-CLJ-1093-v3.patch [ 13363 ]
Nicola Mometto made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn a [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn x [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v2.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn x [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v3.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn x [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Alex Miller made changes -
Approval Vetted [ 10003 ] Screened [ 10004 ]
Alex Miller made changes -
Assignee Alex Miller [ alexmiller ]
Alex Miller made changes -
Description Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v3.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn x [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Named anonymous {{fn}}'s are not guaranteed to have unique class names when AOT-compiled.

For example:

{code}
(defn g [])
(def xx (fn g []))
{code}

When AOT-compiled both functions will emit {{user$g.class}}, the latter overwriting the former.

*Impact:* this affects apps like Cursive, which has been using a patched version of Clojure to get around this issue for quite a while.

*Demonstration script:* demo1.clj

*Patch:* 0001-CLJ-1093-v3.patch

*Approach:* Generate unique class names for named {{fn}}'s the same way as for unnamed anonymous {{fn}}'s.
The patch contains an additional enhancement to include the name of the local binding in the class name.

Comparison between pre and post patch naming scheme (N denotes unique number):

||code||before||after||note||
|{color:red}(defn a []){color}|user$a|user$a|same|
|{color:red}(fn []){color}|user$evalN$fn__N|user$evalN$fn__N|same|
|{color:red}(fn a []){color}|user$evalN$a__N|user$evaN$a__N|same|
|(let [a {color:red}(fn []){color}] a)|user$evalN$a__N|user$evalN$a__N|same|
|(let [a {color:red}(fn x []){color}] a)|user$eval1N$x__N|user$evalN$a__x__N|IMPROVED - contains local binding name|
|(def a {color:red}(fn []){color})|user$a|user$a|same|
|(def a {color:red}(fn x []){color})|user$x|user$a__x__N|FIXED conflict with {{(defn x [])}}|
|(def ^{:foo {color:red}(fn []){color}\} a)|user$fn__N|user$fn__N|same|
|(def ^{:foo {color:red}(fn a []){color}\} a)|user$a|user$a__N|FIXED conflict with {{(defn a [])}}|
|(def a (fn [] {color:red}(fn []){color}))|user$a$fn__N|user$a$fn__N|same|
|(def a (fn [] {color:red}(fn x []){color}))|user$a$x__N|user$a$x__N|same|

*See also:* This patch also fixes the issue reported in CLJ-1227.

*Screened by:* Alex Miller - I am not sure whether the local binding name enhancement is worth doing. It improves debugging of which anonymous class you're talking about but has the downsides of increasing class name (and file name) length.
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-refactored.patch [ 13336 ]
Nicola Mometto made changes -
Attachment 0001-Fix-CLJ-1330-make-top-level-named-functions-classnam.patch [ 12715 ]
Nicola Mometto made changes -
Attachment 0001-CLJ-1093-v2.patch [ 13338 ]
Nicola Mometto made changes -
Rich Hickey made changes -
Approval Screened [ 10004 ] Ok [ 10007 ]
Stuart Halloway made changes -
Resolution Completed [ 1 ]
Status Open [ 1 ] Closed [ 6 ]

People

Vote (8)
Watch (11)

Dates

  • Created:
    Updated:
    Resolved: