2013-04-17 7 views
11

मुझे क्लोजर रिकॉर्ड्स से संबंधित प्रतीत होता है कि थोड़ा आश्चर्यजनक व्यवहार है।रिकॉर्ड्स, प्रोटोकॉल और संकलन से संबंधित आश्चर्यजनक व्यवहार

  1. एक नाम स्थान एक रिकॉर्ड प्रकार परिभाषित करता है::

    (ns defrecordissue.arecord) 
    
    (defrecord ARecord []) 
    
  2. एक और नाम स्थान एक प्रोटोकॉल को परिभाषित करता है, और रिकॉर्ड टाइप 1 में परिभाषित करने के लिए इसे फैली

    सेटअप इस प्रकार है:

    (ns defrecordissue.aprotocol 
        (:require [defrecordissue.arecord]) 
        (:import [defrecordissue.arecord ARecord])) 
    
    (defprotocol AProtocol 
        (afn [this])) 
    
    (extend-protocol AProtocol 
        ARecord 
        (afn [this] 42)) 
    
  3. एक तीसरा नामस्थान रिकॉर्ड का एक उदाहरण बनाता है और रिकॉर्ड पर प्रोटोकॉल फ़ंक्शन को आमंत्रित करता है।

    Exception in thread "main" java.lang.IllegalArgumentException: No implementation of method: :afn of protocol: #'defrecordissue.aprotocol/AProtocol found for class: defrecordissue.arecord.ARecord, compiling:(aot1.clj:5:1) 
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3463) 
        at clojure.lang.Compiler.compile1(Compiler.java:7153) 
        at clojure.lang.Compiler.compile(Compiler.java:7219) 
        at clojure.lang.RT.compile(RT.java:398) 
        at clojure.lang.RT.load(RT.java:438) 
        at clojure.lang.RT.load(RT.java:411) 
        at clojure.core$load$fn__5018.invoke(core.clj:5530) 
        at clojure.core$load.doInvoke(core.clj:5529) 
        at clojure.lang.RestFn.invoke(RestFn.java:408) 
        at clojure.core$load_one.invoke(core.clj:5336) 
        at clojure.core$compile$fn__5023.invoke(core.clj:5541) 
        at clojure.core$compile.invoke(core.clj:5540) 
        at user$eval7.invoke(NO_SOURCE_FILE:1) 
        at clojure.lang.Compiler.eval(Compiler.java:6619) 
        at clojure.lang.Compiler.eval(Compiler.java:6609) 
        at clojure.lang.Compiler.eval(Compiler.java:6582) 
        at clojure.core$eval.invoke(core.clj:2852) 
        at clojure.main$eval_opt.invoke(main.clj:308) 
        at clojure.main$initialize.invoke(main.clj:327) 
        at clojure.main$null_opt.invoke(main.clj:362) 
        at clojure.main$main.doInvoke(main.clj:440) 
        at clojure.lang.RestFn.invoke(RestFn.java:421) 
        at clojure.lang.Var.invoke(Var.java:419) 
        at clojure.lang.AFn.applyToHelper(AFn.java:163) 
        at clojure.lang.Var.applyTo(Var.java:532) 
        at clojure.main.main(main.java:37) 
    Caused by: java.lang.IllegalArgumentException: No implementation of method: :afn of protocol: #'defrecordissue.aprotocol/AProtocol found for class: defrecordissue.arecord.ARecord 
        at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541) 
        at defrecordissue.aprotocol$fn__40$G__35__45.invoke(aprotocol.clj:5) 
        at clojure.lang.AFn.applyToHelper(AFn.java:161) 
        at clojure.lang.AFn.applyTo(AFn.java:151) 
        at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3458) 
        ... 25 more 
    

    अगर मैं 3 बदल) रिकॉर्ड के निर्माण के लिए:

    (ns defrecordissue.aot1 
        (:require [defrecordissue.aprotocol] 
          [defrecordissue.arecord])) 
    
    (defrecordissue.aprotocol/afn (defrecordissue.arecord/->ARecord)) 
    

जब defrecordissue.aot1 नाम स्थान मेरे मामले lein compile defrecordissue.aot1 का उपयोग करने में संकलित किया गया है,, संकलन निम्न अपवादों के साथ विफल रहता है कक्षा सीधे, जैसे:

(ns defrecordissue.aot2 
    (:require [defrecordissue.aprotocol] 
      [defrecordissue.arecord])) 

(defrecordissue.aprotocol/afn (defrecordissue.arecord.ARecord.)) 

संकलन सफल होता है।

मेरा संदेह यह है कि यह किसी भी तरह http://dev.clojure.org/jira/browse/CLJ-371 से संबंधित है, लेकिन मुझे बिल्कुल ठीक नहीं हो रहा है।

मैं भी lein clean बिना कि जोड़ना चाहिए, संकलन सफल होता है दूसरी बार के बाद से रिकॉर्ड के लिए एक वर्ग अब classpath पर उपलब्ध है। इसलिए, मैं एओटी-संकलन द्वारा रिकॉर्ड प्रकार को परिभाषित करने वाले नामस्थान द्वारा इस समस्या को हल कर सकता हूं। https://github.com/ragnard/defrecordissue

मैं इस व्यवहार क्यों दिखाई दे रहा है, और क्या यह से बचने के लिए सही तरीका है:

मुझे लगता है कि मुद्दे को दर्शाता है, के उपयोग के लिए README देख GitHub पर एक सरल leiningen प्रोजेक्ट बनाया?

अद्यतन

मैं GitHub रेपो के लिए एक नई शाखा जोड़ा बेहतर मुख्य मुद्दा illustrating: https://github.com/ragnard/defrecordissue/tree/more-realistic/

समस्या तब होती है, जहां (। यानी जो नाम स्थान में) रिकॉर्ड उदाहरण है की परवाह किए बिना का निर्माण किया।

+0

अच्छा विचार, हालांकि एक ही अपवाद। मुझे लगता है कि 'defrecordissue.arecord' किसी भी मामले में पहले लोड किया जाएगा, क्योंकि इसे' defrecordissue.aprotocol' – Ragge

+0

में भी आवश्यक है टिप्पणी से ऊपर एक और टिप्पणी से संबंधित था जो स्पष्ट रूप से हटा दिया गया था। – Ragge

उत्तर

2

मैं आपके रेपो के साथ समस्या का पुनरुत्पादन कर सकता हूं।

  1. बताएँ lein compile अधिक नामस्थान संकलित करने के लिए:

    lein compile defrecordissue.aprotocol defrecordissue.arecord defrecordissue.aot1 
    
  2. project.clj में

    :aot [defrecordissue.aprotocol defrecordissue.arecord defrecordissue.aot1] 
    

    रखो यहाँ तीन समाधान जो मेरे लिए काम है।

  3. project.clj में

    :aot :all 
    

    रखो।

बाद के दो lein compilelein aot1 का काम (2 के मामले में) करते हैं और lein aot1 और lein aot2 (3. के मामले में) दोनों।

+0

आपके उत्तर के लिए धन्यवाद। मुझे पता है कि मैं 'defrecordissue.arecord' नेमस्पेस संकलित एओटी द्वारा इस मुद्दे के आसपास हो सकता हूं। हालांकि, यह उस मामले में पूरी तरह से संतोषजनक नहीं है जहां समस्या उत्पन्न हुई थी। उस मामले में, 'defrecordissue.arecord' और ' defrecordissue.aprotocol' दोनों लाइब्रेरी का हिस्सा हैं और 'defrecordissue.aot1' केवल उस लाइब्रेरी का उपभोक्ता है, और रिकॉर्ड प्रकार (या यहां तक ​​कि प्रोटोकॉल)। यह इस प्रकार के उदाहरण के रूप में सीधे रिकॉर्ड प्रकार को तुरंत चालू नहीं करता है। यदि संभव है तो मैं किसी भी एओटी संकलित कक्षाओं के बिना पुस्तकालय वितरित करना चाहता हूं। – Ragge

0

मैं इस समय हर समय दौड़ता हूं। यह मैं क्या लेकर आए हैं और यह काम करने लगता है:

(defmacro with-datatype 
    [datatype & body] 
    (let [last-dot (.lastIndexOf ^String (str datatype) ".") 
     ns (-> datatype 
       str 
       (subs 0 last-dot) 
       symbol)] 
    `(do 
     (require (quote ~ns)) 
     (import ~datatype) 
     [email protected]))) 

(defmacro extend-type* 
    [datatype & extensions] 
    `(with-datatype ~datatype 
    (extend-type ~datatype 
     [email protected]))) 

(defmacro extend-protocol* 
    [protocol & specs] 
    (let [splitter (let [l (atom nil)] 
        #(if (symbol? %) (reset! l %) @l)) 
     specs (partition-by splitter specs)] 
    `(do 
     [email protected](for [[datatype & extensions] specs] 
      `(extend-type* ~datatype ~protocol [email protected]))))) 

तो फिर तुम केवल अपने दूसरे कोड ब्लॉक बदलने की जरूरत:

(ns defrecordissue.aprotocol) 

(defprotocol AProtocol 
    (afn [this])) 

(extend-protocol* AProtocol 
    defrecordissue.arecord.ARecord 
    (afn [this] 42)) 

हो सकता है कि साफ नहीं समाधान है, लेकिन आप डॉन अब आपके पुस्तकालयों को एओटी नहीं करना है।

संबंधित मुद्दे