2013-03-04 17 views
5

Sto imparando Scala come un progetto personale perché sono stufo della verbosità di Java. Mi piace molto di quello che vedo, ma mi chiedo se c'è un modo per in modo efficiente implementare alcuni semplici contratti sui metodi. Io non sono (necessariamente) dopo la piena DBC, ma c'è un modo per: -Scala - design semplice per contratto

  1. indicano che un parametro o un campo di classe è necessario, vale a dire non può essere nullo. La cosa Option sembra indicare chiaramente se è presente un valore OPTIONAL, ma voglio specificare gli invarianti di classe (x è richiesto) e anche per specificare in modo succinto che è necessario un parametro. So che posso fare "if" per lanciare qualche tipo di eccezione, ma voglio una funzione linguistica per questo caso d'uso MOLTO comune. Mi piacciono le mie interfacce, non mi piace la programmazione difensiva.

  2. E 'possibile definire succinti ed efficienti (runtime performance) tipi di intervallo, come "NonNegativeInt" - Voglio dire che un parametro è> = 0. O all'interno di un intervallo. PASCAL aveva questi tipi e li ho trovati eccellenti per comunicare l'intento. Questo è uno dei maggiori svantaggi di C, C++, Java, ecc. Quando dico succinto Intendo dire che voglio dichiarare una variabile di questo tipo con la stessa facilità di un normale int, non dover creare ogni singola istanza sul mucchio.

+0

In realtà C e C++ ha int non negativo: ricerca "int unsigned" in google. –

+2

FYI: http://www.pm.inf.ethz.ch/education/theses/student_docs/Rokas_Matulis/Rokas_Matulis_MA_report Il plugin del compilatore sviluppato funziona per 2.10.0, ma non l'abbiamo ancora rilasciato in alcun modo (ancora) perché è - essendo una tesi di laurea - non è davvero stabile. –

+0

@ om-nom-nom. Si, sono d'accordo. E 'passato troppo tempo da quando ho fatto C/C++ ma è molto facile da eludere se ricordo. Ad ogni modo, il mio intento "reale" (mi dispiace) è stato quello di chiedere dei tipi numerici utili non solo NonNegativeInt. Un esempio sarebbe 'DegreesCentigrade', o qualsiasi altra cosa ** specifica per il dominio ** - maggiore sicurezza del tipo che mi è piaciuta in Pascal. –

risposta

7

Per il punto (1), Option dovrebbe infatti essere sufficiente. Questo perché mentre scala supporta valori nulli, lo fa principalmente per compatibilità con Java. Il codice Scala non dovrebbe contenere valori nulli, e dove dovrebbe essere limitato a luoghi molto localizzati e convertito in un'opzione il prima possibile (un buon codice di scala non consentirà mai la propagazione di valori nulli). Quindi in scala idiomatica, se un campo o parametro è non di tipo Option, ciò significa che è necessario.

Ora, c'è anche il carattere (sperimentale e mai completamente supportato per quanto posso dire) NotNull tratto. Vedi How does the NotNull trait work in 2.8 and does anyone actually use it?

Per il punto (2) scala 2.10 introduce value classes. Con loro, puoi definire la tua classe che avvolge Int senza sovraccarico di runtime e implementa i suoi operatori come meglio credi. Le uniche posizioni in cui si avrebbe un controllo di runtime si verificherebbero durante la conversione da un normale Int al numero NonNegativeInt (genera un'eccezione se l'int è negativo). Si noti che questo controllo verrà eseguito ogni volta che si crea un nuovo NonNegativeInt, il che significa anche ogni volta che si esegue un'operazione, quindi ci sarà un impatto di runtime non nullo. Ma Pascal si trovava nella stessa situazione (i controlli dell'intervallo sono eseguiti in fase di esecuzione in Pascal), quindi suppongo che tu stia bene con questo.

UPDATE: Ecco un esempio di implementazione NonNegativeInt (qui rinominato UInt):

object UInt { 
    def apply(i: Int): UInt = { 
    require(i >= 0) 
    new UInt(i) 
    } 
} 
class UInt private (val i: Int) extends AnyVal { 
    override def toString = i.toString 
    def +(other: UInt) = UInt(i + other.i) 
    def -(other: UInt) = UInt(i - other.i) 
    def *(other: UInt) = UInt(i * other.i) 
    def /(other: UInt) = UInt(i/other.i) 
    def <(other: UInt) = i < other.i 
    // ... and so on 
} 

e alcuni utilizzo esempio nel REPL:

scala> UInt(123) 
res40: UInt = 123 

scala> UInt(123) * UInt(2) 
res41: UInt = 246 

scala> UInt(5) - UInt(8) 
java.lang.IllegalArgumentException: requirement failed 
     at scala.Predef$.require(Predef.scala:221) 
     at UInt$.apply(<console>:15) 
     ... 
+0

OK, quindi il contratto non nullo è implicito in Scala idiomatica: posso accettarlo - usare Opzione per Opzionale. Preferirei comunque (fino a quando non diventerò più a mio agio con l'idioma che suppongo), potendo essere esplicito riguardo alla non nullità. Anche le classi di valore assomigliano al biglietto. Grazie. Quindi accettando la tua risposta –

4

Cos'è questo null di cui parli?

Seriamente, barra null ai bordi del sistema, dove viene in contatto con il codice che non è stato scritto. A quel confine ci si assicura che tutti i valori nullable siano convertiti in Option.

Allo stesso modo, non utilizzare le eccezioni. Come con null, barrali al cancello. Trasformali in Either o utilizza ScalaZ Validation.

Come per i tipi dipendenti (dove il tipo interagisce con o dipende da valori specifici o sottoinsiemi di valori come i numeri naturali) è più lavoro. Tuttavia, Spire ha un tipo Natural. Potrebbe non essere esattamente quello che vuoi dato che è una precisione arbitraria, ma impone l'aspetto non negativo dei numeri naturali.

Addendum

conversione da un valore annullabile al Option è banalmente ospitato dalla Scala standard Biblioteca stessa nella forma della Option factroy. A:

scala>  val s1 = "Stringy goodness" 
s1: String = Stringy goodness 

scala>  val s2: String = null 
s2: String = null 

scala>  val os1 = Option(s1) 
os1: Option[String] = Some(Stringy goodness) 

scala>  val os2 = Option(s2) 
os2: Option[String] = None 
+0

Grazie. Sto volendo ** documentare ** intento sulle mie interfacce, ma sono completamente d'accordo sul bandire i valori nulli al limite del sistema. Bello! Niente più controlli nulli difensivi. Ma questo non è applicato. I riferimenti C++ applicano (abbastanza vicino) la non nullità Sono ancora nuovo di Scala, quindi sono confuso su molte cose. Troppi anni sopportando Java :) –

+0

Come non viene applicata? I valori di 'Option' sono' None' o 'Some (valore)'. E il tipo stesso serve a documentare le possibili alternative. Infine, se 'null's provengono da un codice diverso da Scala, allora lo fanno e nessuna quantità di documentazione al contrario lo cambierà. Quindi non sono chiaro quale sia la tua obiezione. –

+0

Scusami. Intendevo se non dovevo seguire Scala idiomatica. Sto cercando un nuovo equilibrio, cioè in Java sto costantemente controllando contro null e lo odio. Ho bisogno di "lasciar andare" quel bagaglio! –