2012-06-30 10 views
8

Credo di capire la nuova funzione di "classe di valore" di Scala 2.10, dal confronto con newtype di Haskell:Che aspetto hanno le classi di valore definite dall'utente da Java?

trait BoundedValue[+This] extends Any { this: This => 

    def upperBound: This 

    def lowerBound: This 

} 

class Probability @throws(classOf[IllegalArgumentException]) (v: Double) extends AnyVal with BoundedValue[Probability] { 

    val value: Double = if ((v >= 0.0) && (v <= 1.0)) v else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]") 

    override val upperBound: Probability = new Probability(0.0) 

    override val lowerBound: Probability = new Probability(1.0) 

    // Implement probability arithmetic here; 
    // will be represented by Double at runtime. 

} 

La domanda che ho è, come fa una classe di valori sembrano codice Java che utilizza il pacchetto Scala in cui è dichiarato? La classe value appare come una classe di riferimento dal lato Java, oppure viene cancellata completamente (e quindi appare come il tipo che esegue il wrapping)? In altre parole, quanto sono sicuri i tipi sono classi di valore quando Java è coinvolto nel livello sorgente?


EDIT

Il codice di cui sopra non viene compilato, secondo il documento SIP-15 (collegato nella risposta di Daniel), perché classi di valore non è consentito avere qualsiasi logica di inizializzazione, perché o v deve essere esplicitamente val o Probability deve avere un metodo unbox e un corrispondente metodo box sul suo oggetto companion e poiché le classi valore devono avere esattamente un campo. Il codice corretto è:

trait BoundedValue[This <: BoundedValue[This]] extends Any { this: This => 

    def upperBound: This 

    def lowerBound: This 

} 

class Probability private[Probability] (value: Double) extends AnyVal with BoundedValue[Probability] { 

    @inline override def upperBound: Probability = new Probability(0.0) 

    @inline override def lowerBound: Probability = new Probability(1.0) 

    @inline def unbox: Double = value 

    // Implement probability arithmetic here; 
    // will be represented by Double at runtime (mostly). 

} 

object Probability { 

    @throws(classOf[IllegalArgumentException]) 
    def box(v: Double): Probability = if ((v >= 0.0) && (v <= 1.0)) new Probability(v) else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]") 

} 

La domanda stessa è ancora valido come è, tuttavia.

+1

Nel programma di test, è stato possibile trasferire il valore spostato all'esterno dei limiti validi da Java? –

+0

@DavidHarkness In questo momento non ho accesso ad una macchina con 2.10.0-M4, quindi non lo so. Controllerò quando posso. –

risposta

6

Le classi di valore vengono compilate come classi normali e possono apparire come riferimenti.

La magia in loro è che, quando la classe valore non sfugge la portata, ogni traccia di esso vengono cancellati dal codice, inlining in modo efficace tutto il codice. E, naturalmente, dando ulteriore sicurezza al tipo.

Vedere anche SIP-15, che spiega la meccanica.

+0

Grazie! Pensavo di aver letto il SIP, ma suppongo di no. –

+2

Una domanda altrettanto interessante di "in che modo i tipi di valori Scala codificati su una piattaforma che non ha i tipi di valore stesso (ad esempio JVM)" è "come sono codificati i tipi di valori Scala su una piattaforma che * ha * ha stessi tipi di valore (ad es. CLI)". Ad esempio, i tipi di valori Scala possono essere compilati nelle strutture sulla CLI? È garantito che verranno * sempre * compilati per le strutture? –

+1

La tua domanda è molto interessante, ma mi sono reso conto che non solo le strutture della CLI non sono supportate (non erano menzionate nel SIP, l'ultima volta che l'ho letto), ma probabilmente sono anche inutili. Le classi di valore possono avere un solo campo, come i newtypes di Haskell, quindi penso che usare le strutture e non i primitivi non aiuterebbe. Le strutture hanno molti vantaggi per l'utilizzo della memoria, ma per utilizzarle è necessario fornire un meccanismo separato, ovvero un'annotazione che richiede questo comportamento che può essere ignorato. Il problema semantico è che le strutture dovrebbero probabilmente ereditare da AnyVal solo sulla CLI, non sulla JVM. – Blaisorblade