2011-11-19 22 views
8

क्यों इस स्काला कोड है:स्काला टुपल को अनपॅक करते समय एक नया ट्यूपल क्यों बनाता है?

class Test 
{ 
    def foo: (Int, String) = 
    { 
    (123, "123") 
    } 

    def bar: Unit = 
    { 
    val (i, s) = foo 
    } 
} 

bar() है कि एक नए Tuple2 निर्माण के लिए निम्नलिखित बाईटकोड उत्पन्न करते हैं, यह करने के लिए foo() से Tuple2 गुजरता है और फिर उससे बाहर मूल्यों हो जाता है?

public void bar(); 
Code: 
0: aload_0 
1: invokevirtual #28; //Method foo:()Lscala/Tuple2; 
4: astore_2 
5: aload_2 
6: ifnull 40 
9: new  #7; //class scala/Tuple2 
12: dup 
13: aload_2 
14: invokevirtual #32; //Method scala/Tuple2._1:()Ljava/lang/Object; 
17: aload_2 
18: invokevirtual #35; //Method scala/Tuple2._2:()Ljava/lang/Object; 
21: invokespecial #20; //Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V 
24: astore_1 
25: aload_1 
26: invokevirtual #39; //Method scala/Tuple2._1$mcI$sp:()I 
29: istore_3 
30: aload_1 
31: invokevirtual #35; //Method scala/Tuple2._2:()Ljava/lang/Object; 
34: checkcast  #41; //class java/lang/String 
37: astore 4 

इस वजह संकलक जाँच नहीं कर रहा है कि foo() रों वापसी मान एक टपल नहीं है है?

क्या JVM निर्माण को किसी भी तरह से अनुकूलित करेगा?

+0

'foo' का वापसी मूल्य _is_ एक tuple। आपको ऐसा क्यों लगता है कि यह नहीं है? –

+0

foo एक प्रकार लौटाता है, लेकिन 9: बार में() यह एक नया ट्यूपल बनाता है। –

उत्तर

4

यह लगता है बनाने के लिए कोड उत्पन्न करने के लिए की प्रासंगिकता का spec (में 4.1 मूल्य घोषणाएं और परिभाषाएँ के अनुसार किया जाना है - थोड़ा stackoverflow लिए पुन: स्वरूपित प्रदर्शन):

मूल्य परिभाषाओं के वैकल्पिक रूप से एक पैटर्न (§8.1) बाईं ओर के रूप में हो सकता है।

  1. तो पैटर्न p बाध्य है चर x1, . . . , xn, जहां n >= 1: अगर p कुछ एक साधारण नाम या एक नाम एक बृहदान्त्र और एक प्रकार के द्वारा पीछा के अलावा अन्य पैटर्न है, तो मूल्य परिभाषा val p = e इस प्रकार का विस्तार होता है यहां, $x एक नया नाम है।
val $x = e match {case p => (x1, . . . , xn)} 
    val x1 = $x._1 
    . . . 
    val xn = $x._n 

तो टपल निर्माण पार्सर चरण में होता है। तो करने के लिए पार्सर चरण के अंत में val (i, s) = (1, "s") और अधिक खर्च:

private[this] val x$1 = scala.Tuple2(1, "s"): @scala.unchecked match {  
    case scala.Tuple2((i @ _), (s @ _)) => scala.Tuple2(i, s) 
}; 
val i = x$1._1; 
val s = x$1._2 

यह साधारण परीक्षण पर इस मापने एक लाख पुनरावृत्तियों पर:

def foo: (Int, String) = (123, "123") 
def bar: Unit = { val (i, s) = foo } 
def bam: Unit = { val f = foo; val i = f._1; val s = f._2 } 

पैदावार

foo: Elapsed: 0.030 
bar: Elapsed: 0.051 
._1 ._2 access: Elapsed: 0.040 

और -optimize ध्वज के साथ :

foo: Elapsed: 0.027 
bar: Elapsed: 0.049 
._1 ._2 access: Elapsed: 0.029 
+0

धन्यवाद। बीटीडब्लू, स्काला 2.9 कंपाइलर के साथ और बिना -ऑप्टिमाइज़ टेस्ट क्लास के लिए उसी बाइटकोड उत्पन्न करता है, लेकिन शायद यह समय को तेज़ी से बनाने के लिए बेंचमार्किंग कोड पर मदद करता है। –

4

यह स्केलैक में एक मिस्ड अनुकूलन अवसर की तरह लगता है।

संकलक हमें Unapplies#caseClassUnapplyReturnValue, जो TreeDSL#SOME कॉल एक नया TupleN