Problem with autotest and protocols & records in different files/namespaces

67 views
Skip to first unread message

Simon Katz

unread,
Apr 12, 2013, 8:11:54 AM4/12/13
to mi...@googlegroups.com
I've run into a problem using Midje autotest with protocols and records, when the protocols and records are defined in different files/namespaces.

I get an error like this:

FAIL at (core_test.clj:6)
    Expected: 42
      Actual: java.lang.IllegalArgumentException: No implementation of method: :f of protocol: #'midje-protocols-records-in-different-ns.protocol/P found for class: midje_protocols_records_in_different_ns.record.R
FAILURE: 1 check failed.

Here's a simple example that shows the problem...

My project structure is like this:

.
├── project.clj
├── src
│   └── midje_protocols_records_in_different_ns
│       ├── protocol.clj
│       └── record.clj
└── test
    └── midje_protocols_records_in_different_ns
        └── core_test.clj

My files are:

project.clj:

    (defproject midje-protocols-records-in-different-ns "0.1.0-SNAPSHOT"
      :description "FIXME: write description"
      :url "http://example.com/FIXME"
      :license {:name "Eclipse Public License"
                :url "http://www.eclipse.org/legal/epl-v10.html"}
      :dependencies [[org.clojure/clojure "1.5.1"]])

protocol.clj:

    (ns midje-protocols-records-in-different-ns.protocol)
    
    (defprotocol P
      (f [self]))

record.clj:

    (ns midje-protocols-records-in-different-ns.record
      (require [midje-protocols-records-in-different-ns.protocol
                :refer [P]]))
    
    (defrecord R
        []
      P
      (f [self] 42))

core_test.clj:

    (ns midje-protocols-records-in-different-ns.core-test
      (:use midje.sweet
            midje-protocols-records-in-different-ns.protocol
            midje-protocols-records-in-different-ns.record))
    
    (fact (f (->R)) => 42)

Details of when the problem occurs:
  • Only with autotest — non-auto testing works fine.
  • Both "(autotest)" from nrepl and "lein midje :autotest" from the command line give the same problem.
  • If I move the `defrecord` form from "record.clj" to "protocol.clj", there is no problem.
Any ideas?

Simon

Brian Marick

unread,
May 12, 2013, 7:27:11 PM5/12/13
to mi...@googlegroups.com
Sorry for not replying earlier; you caught me at the beginning of a month-long trip.

Some features of Clojure don't play well with the repl. Multimethods are the example I most run into. I avoid protocols and records because they strike me as the sort of efficiency hack that should be forced on you by profiling, but it seems I've had problems where I `(require namespace :reload)` and get strange errors that make me exit the repl and reload everything.

Can you check whether the same problems happen if you emulate the reloading that autotest does by hand? That is, don't use autotest at all, but use `require … :reload` whenever you make changes.
> --
> You received this message because you are subscribed to the Google Groups "Midje" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to midje+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

--------
Latest book: /Functional Programming for the Object-Oriented Programmer/
https://leanpub.com/fp-oo

Simon Katz

unread,
May 13, 2013, 8:33:25 AM5/13/13
to mi...@googlegroups.com
Yes, the same problem occurs if I do `require ... :reload` by hand.

Ignoring the namespaces, if I re-evaluate the `defprotocol` form I must re-evaluate the `defrecord` form before creating instances, otherwise I get the error.

I added print statements to show when files are being loaded. With autotest at startup I get this:
Loading `defprotocol` namespace
Loading `defrecord` namespace
Loading `defprotocol` namespace
so autotest is re-loading the `defprotocol` namespace.

If you want to have a closer look, I've placed my project at https://github.com/simon-katz/midje-protocols-records-in-different-ns.

BTW, this is not a big deal for me. As you say protocols don't play nicely with the REPL (a pity!), so I will limit my use of them.

FWIW, my understanding of protocols and records is that records by themselves can be an efficiency hack, and that records+protocols can be useful if you want multiple implementations. I haven't played with this yet, though.

Thanks,
Simon

Brian Marick

unread,
May 13, 2013, 2:10:50 PM5/13/13
to mi...@googlegroups.com

On Apr 12, 2013, at 7:11 AM, Simon Katz <nomi...@gmail.com> wrote:

> • If I move the `defrecord` form from "record.clj" to "protocol.clj", there is no problem.

You're not going to believe this one. Put a colon in front of `require` in the following form and autotest will start working:

(ns midje-protocols-records-in-different-ns.record
(require [midje-protocols-records-in-different-ns.protocol :refer [P]]))

For whatever reason, the lack of colon prevents Clojure from knowing that it's already loaded the `protocol` namespace.

Simon Katz

unread,
May 14, 2013, 5:54:04 AM5/14/13
to mi...@googlegroups.com
On Monday, 13 May 2013 19:10:50 UTC+1, Brian Marick wrote:
You're not going to believe this one. Put a colon in front of `require` in the following form and autotest will start working: 

(ns midje-protocols-records-in-different-ns.record
  (require [midje-protocols-records-in-different-ns.protocol :refer [P]]))

For whatever reason, the lack of colon prevents Clojure from knowing that it's already loaded the `protocol` namespace.

Wow! Good spot. (And bad lack of two spots.)
Reply all
Reply to author
Forward
0 new messages