Pular para o conteúdo

Escopo de recursos

Vários recursos, uma saída: o escopo solta tudo na ordem inversa da entrada — inclusive quando o corpo falha.

Um recurso é fácil de fechar. Cinco são fáceis de esquecer — e o esquecimento acontece sempre no mesmo lugar: o caminho de erro. O escopo resolve os dois: tudo o que entra sai junto, e sai na ordem inversa da entrada.

dataforge
adopt Arcane.Posse as P

saida := []
e := P.escopo()

e.dono("conexao", lambda x => saida.append(x))
e.dono("transacao", lambda x => saida.append(x))
arquivo := e.guardar(P.dono("arquivo", lambda x => saida.append(x)))

assert e.quantos() is 3
assert arquivo.usar(lambda x => len(x)) is 7

assert e.soltar() is 3
assert saida is ["arquivo", "transacao", "conexao"]      // do último ao primeiro
assert not e.vivo() and e.soltar() is 0                  // idempotente

com_escopo: e o caminho de erro também#

dataforge
adopt Arcane.Posse as P

saida := []

monitor:
    P.com_escopo(lambda e => e.dono("a", lambda x => saida.append(x))
                              .usar(lambda x => trigger "no meio"))
handle Error as e:
    assert e.message is "no meio"

assert saida is ["a"]          // soltou mesmo com o corpo falhando

E um recurso que falha ao fechar não deixa os outros abertos: o escopo solta todos e relata depois — o mesmo raciocínio do defer, que também não engole o erro.

Quando usar cada um#

SituaçãoA peça
um recurso, um usoP.com(dono, acao)
vários recursos que saem juntosP.com_escopo(lambda e => …)
o recurso vive além da açãoP.dono(…) devolvido, e quem recebe solta
muitos donos, saída no últimoP.compartilhado(…)
fechar no fim da ação, sem objeto novodefer, que a linguagem já tem