2016-10-25 16 views
9

के बीच अंतर कैसे करता है मेरा other question डुप्लिकेट के रूप में बंद हो गया है, इसलिए मैं इसे फिर से कोशिश करूंगा। मैंने this question भी पढ़ा है और जो मैं पूछ रहा हूं वह अलग है। मुझे () => Type से अलग कैसे आंतरिक कार्यान्वयन सीखने में रूचि है।स्कैला() => टी और => टी

मेरा भ्रम जावप और cfr डिस्सेप्लर देखने से आ रहा है जो दो मामलों में कोई अंतर नहीं दिखाता है।

उदा। ParamTest.scala:

object ParamTest { 
    def bar(x: Int, y: => Int) : Int = if (x > 0) y else 10 
    def baz(x: Int, f:() => Int) : Int = if (x > 0) f() else 20 
} 

javap उत्पादनjavap ParamTest.scala:

public final class ParamTest { 
    public static int baz(int, scala.Function0<java.lang.Object>); 
    public static int bar(int, scala.Function0<java.lang.Object>); 
} 

सीएफआर decompiled उत्पादनjava -jar cfr_0_118.jar ParamTest$.class:

import scala.Function0; 

public final class ParamTest$ { 
    public static final ParamTest$ MODULE$; 

    public static { 
     new ParamTest$(); 
    } 

    public int bar(int x, Function0<Object> y) { 
     return x > 0 ? y.apply$mcI$sp() : 10; 
    } 

    public int baz(int x, Function0<Object> f) { 
     return x > 0 ? f.apply$mcI$sp() : 20; 
    } 

    private ParamTest$() { 
     MODULE$ = this; 
    } 
} 

संपादित करें 1: स्काला सिंटेक्स पेड़: scalac -Xprint:parse ParamTest.scala

package <empty> { 
    object ParamTest extends scala.AnyRef { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    def bar(x: Int, y: _root_.scala.<byname>[Int]): Int = if (x.$greater(0)) 
     y 
    else 
     10; 
    def baz(x: Int, f: _root_.scala.Function0[Int]): Int = if (x.$greater(0)) 
     f() 
    else 
     20 
    } 
} 

संपादित 2: मेलिंग सूची अनुसंधान:

मेलिंग सूची जो अनिवार्य रूप से कहा गया है कि => T() => T के रूप में कार्यान्वित किया जाता है पर इस interesting post पढ़ें। उद्धरण:

सबसे पहले,

f: => Boolean

को देखो, यह वास्तव में एक Function0 के रूप में कार्यान्वित किया जाता है हालांकि यह एक "द्वारा नाम पैरामीटर" कहा जाता है

f:() => Boolean

बस दोनों सिरों पर इस्तेमाल विभिन्न वाक्यविन्यास के साथ।

अब मैं this answer द्वारा और भी उलझन में हूं जो स्पष्ट रूप से कहता है कि दोनों अलग हैं।

प्रश्न:

  • कैसे स्काला baz से bar भेद है? दोनों के लिए विधि हस्ताक्षर (कार्यान्वयन नहीं) decompiled कोड में समान हैं।
  • क्या दो परिदृश्यों में अंतर संकलित बाइटकोड में नहीं टिकता है?
  • क्या असंगत कोड गलत है?
  • संपादित करें 1 संपादित करने के बाद जोड़ा गया: मैंने पाया कि स्केलैक सिंटैक्स पेड़ एक अंतर दिखाता है, bar का दूसरा तर्क _root_.scala.<byname>[Int] है। यह क्या करता है?कोई स्पष्टीकरण, scala source या समकक्ष छद्म कोड में पॉइंटर्स उपयोगी होंगे।
  • से ऊपर संपादित 2 देखें: क्या उद्धृत ब्लॉक सही है? जैसा कि Function0 का एक विशेष उप-वर्ग है?
+2

JVM बाइटकोड में इन प्रकारों का प्रतिनिधित्व कैसे किया जाता है यह महत्वपूर्ण क्यों है? वे स्कैला कोड में अलग हैं, यह महत्वपूर्ण है (जब तक आप जावा से स्कैला को कॉल करने की कोशिश नहीं कर रहे हैं, लेकिन यह नहीं है कि आप क्या पूछ रहे हैं)। –

+0

क्योंकि स्कैला उस तरह से काम करता है। यह स्कैला कोड को .class फ़ाइलों में संकलित करता है और JVM में निष्पादित करता है। इसलिए .class फ़ाइल में आवश्यक और पर्याप्त जानकारी होनी चाहिए। स्कैला स्रोत फाइलें बिल्कुल महत्वपूर्ण नहीं हैं। [लिंक किए गए प्रश्न] देखें (http://stackoverflow.com/questions/40246137/what-does-double-right-arrow-type-with-no-lhs-mean-in-function-argument/), आप पुन: पेश कर सकते हैं 'ParamTest.scala' स्रोत फ़ाइल को हटाने के बाद 'foo (baz, 100)' को कॉल करने में त्रुटि। – vsnyc

+0

इस प्रश्न के लिए एक और प्रेरणा है [यह उत्तर] (http://stackoverflow.com/a/13337382/2063026) जहां सबसे ऊपर की टिप्पणी (160) जोर देती है, मैं उद्धरण देता हूं: "इसके अलावा," कॉल-बाय-नाम "में नामों से कोई लेना देना नहीं है। '=> Int' 'Int' से एक अलग प्रकार है; यह" कोई तर्क नहीं है जो एक इंट बनाम बनाम इंट उत्पन्न करेगा "। लेकिन जैसा कि हम ऊपर देखते हैं, यह मामला नहीं है। कॉल-बाय-नाम आलसी मूल्यांकन के साथ करना है, न कि यह कोई तर्क का कार्य है ... – vsnyc

उत्तर

4

स्कैला baz से अलग कैसे है? विधि हस्ताक्षर ( कार्यान्वयन नहीं) दोनों के लिए डिकंपील्ड कोड में समान हैं।

स्कैला को की आवश्यकता नहीं है दोनों के बीच अंतर करें। इसके परिप्रेक्ष्य से, ये दो अलग-अलग विधियां हैं। दिलचस्प बात यह है (मेरे लिए कम से कम) है कि यदि हम bar में baz नाम बदलने और एक "कॉल-दर-नाम" पैरामीटर के साथ एक अधिभार बनाने का प्रयास करने पर हम पाते है:

Error:(12, 7) double definition: 
method bar:(x: Int, f:() => Int)Int and 
method bar:(x: Int, y: => Int)Int at line 10 
have same type after erasure: (x: Int, f: Function0)Int 
    def bar(x: Int, f:() => Int): Int = if (x > 0) f() else 20 

कौन सा हमें उस के लिए एक संकेत है कवर के तहत, Function0 पर अनुवाद के साथ कुछ चल रहा है।

क्या दो परिदृश्यों में अंतर संकलित बाइटकोड में नहीं टिकता है?

स्कैला जेवीएम बाइटकोड उत्सर्जित करने से पहले, इसमें संकलन के अतिरिक्त चरण हैं।

[[syntax trees at end of uncurry]] 
package testing { 
    object ParamTest extends Object { 
    def <init>(): testing.ParamTest.type = { 
     ParamTest.super.<init>(); 
    () 
    }; 
    def bar(x: Int, y:() => Int): Int = if (x.>(0)) 
     y.apply() 
    else 
     10; 
    def baz(x: Int, f:() => Int): Int = if (x.>(0)) 
     f.apply() 
    else 
     20 
    } 
} 

होने से पहले ही हम बाइट कोड फेंकना, bar एक Function0 में अनुवाद किया गया है: इस मामले में एक दिलचस्प एक "uncurry" मंच (-Xprint:uncurry) को देखने के लिए है।

decompiled कोड गलत

नहीं है, यह निश्चित रूप से सही है।

मैंने पाया scalac वाक्य रचना पेड़ एक अंतर दिखाने करता है कि, बार है प्रकार जड़ .scala का दूसरा तर्क। [इंट]। क्या करता है?

स्कैला संकलन चरणों में किया जाता है, जहां प्रत्येक चरण आउटपुट अगले इनपुट में होता है। पार्स किए गए एएसटी के अलावा, स्कैला चरण भी प्रतीक बनाते हैं, जैसे कि यदि एक चरण एक विशेष कार्यान्वयन विस्तार पर निर्भर करता है तो यह उपलब्ध होगा।<byname> एक कंपाइलर प्रतीक है जो दिखाता है कि यह विधि "कॉल-बाय-नेम" का उपयोग करती है, ताकि चरणों में से कोई एक इसे देख सके और इसके बारे में कुछ कर सके।

+0

बहुत उपयोगी, इसका उत्तर देने के लिए अपना समय लेने और सही दिशा में मुझे मार्गदर्शन करने के लिए धन्यवाद! – vsnyc

+2

@vsnyc आपका स्वागत है। उन प्रश्न पूछना, इस तरह हम सभी सीखते हैं। खुशी है कि मैं मदद कर सकता हूं। –

+0

महान, महान उत्तर! – Ashesh

3

स्कैला कोड को संकलक द्वारा विश्लेषण किया गया है और जेवीएम बाइटकोड में बदल दिया गया है। स्केल स्तर पर आपके पास प्रभावशाली, बहुत मजबूत प्रकार प्रणाली है, नाम पैरामीटर द्वारा कॉल करें और इस तरह की अन्य सामग्री। बाइटकोड में यह सब चला गया है। कोई घुमावदार पैरामीटर, कोई प्रभाव नहीं, केवल सादे तरीके। रनटाइम को () => A और => A को अलग करने की आवश्यकता नहीं है, यह केवल बाइटकोड निष्पादित करता है। सभी चेक और सत्यापन, आपको प्राप्त त्रुटियां कंपाइलर से होती हैं जो स्केल कोड का विश्लेषण करती है, बाइटकोड नहीं। नाम से संकलन की प्रक्रिया में बस Function0 के साथ प्रतिस्थापित किया गया है और ऐसे पैरामीटर के सभी उपयोगों पर apply विधि है, लेकिन यह पार्स चरण में नहीं होती है, लेकिन बाद में, आप संकलक आउटपुट में <byname> देखते हैं। बाद के चरणों को देखने का प्रयास करें।

3

क्योंकि स्कैला इस तरह से काम करता है। यह स्कैला कोड को .class फ़ाइलों में संकलित करता है और JVM में निष्पादित करता है। इसलिए .class फ़ाइल में आवश्यक और पर्याप्त जानकारी होनी चाहिए।

ऐसा करता है। यह जानकारी @ScalaSignature नामक एनोटेशन में संग्रहीत है। javap -v अपनी उपस्थिति दिखाना चाहिए, लेकिन यह मानव-पठनीय नहीं है।

जो JVM बाईटकोड में प्रतिनिधित्व नहीं जा सकती है स्काला हस्ताक्षर में जानकारी का एक बहुत कुछ है, क्योंकि यह आवश्यक है: बस द्वारा नाम नहीं बनाम Function0 मानकों, लेकिन पहुँच क्वालिफायर, पैरामीटर नाम, आदि

+0

पुष्टि करने के लिए धन्यवाद। युवाल का जवाब बहुत उपयोगी रहा है, इससे मुझे सही दिशा में ले जाया गया। अब मैं और अधिक पढ़ रहा हूं [ यह जवाब] (http: // stackoverflow।कॉम/ए/3312036/2063026) [वॉनसी] से (http://stackoverflow.com/users/6309/vonc)। – vsnyc

+1

ध्यान दें कि यह केवल प्राचीन स्कैला संस्करणों पर ही लागू होता है: 'स्कालासिग' विशेषता को स्कैला 2.8 में 'स्कालासिग्नेचर' द्वारा प्रतिस्थापित किया गया था। –

+0

धन्यवाद, मैं इसका एक नोट बनाउंगा। – vsnyc

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