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 // idempotentecom_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 falhandoE 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ção | A peça |
|---|---|
| um recurso, um uso | P.com(dono, acao) |
| vários recursos que saem juntos | P.com_escopo(lambda e => …) |
| o recurso vive além da ação | P.dono(…) devolvido, e quem recebe solta |
| muitos donos, saída no último | P.compartilhado(…) |
| fechar no fim da ação, sem objeto novo | defer, que a linguagem já tem |