2014-06-17 35 views
5

Więc Option[Int] lub Option[String] czy o to chodzi Option[A] skutkuje Some(A) lub None, ale Boolean jest inna, gdyż z natury oznacza podwójne stany (true/false), czy to ma sens mieć Option[Boolean]? Często spotykam się z tym, gdy odpowiedź JSON nie powinna zawierać pola boolowskiego opartego na pewnej logice biznesowej.Scala: Czy opcja [Boolean] ma sens?

Jakieś myśli?

+4

Oczywiście, jest to uzasadniona reprezentacja dla stanu trójstanowego: Prawdziwy, Fałszywy, Niewiedzać/Nie dbać. –

+1

może nie jest optymalna pod względem wydajności (ponieważ jest to klasa w pełni rozwinięta), ale dlaczego nie? Jeśli chcesz zoptymalizować, możesz zakodować go jako bajt lub int, na przykład –

Odpowiedz

7

Optionality to ortogonalny problem dotyczący rodzaju danych. Więc tak, Option[Boolean] ma tyle samo sensu, co Option[Int].

Porozmawiajmy o twoim konkretnym przypadku użycia.


Jeśli reguła biznesu mówi pola (powiedzmy) isPrimeTime musi być typu Boolean, ale nie jest obowiązkowe, to należy modelować go z Option[Boolean].

None w tym kontekście wskazuje na brak wartości, Some(true) oznaczałoby „obecny i prawdziwe”, Some(false) oznaczałoby „obecny i fałsz”. Pozwoliłoby to również na dodawanie domyślne w kodzie jak poniżej:

val isPrimeTime = json.getAs[Option[Boolean]]("isPrimeTime").getOrElse(false) 

Można stosować różne Option kombinatorów innych przypadkach powszechnego użytku, które pojawiają się w takich ustawieniach. (Chciałbym dać pracę wyobraźni na ten temat.)


Jeśli domena ma dużo tych „trójstanowych” pól, a jeśli trzeci stan wskazuje na pewne specyficzne dla domeny pomysł, co nie wynika z kontekstu, Zdecydowanie radzę utworzyć własny rodzaj sum. Nawet jeśli możesz technicznie nadal używać Option[Boolean], może to nie być dobre dla twojego zdrowia psychicznego. Oto przykład.

sealed trait SignalValueIndication 
case class Specified(value: Boolean) extends SignalValueIndication 
case object DontCare extends SignalValueIndication 

// Use 
val signalValue = signalValueIndication match { 
    case Specified(value) => value 
    case DontCare => chooseOptimalSignalValueForImpl 
} 

To wydaje się jak byłoby to ogromne marnotrawstwo, ponieważ jesteś utraty kombinatorów dostępny na Option. Częściowo dobrze. Częściowo dlatego, że ponieważ oba typy są izomorficzne, pisanie mostów nie byłoby tak trudne.

sealed trait SignalValueIndication { 
    // ... 
    def toOption: Option[Boolean] = this match { 
    case Specified(value) => Some(value) 
    case DontCare => None 
    } 

    def getOrElse(fallback: => Boolean) = this.toOption.getOrElse(fallback) 
} 

object SignalValueIndication { 
    def fromOption(value: Option[Boolean]): SignalValueIndication = { 
    value.map(Specified).getOrElse(DontCare) 
    } 
} 

To wciąż znacząca powielanie i trzeba oceniać indywidualnie w każdym przypadku-to-czy dodany klarowność nadrabia.

Podobna opinia została wydana przez HaskellTips na Twitterze niedawno i podobna dyskusja nastąpiła. Możesz go znaleźć here.


Czasami obecność lub brak pola jest decyzją, którą można zakodować w strukturze danych. Używanie Option może być w takich przypadkach nieprawidłowe.

Oto przykład. Wyobraź sobie, że istnieje pole differentiator, dla którego dozwolone są następujące dwa rodzaje wartości.

// #1 
{ "type": "lov", "value": "somethingFromSomeFixedSet" }, 

// #2 
{ "type": "text", "value": "foo", "translatable": false } 

Tutaj zakładamy pole translatable jest obowiązkowe, ale tylko dla ` "type": "tekst".

Można modelować go Option tak:

case class Differentiator(
    _type: DifferentiatorType, 
    value: String, 
    translatable: Option[Boolean] 
) 

jednak lepszy sposób na modelu, który będzie: Effective ML rozmowa

sealed trait Differentiator 
case class Lov(value: String) extends Differentiator 
case class Text(value: String, translatable: Boolean) extends Differentiator 

Yaron Minsky zawiera sekcję w tej sprawie. Może się to okazać pomocne. (Chociaż używa ML do zilustrowania punktów, rozmowa jest całkiem dostępna i dotyczy również programistów Scala).

10

To jest poprawne użycie Option[Boolean]. Załóżmy, że mam działającą pracę, która zajmie trochę czasu, a ja chcę mieć wartość, która wskaże, czy praca zakończyła się sukcesem, czy nie. Sugeruje to wartość typu Option[Boolean].

  • Do czasu zakończenia zadania nie wiem, czy zakończyło się pomyślnie, czy nie, więc ma wartość None.
  • Po zakończeniu zadania zakończyło się sukcesem lub nie, więc ma wartość Some(true) lub Some(false).
+0

Kudos, jeśli możesz podać przykład dla opcji [Option [Option [Boolean]] ". –

+1

Dla dowolnego 'X', możesz chcieć użyć' Opcji [X] ', aby wskazać, czy' X' jest dostępne. Załóżmy na przykład, że masz podzadania do sprawdzania, czy praca jest sukcesem; to podzadanie zgłasza 'Option [Boolean]', aby wskazać sukces/niepowodzenie/niekompletność, i możesz zwrócić 'Option [Option [Boolean]]', aby wskazać, że podzadanie nie odpowiada. W końcu możesz go spłaszczyć, ale na początku chcesz bardzo odmiennie reagować na niepowodzenie zadania i awarię zadania. –

+0

@RexKerr Miałem na myśli humor. :) Ale dobre wyjaśnienie. –