Hey Mike, I absolutely love your videos. I was wondering if you ever would consider doing paid tutoring? You are, without a doubt, the person who explains concepts in ways that I can understand. And my plan is to go to university for Software Engineering. Even if you don't do paid tutoring, I want to express a massive thank you for putting out all this amazing, and super informative and educational content for free. Keep up the amazing work!
Cheers, thank you for the kind words! I'd have to think carefully about tutoring and other work responsibilities -- unfortunately I don't scale well as only 1 person :)
Hello, Mike! You make wonderful content. I notice you always tend to utilize primary documentation (APIs) in your videos, which is very professional and appreciated! As a college student learning programming, I was wondering if you would please consider putting together a video on how to understand documentation, as this seems to me to be the most valuable skill after learning the language syntax. Thanks, Mike!
@@bsdooby probably so -- perhaps if you need to shutdown some system and restart it, then it's useful, but otherwise I typically haven't had a use case🙂
That corner seems dark indeed, but if you know some rules it's quite controllable. Use case: You can handle large object hierarchies with it. And single handedly you can destroy them by a simple root.destroy call. One good example is the lifetime management of Vulkan graphics objects. All the responsibility is at the client's side. If you forget to deallocate something, it will hold a resource on your GPU until your application terminates. With D's ~this it can be automatized. Just keep in mind that destructors can be called from ANY thread and they can be called in ANY order. If a child object destructs, it must tell it the parent first, so when the parent will destroy, it will know that the child is already destroyed itself. If you just want to reclaim the memory used by the object, you simply clear all references to that object. The next time your program allocates memory, and run out of space, it will do a GC.collect and utilize those object with no references to them. After program execution it is not guaranteed to the destructors will be called at all. If you want it work deterministically for example save ini files, you call destroy(). If your objects are just holding Windows resource handles, just live them there, the OS will do the cleanup anyways. And manual GC.collect only does something if it wans, we have no control over it, it is not a solution for lags. Clever ways of reusing already allocated memory is a better solution. Also don't throw exceptions from destructors. To avoid weird access violations of undefinied behavior use this instead of destroy -> void free(ref Object o){ if(o){ o.destroy; o = null; } }
@@realhet Good note -- thanks for sharing! Indeed, GC.collect may not be as deterministic (dlang.org/library/core/memory/gc.collect.html) as we think-- docs state its up to implementation (in my experience, it generally collects on linux, but that could be one implementation).
@@realhet I think you could use scoped!Type or Unique!Type for that. But for scoped to work the object must be in a deeper scope than the object it relies on. (So it is destroyed in correct order). Unique could be used with a class hierarchy holding the objects, with the benefit of dependency injection. But I still experiment with this myself.
@@MrDavibu There are a lot of things that you should declare once and reuse as long as you can in Vulkan. So you create something and you let it hang around until it is needed for the next task. And sometimes you feel like you are running out of some resources, so you unload some older stuff. The stuff will know the ownership graph and it will know how to deallocate itself properly. There are a lot of 'scopes' but they are not in a strict ordered hierarchy, they are overlapping depending on many conditions dynamically. I really like to use scoped!Class for example when I draw something in my current opengl thing. At the end of the scope it will automatically send the data into a VBO object, draws it and cleans up. But the strict object hierarchy is required to manage lifecycles of things that is unknown in the future. (Because it is too much for me to manage it by myself, to guarantee no bugs, I had to automatize it. And also because I'm lazy: automatizing code generation feels like I don't have to write code. Actually it's the opposite but it's more fun :D.) Unique!T is new for me, so it's a scoped! for structs and a possibility to escape from the scope. I like it, thank you for mentioning!
If assignment id = _id; can so easily replace the call to super(42); what was the rational for super() in the first place? The only rational reason i can think of is just to make it more explicit.
Nice tutorial
Cheers!
Hey Mike, I absolutely love your videos. I was wondering if you ever would consider doing paid tutoring? You are, without a doubt, the person who explains concepts in ways that I can understand. And my plan is to go to university for Software Engineering. Even if you don't do paid tutoring, I want to express a massive thank you for putting out all this amazing, and super informative and educational content for free. Keep up the amazing work!
Cheers, thank you for the kind words! I'd have to think carefully about tutoring and other work responsibilities -- unfortunately I don't scale well as only 1 person :)
D's lessons are D'liteful!
@@GaryChike more D'liteful lessons coming!
Hello, Mike! You make wonderful content. I notice you always tend to utilize primary documentation (APIs) in your videos, which is very professional and appreciated! As a college student learning programming, I was wondering if you would please consider putting together a video on how to understand documentation, as this seems to me to be the most valuable skill after learning the language syntax. Thanks, Mike!
Cheers, thank you for the kind words! Hmm, that may be an interesting video -- I'll consider doing some sort of 'code exploration' video.
@MikeShah Thanks so much for your consideration!
As you said, are there use cases for `destroy`? I fear it is like Java's finalize (?) A dark corner...
@@bsdooby probably so -- perhaps if you need to shutdown some system and restart it, then it's useful, but otherwise I typically haven't had a use case🙂
That corner seems dark indeed, but if you know some rules it's quite controllable.
Use case: You can handle large object hierarchies with it. And single handedly you can destroy them by a simple root.destroy call.
One good example is the lifetime management of Vulkan graphics objects. All the responsibility is at the client's side. If you forget to deallocate something, it will hold a resource on your GPU until your application terminates. With D's ~this it can be automatized.
Just keep in mind that destructors can be called from ANY thread and they can be called in ANY order. If a child object destructs, it must tell it the parent first, so when the parent will destroy, it will know that the child is already destroyed itself.
If you just want to reclaim the memory used by the object, you simply clear all references to that object. The next time your program allocates memory, and run out of space, it will do a GC.collect and utilize those object with no references to them.
After program execution it is not guaranteed to the destructors will be called at all. If you want it work deterministically for example save ini files, you call destroy(). If your objects are just holding Windows resource handles, just live them there, the OS will do the cleanup anyways.
And manual GC.collect only does something if it wans, we have no control over it, it is not a solution for lags. Clever ways of reusing already allocated memory is a better solution.
Also don't throw exceptions from destructors.
To avoid weird access violations of undefinied behavior use this instead of destroy -> void free(ref Object o){ if(o){ o.destroy; o = null; } }
@@realhet Good note -- thanks for sharing! Indeed, GC.collect may not be as deterministic (dlang.org/library/core/memory/gc.collect.html) as we think-- docs state its up to implementation (in my experience, it generally collects on linux, but that could be one implementation).
@@realhet
I think you could use scoped!Type or Unique!Type for that. But for scoped to work the object must be in a deeper scope than the object it relies on. (So it is destroyed in correct order). Unique could be used with a class hierarchy holding the objects, with the benefit of dependency injection.
But I still experiment with this myself.
@@MrDavibu There are a lot of things that you should declare once and reuse as long as you can in Vulkan. So you create something and you let it hang around until it is needed for the next task. And sometimes you feel like you are running out of some resources, so you unload some older stuff. The stuff will know the ownership graph and it will know how to deallocate itself properly. There are a lot of 'scopes' but they are not in a strict ordered hierarchy, they are overlapping depending on many conditions dynamically.
I really like to use scoped!Class for example when I draw something in my current opengl thing. At the end of the scope it will automatically send the data into a VBO object, draws it and cleans up.
But the strict object hierarchy is required to manage lifecycles of things that is unknown in the future. (Because it is too much for me to manage it by myself, to guarantee no bugs, I had to automatize it. And also because I'm lazy: automatizing code generation feels like I don't have to write code. Actually it's the opposite but it's more fun :D.)
Unique!T is new for me, so it's a scoped! for structs and a possibility to escape from the scope. I like it, thank you for mentioning!
If assignment id = _id; can so easily replace the call to super(42); what was the rational for super() in the first place? The only rational reason i can think of is just to make it more explicit.
@@kyleheaser2385 this is just a minimal example to show that we can move the call of the 'superclass' constructor from the 'subclass' as we need