3 ms·
I don't mind it not being default - but the section doesn't mention at all how to get wrapping behavior. Just one sentence like "use this different operator to
by pingyong 7y ago
I don't mind it not being default - but the section doesn't mention at all how to get wrapping behavior. Just one sentence like "use this different operator to get wrapping behavior" would be fine, but since they didn't mention it at all I kind of went away with the idea that it is not supported at all, which honestly would be a massive problem.
>defer is way more transparent than RAII, because your code is right there in the function call, not hidden in a pile of classes that might change underneath.
I mean, sort of? It seems way less composable though, if you have an object which contains 5 different resources, now you have to defer 5 things? How does this interact with return values, if you defer file.close() for example but return the file, does it still get closed? And if you have a heap allocated array of those objects, where objects get inserted at different places, defer doesn't work at all anymore, since it's just bound to function scope? Because that's usually the scenario that can be annoying to handle in C (opposed to just closing whatever was opened in the same function scope), so it seems a bit odd to me to kind of violate that "no hidden control flow" principle for something that doesn't even solve the primary issue that C resource handling has.
- clarry 7y ago> I don't mind it not being default - but the section doesn't mention at all how to get wrapping behavior. I think that piece would get too long if it described everything in depth. https://ziglang.org/documentation/master/#Wrapping-Operations https://ziglang.org/documentation/master/#Wrapping-Operation... > I mean, sort of? It seems way less composable though, if you have an object which contains 5 different resources, now you have to defer 5 things? Defer is used for scope-local resources. If you create five different things in the local scope that need to be cleaned up, then they are most likely not part of the same object; yes, you will need to clean them all up. If you have an object with five different thing, then you would defer that object's cleanup routine. > How does this interact with return values, if you defer file.close() for example but return the file, does it still get closed? Yes. Why would you defer close on a file that you are planning to return? That's by definition not some scope-local resource with scope lifetime you want to cleanup at the end of scope. That's like implementing malloc that frees the block before returning. Note that there is errdefer, which you can use to defer the release of resources that would be returned normally but need to be cleaned up on error. https://ziglang.org/documentation/master/#defer https://ziglang.org/documentation/master/#defer > And if you have a heap allocated array of those objects, where objects get inserted at different places, defer doesn't work at all anymore, since it's just bound to function scope? I don't understand what you're asking about here. If you malloc() an array in C, then you free() it when you're done with it. The exact same mechanism works in Zig, but defer also helps you ensure free() actually gets called when you go out of scope, so you can still use early returns instead of ret = foo; goto err_bar; > Because that's usually the scenario that can be annoying to handle in C (opposed to just closing whatever was opened in the same function scope), so it seems a bit odd to me to kind of violate that "no hidden control flow" principle for something that doesn't even solve the primary issue that C resource handling has. I don't agree that it's violating the "no hidden control flow constraint." It's explicit, right there in the scope, not stashed away in a bunch of destructors. It's as transparent as return or goto or break. Again, I don't really understand the rest of your complaints (or what's your primary issue with C's resource handling). Defer is just a mechanism to make it easier to release resources whose lifetime is tied to a scope.
- pingyong 7y ago>I think that piece would get too long if it described everything in depth. I don't think one sentence more about a very fundamental operation in a page-long document would really be misplaced. But as far as the language itself goes, those operators seem fine to me. >Note that there is errdefer That is definitely more useful, and covers the situation I was thinking of. >I don't understand what you're asking about here. If you malloc() an array in C, then you free() it when you're done with it. This is about composed objects. So an allocated array of objects, which in turn also hold allocated objects, which might in turn also hold allocated objects. >I don't agree that it's violating the "no hidden control flow constraint." It's explicit, right there in the scope, not stashed away in a bunch of destructors. It's as transparent as return or goto or break. Not sure I can completely agree with that. Fundamentally, defer means that something happens at a point where there is no associated code. If you read the line "return 5;", you don't know if that triggers one (or multiple) function calls. Yes, you only have to look for those in function scope (which could be 5000+ lines in some cases) (you only have to look for destructors in function scope too btw), but it is still a "hidden code path". For me personally it doesn't really matter at that point if I have to first search in the function body (and then potentially in the cleanup function), or first in the function body and then potentially in destructors. It removes the ability to reason about code line by line either way. Which might be a price that is worth to pay for easier cleanup logic, but the way I'm seeing it I'm only getting like a quarter of the benefit of destructors but I'm paying essentially the same price.
- clarry 7y ago> This is about composed objects. So an allocated array of objects, which in turn also hold allocated objects, which might in turn also hold allocated objects. The way this is solved by calling the cleanup routine for the first object in the hierarchy. If that object is responsible for the lifetime of other objects, then it will also call their cleanup routine. From the user's perspective, those are invisible, just as any calls to free() or close() or fflush() inside an fclose() are. > If you read the line "return 5;", you don't know if that triggers one (or multiple) function calls. If you read the line "continue;" or "break;", you don't know if that triggers one (or multiple) function calls until you read the surrounding code. I still find it much easier to follow code inside a function than to jump through classes. But the bigger picture is that it makes lifetime management explicit and thus transparent, and you needn't complicate the language with copy constructors and move semantics.