Clojure

Deftypes not re-evaluated when protocols change; causes errors

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: Release 1.2
  • Component/s: None
  • Labels:
    None

Description

I keep having to restart my JVM to avoid a puzzling issue when changing protocol definitions.

Here's the simplest way to reproduce the problem:

Start with file protoproblem/proto.clj:

(ns protoproblem.proto)

   (defprotocol Steps
     (one [x])
     (two [x]))
</code></pre>

and file protoproblem/impl.clj:
<pre><code>   (ns protoproblem.impl
     (:require [protoproblem.proto :as proto]))

   (deftype ArraySteps [a]
     proto/Steps
     (one [x] (first a))
     (two [x] (second a)))
</code></pre>

In the repl, everything works as expected:
<pre><code>   user> (load "protoproblem/proto")
   nil
   user> (load "protoproblem/impl")
   nil
   user> (protoproblem.proto/one (protoproblem.impl.ArraySteps. [1 2]))
   1
</code></pre>

Now, we redefine the protocol by commenting out the 'one' method def in proto.clj, and then reloading it:
<pre><code>   user=> (load "protoproblem/proto")
   nil
   user=> (protoproblem.proto/one (protoproblem.impl.ArraySteps. [1 2]))
   java.lang.NullPointerException (NO_SOURCE_FILE:9)
   user=> (load "protoproblem/impl")
   java.lang.IllegalArgumentException: Can't define method not in interfaces: one (impl.clj:5)
</code></pre>

That's pretty much as expected. But what if we try to get back to how things were, by reversing the changes in proto.clj, and reloading? This is where the problems arise:
<pre><code>   user=> (load "protoproblem/proto")
   nil
   user=> (load "protoproblem/impl")
   nil
   user=> (protoproblem.proto/one (protoproblem.impl.ArraySteps. [1 2]))
   java.lang.IllegalArgumentException: No implementation of method: :one of protocol: #'protoproblem.proto/Steps found for class: protoproblem.impl.ArraySteps (NO_SOURCE_FILE:0)

Ouch!

At this point, I have to restart my JVM to proceed, which is making incremental development of protocols-based code unusually tedious.

I initially encountered the behaviour using "C-c C-k" under slime/swank-clojure, but the above transcript is from a plain command-line repl, using a Clojure 1.2 snapshot from today. (The same thing happened with a snapshot from 2 weeks ago.)

When using "reify" inside a factory function instead of the constructor for a "deftype", everything works as expected.

Activity

Hide
Assembla Importer added a comment -
Show
Assembla Importer added a comment - Converted from http://www.assembla.com/spaces/clojure/tickets/353
Hide
Assembla Importer added a comment -

cgrand said: Is this the same DynamicClassLoader caching problem as in #368?

Show
Assembla Importer added a comment - cgrand said: Is this the same DynamicClassLoader caching problem as in #368?
Hide
Assembla Importer added a comment -

richhickey said: (In [[r:f47b3d6f028e0370c495383731a449092d0ae451]]) disable don't-recompile-if-same-source in DynamicClassLoader, fixes #353

Branch: master

Show
Assembla Importer added a comment - richhickey said: (In [[r:f47b3d6f028e0370c495383731a449092d0ae451]]) disable don't-recompile-if-same-source in DynamicClassLoader, fixes #353 Branch: master

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: