21
Ideas / Defer on functions.
« Last post by lerno on March 22, 2019, 11:35:51 AM »What if functions could add defer to the scope where they are invoked?
Here is some code:
This is fine, the resource is released no matter what path is taken. However, this always requires the defer.
I envisioned a defer sugar, like this:
This would sort of make it more succinct and would also make it possible to use it in an expression.
However, what if there was a "safe" version?
This would be fully equivalent to the code with defer above, but could then be written as:
Although resource management is a fine example of this, it's *really* nice for refcounting as if you write the following imaginary code:
If @rcmalloc returns 1, then rc would be 2 in the first case (except if we have special handling of assignment of RC) and a leak on the second line.
However, if @rcmalloc returns 0, then the second line also leaks.
However, if we let @rcmalloc return rc = 1 AND have the profile of @defer(release), then an implicit defer would ensure that in the scope where called the rc would eventually be decreased (unless assigned to). And this is basically what @autorelease in ObjC does too, but in a less controlled manner.
Even if the above example doesn't make sense, or refcounting shouldn't have language support, it's still a very good way to cheaply enable manual RC built on top of the language.
Here is some code:
Code: [Select]
func bool do_stuff(i32 resource_id)
{
Resource *x = get_resource(resource_id);
defer release_resource(x);
if (!play_around_with(x)) return false;
do_some_other_thing(x);
return foo(x);
}
This is fine, the resource is released no matter what path is taken. However, this always requires the defer.
I envisioned a defer sugar, like this:
Code: [Select]
func bool do_stuff(i32 resource_id)
{
Resource* x = get_resource(resource_id) @defer(release_resource);
if (!play_around_with(x)) return false;
do_some_other_thing(x);
return foo(x);
}
This would sort of make it more succinct and would also make it possible to use it in an expression.
However, what if there was a "safe" version?
Code: [Select]
func Resource get_resource_with_release(i32 resource_id) @defer(release_resource)
{ ... }
This would be fully equivalent to the code with defer above, but could then be written as:
Code: [Select]
func bool do_stuff(i32 resource_id)
{
Resource* x = get_resource_with_release(resource_id); // inserts an implicit defer!
if (!play_around_with(x)) return false;
do_some_other_thing(x);
return foo(x);
}
Although resource management is a fine example of this, it's *really* nice for refcounting as if you write the following imaginary code:
Code: [Select]
Foo@ foo = @rcmalloc(sizeof(Foo)); // What is the refcount of foo after this?
foo_something(@rcmalloc(sizeof(Foo))); // Does this leak?
If @rcmalloc returns 1, then rc would be 2 in the first case (except if we have special handling of assignment of RC) and a leak on the second line.
However, if @rcmalloc returns 0, then the second line also leaks.
However, if we let @rcmalloc return rc = 1 AND have the profile of @defer(release), then an implicit defer would ensure that in the scope where called the rc would eventually be decreased (unless assigned to). And this is basically what @autorelease in ObjC does too, but in a less controlled manner.
Even if the above example doesn't make sense, or refcounting shouldn't have language support, it's still a very good way to cheaply enable manual RC built on top of the language.