La trasparenza referenziale non è un concetto definito formalmente ma
usually means that an expression always evaluates to the same result in any context. Source
Ecco un semplice test per la trasparenza referenziale per un'espressione e
: fa inline una dichiarazione di e
modifica (potenziale) comportamento?
Cioè, c'è una differenza tra:
val x = e
doFoo(x)
doBar(x)
e il seguente
doFoo(e)
doBar(e)
In questo caso c'è un'enorme differenza! Ad esempio, questo codice funzionerà correttamente:
val user = getPerson(32)
deleteUser(user)
displayUserDeletion(user)
mentre questo codice esploderà
deleteUser(getPerson(32))
displayUserDeletion(getPerson(32))
Quindi questo non è sicuramente referenzialmente trasparente. Per quanto riguarda la tua seconda domanda:
Perhaps the possibility of an Out of Memory or Stack Overflow error breaks RT?
Di solito quando pensiamo alla trasparenza referenziale o veramente a qualsiasi proprietà dei nostri programmi, pensiamo a loro come a macchine perfette con memoria infinita. Questa assunzione semplificativa è ovviamente sbagliata, ma davvero necessaria per parlare ovunque dei programmi. Fondamentalmente, stack overflow e OOM "break RT", quindi RT è sempre interrotta perché praticamente per qualsiasi espressione e
esiste un computer con un'espressione sufficientemente piccola tale che
val x = e
doFoo(x)
doBar(x)
funziona ma
doFoo(e)
doFoo(e)
esaurisce la memoria. Per evitare che la trasparenza referenziale sia un concetto inutile, dobbiamo ignorare la limitazione delle nostre runtime.
Questa definizione mostra anche perché dovremmo preoccuparci di RT, poiché consente ottimizzazioni potenti come l'eliminazione di sottoespressione comune ( i compilatori Haskell lo fanno ) dove se e
è RT possiamo fare in modo che venga valutata solo una volta, ad es trasformando
doFoo(e)
doBar(e)
in
val x = e
doFoo(x)
doBar(x)
Per quanto riguarda la domanda nel titolo, ci sono in realtà funzioni impure che sono referenzialmente trasparenti, ma è piuttosto una circostanza insolita:
- Supponiamo di avere un oggetto mutabile
S
che ha solo un metodo per modificarlo, S.f()
, cioè è idempotente. In questo caso S.f()
è impuro (cambia stato) ma è referenzialmente trasparente.
Per rendere questo più concreto, supponiamo di avere
class Foo {
private var _x = 0
def this(x: Int) { this(); _x = x }
def x = _x
def setXToFive(): Unit = {
_x = 5
}
}
Qui se foo : Foo
, foo.setXToFive()
è referenzialmente trasparente.