try... after and clean-up
Richard Carlsson
richardc@REDACTED
Tue Jan 10 12:17:40 CET 2006
Hi!
The basic pattern should be something like this, for
each individual resource:
{ok, Handle} = allocate_resource(),
try
use_resource(Handle)
after
free_resource(Handle)
end
That is, you make sure that the 'try...after...end' is entered
*if and only if* the resource has been allocated. (If the
allocation failed, there is nothing to clean up.) It must not
be possible to get an exception _after_ the resource has been
successfully allocated, which prevents the free_resource()
from being executed (e.g., if the allocate_resource() call
above would return {true, Handle} rather than {ok, Handle}).
If that happens, you won't even know _how_ to refer to the
resource, since the handle will not be bound to any variable
in scope when that exception is finally caught (somewhere else).
Hence, don't put any unnecessary code between the allocation
and the start of the 'try'.
Assuming this is clear, the rest is easy. Preferably, you
lift out each use_resource() section to a separate function
rather than nesting, and maybe also put each allocate-use-free
block like the above in separate functions. You could even
abstract out the use-body, to get that functional feeling:
with_x(F) ->
{ok, R} = allocate_x(),
try F(R) after free_x(R) end.
...
with_x(fun (R) -> use_x(R, OtherArgs) end)
...
A less ambitious rewrite of your code could look as follows:
run(Args)
when is_record(Args, bot_args) ->
Bot = #bot {
poker_server = Args#bot_args.host,
dispatchers = [{"script",
Args#bot_args.script,
Args#bot_args.script_args
}],
log = Args#bot_args.log,
ignored = Args#bot_args.ignored,
lobby_bot = Args#bot_args.lobby_bot
},
Bot1 = notrace(Bot, [cl_ssl_handshake_data,
srv_ssl_handshake_data,
srv_update_hint_text,
cl_handshake,
srv_handshake,
srv_news]),
try
UtilSock = util:connect_script_server(),
try
Bot2 = Bot1#bot {
util_sock = UtilSock
},
Bot3 = util:connect(Bot2,
[lobby_con_wrap(),
lobby_handle_wrap(),
connected]), % event to post
try
run(Bot3, handle(Bot3, handshake))
after
%% cleanup Bot3
end
after
%% cleanup UtilSock
end,
after
%% cleanup Bot1
end.
Good luck!
/Richard
More information about the erlang-questions
mailing list