Skip to content

Instantly share code, notes, and snippets.

@stuartsierra
Last active January 4, 2016 01:59
Show Gist options
  • Select an option

  • Save stuartsierra/8551970 to your computer and use it in GitHub Desktop.

Select an option

Save stuartsierra/8551970 to your computer and use it in GitHub Desktop.

Revisions

  1. stuartsierra revised this gist Jan 22, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion reevaluated_types.clj
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@
    ;; In general, whenever you have an error of the form
    ;; "X cannot be cast to X", check for the possibility
    ;; that X has been redefined and you are using an instance
    ;; that was creating using the old definition.
    ;; that was created using the old definition.

    ;; This is further complicated by ahead-of-time (AOT)
    ;; compilation, because the AOT-compiled version of a type
  2. stuartsierra revised this gist Jan 22, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion reevaluated_types.clj
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@
    ;; In general, whenever you have an error of the form
    ;; "X cannot be cast to X", check for the possibility
    ;; that X has been redefined and you are using an instance
    ;; that was creating using to the old definition.
    ;; that was creating using the old definition.

    ;; This is further complicated by ahead-of-time (AOT)
    ;; compilation, because the AOT-compiled version of a type
  3. stuartsierra created this gist Jan 22, 2014.
    51 changes: 51 additions & 0 deletions reevaluated_types.clj
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    ;; Demonstration of how re-evaluating type/protocol
    ;; definitions can lead to confusing errors in Clojure.

    (set! *warn-on-reflection* true)

    ;; Create a new type Foo
    (deftype Foo [x])

    ;; Create an instance of that type
    (def a-foo (Foo. 1))

    ;; Maybe create a type-hinted function
    (defn use-foo [^Foo foo]
    (prn (.x foo)))


    ;; Now suppose we re-evaluate the definition of Foo,
    ;; perhaps in a REPL or editor
    (deftype Foo [x])


    ;; Now look what happens!

    (prn (type a-foo)) ;; user.Foo

    (prn (instance? Foo a-foo)) ;; false ?!

    (prn (= Foo (type a-foo))) ;; false ?!

    (use-foo a-foo)
    ;; java.lang.ClassCastException:
    ;; user.Foo cannot be cast to user.Foo


    ;; What's going on?

    ;; The object bound to a-foo is an instance of the *old*
    ;; class Foo we defined on line 7. Clojure's dynamic class
    ;; loader allows us to create a new class named Foo on line
    ;; 19, but as far as the JVM is concerned it's not the same
    ;; class.

    ;; In general, whenever you have an error of the form
    ;; "X cannot be cast to X", check for the possibility
    ;; that X has been redefined and you are using an instance
    ;; that was creating using to the old definition.

    ;; This is further complicated by ahead-of-time (AOT)
    ;; compilation, because the AOT-compiled version of a type
    ;; or protocol will often get loaded earlier than the
    ;; source-code containing it.