2015-09-19 9 views
5

क्या कोई प्रकार-सुरक्षित स्केल के लिए === कार्यान्वयन के बराबर है जिसमें == से शून्य ओवरहेड है? स्कालाज़ और स्कैलाउटिल्स में === के विपरीत, एक कार्यान्वयन जो चेक करने के लिए सीधे मैक्रो का उपयोग करता है?टाइप-सुरक्षित मैक्रो के बराबर है?

मैं कई जगहों पर === का उपयोग करना चाहता हूं लेकिन ये हॉट-स्पॉट हैं, इसलिए मैं नहीं चाहता कि कोई अतिरिक्त रनटाइम लागत (जैसे प्रकार के वर्गों और ऐसे निर्माण) का निर्माण करना चाहें।

+1

एक मैक्रो कार्यान्वयन आपको एक अंतर्निहित मूल्य वर्ग पर क्या खरीदता है? –

+0

@TravisBrown मूल्य वर्ग आवंटन लागत को बचाते हैं, लेकिन अगर मैं गलत नहीं हूं, तो इंडिकेशन लागत को न बचाएं। यह प्रासंगिक हो सकता है: http://typelevel.org/blog/2015/08/06/machinist.html –

उत्तर

1

मुझे लगता है कि आप machinist के साथ इसे आसानी से प्राप्त कर सकते हैं।

GitHub पर README बिल्कुल === उदाहरण देता है:

import scala.{specialized => sp} 

import machinist.DefaultOps 

trait Eq[@sp A] { 
    def eqv(lhs: A, rhs: A): Boolean 
} 

object Eq { 
    implicit val intEq = new Eq[Int] { 
    def eqv(lhs: Int, rhs: Int): Boolean = lhs == rhs 
    } 

    implicit class EqOps[A](x: A)(implicit ev: Eq[A]) { 
    def ===(rhs: A): Boolean = macro DefaultOps.binop[A, Boolean] 
    } 
} 

तो आप ==


से अधिक शून्य भूमि के ऊपर (बिना किसी अतिरिक्त आवंटन, बिना किसी अतिरिक्त अविवेक) के साथ === उपयोग कर सकते हैं यदि आप हैं आउट ऑफ़ द बॉक्स कार्यान्वयन की तलाश में, spire (जिसमें से मशीनिन का जन्म हुआ) एक प्रदान करता है।

भी cats एक प्रदान करता है।

वे दोनों मैक्रो-आधारित हैं क्योंकि वे कार्यान्वयन के लिए machinist का उपयोग करते हैं।

+0

स्पायर और बिल्लियों में कार्यान्वयन के लिए दोनों प्रकार के वर्ग उदाहरणों की आवश्यकता होती है, हालांकि, आपको यह ध्यान रखना होगा कि आप ' प्रत्येक उपयोग पर उनको तुरंत चालू नहीं कर रहे हैं, आदि –

+0

@TravisBrown, मुझे यकीन नहीं है कि मैं अनुसरण करता हूं। जब तक आप 'ईकॉप्स' से 'ev' का उपयोग नहीं करते हैं, तब तक आपको ठीक होना चाहिए, क्योंकि टाइप क्लास केवल समानता संचालन की उपलब्धता के प्रमाण के रूप में उपयोग की जाती है। क्या मै गलत हु? –

0

मशीनिनिस्ट पर आधारित उत्तर शायद सबसे अच्छा है।

import scala.collection.breakOut 
import scala.language.experimental.macros 
import scala.reflect.macros.blackbox 

object Implicits { 
    implicit class TripleEquals[A](a: A) { 
    def === [B >: A](b: B): Boolean = macro Macros.equalsImpl[A, B] 
    } 
} 

object Macros { 
    private val positiveList = Set("scala.Boolean", "scala.Int", "scala.Long", 
           "scala.Float", "scala.Double", "scala.Option) 
    private val negativeList = Set("java.lang.Object", "java.io.Serializable", 
           "<refinement>") 

    def equalsImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: blackbox.Context) 
                (b: c.Expr[A]): c.Tree = { 
    import c.universe._ 
    val bTpe = weakTypeOf[B] 
    val base = bTpe.baseClasses 
    val names: Set[String] = base.collect { 
     case sym if sym.isClass => sym.fullName 
    } (breakOut) 

    // if a primitive is inferred, we're good. otherwise: 
    if (names.intersect(positiveList).isEmpty) { 
     // exclude all such as scala.Product, scala.Equals 
     val withoutTopLevel = names.filterNot { n => 
     val i = n.lastIndexOf('.') 
     i == 5 && n.startsWith("scala") 
     } 
     // exclude refinements and known Java types 
     val excl = withoutTopLevel.diff(negativeList) 
     if (excl.isEmpty) { 
     c.abort(c.enclosingPosition, s"Inferred type is too generic: `$bTpe`") 
     } 
    } 

    // now simply rewrite as `a == b` 
    val q"$_($a)" = c.prefix.tree 
    q"$a == $b" 
    } 
} 

यह उच्च kinded प्रकार के साथ काम नहीं करता है, फिर भी, इसलिए tuples: यहाँ एक और अधिक hackish संस्करण है कि इस तरह Any या AnyRef या दो असंबंधित मामले वर्गों (Product with Serializable) के विशिष्ट मिश्रण का निष्कर्ष निकालते के रूप में मामलों का पता लगाता है दुर्भाग्यवश Some(1) === Some("hello") संकलित करते समय जानबूझ कर असफल हो रहे हैं।


संपादित: एक अंतर्निहित a small library है कि इस पर सुधार उच्च kinded प्रकारों का समर्थन करने के लिए।

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