From b2324b2782959b32ff6e36c2578a0bc2cdf4aeb5 Mon Sep 17 00:00:00 2001 From: Stoian Dan Date: Mon, 16 Sep 2024 17:40:56 +0300 Subject: [PATCH 1/4] Create 2024-09-16-lazy-loading-in-csharp.md --- _posts/2024-09-16-lazy-loading-in-csharp.md | 108 ++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 _posts/2024-09-16-lazy-loading-in-csharp.md diff --git a/_posts/2024-09-16-lazy-loading-in-csharp.md b/_posts/2024-09-16-lazy-loading-in-csharp.md new file mode 100644 index 0000000000000..2b8bf774f5e17 --- /dev/null +++ b/_posts/2024-09-16-lazy-loading-in-csharp.md @@ -0,0 +1,108 @@ +# Lazy Loading in C# (and not only) + +## Introduction +_Lazy loading_ is a technique used to dealy the execution of code for later on. There are a couple of reasons as to why you'd want to do that, and we'll enumerate some: + +- Speed – the best code, is also the fastest code, the most secure and most maintainable, that is to say which means _no code at all_. However, for obvious reasons, we do need at times to write code, but while we can't avoid writing it, we could delay or even, _possibly_, completely avoid _executing_ it. +- Memory footprint – RAM memory is still important, avoiding loading a heavy object does not just result in speed, but also in a more efficient system memory-wise. + +## Hands-on + +While the theory sounds great, there still remains the question how do you actually _avoid_ calling code? While there are a couple of ways to do that, I'd like to focus on two of them: + + +### Singletons +First, when it comes the the [_singleton pattern_](https://en.wikipedia.org/wiki/Singleton_pattern), objects (if we're talking in a _OOP_ context, but this goes for other paradigms as well) are often _statically_ allocated. This affects us even more, as static objects, often get initialized early on. For example in `.NET Framework` _static_ fields get initialized before the non-static constructor of the class is called. This is also the case for other platforms, like `Java`. Here an `if` check is usually employed for _lazy loading_: + +```C# + class Singleton + { + private static Singleton _instance = null; // redundant, for explicity + + private Singleton { ... } + + public Singleton Instance() + { + if (Singleton._instance == null) + { + _instance = new Singleton(); + } + return _instance; + } + } +``` + +In the above example ☝️ we can see how an `if` statement is used to check if our singleton has ever been istanciated before, if so, we just return that instance. However, if this is the first time, we create a first instance. This saves us some time and memory, because we might not get to use the class at all (depending on the use case) or we might just delay the execution. + +Notice, the more moder `.NET` platform actually uses lazy loading by default. Static fields only get initialized before being used, and so, `.NET` does this for us, as opposed to the older `.NET Framework`. + + +## Instance fields + +The more interesting and common use case, is when we'd like to delay the initialization of an _instance_ field. For this, both frameworks (`.NET` and `.NET Framwork`) come with build-in support, namely: `Lazy`, a generic class which can wrap any object and delay it's initialization. We'll explore a simple implementation of such an idea, and see how we can achieve this in pretty much any programming language. + +Frist imagine the scenario of two classes: +```C# +public class Foo { ... } +``` +and +```C# +public class Bar { ... } +``` +with a _composition_ relationship of type: +```C# +public class Foo +{ + Bar bar = new(); + ... +} +``` +Our goal is to delay the initialization of the field `bar` in any `Foo` instance. + +From the get go, our solution needs to address any possible type, not just field of type `Bar`. This is why _generics_ are needed. So our solution begins to look as such: + +```C# + public class Lazy { … } +``` + +Second, we'd need to know all about how _exactly_ to create this _delayed_ `bar` object, and yet, not create it just yet… This sounds like a _producer_ and a _callback_ (or _higher-order function_) is exactly what could help us. In `.NET` the `Func` type is a _function_ type that takes 0 parameters and returns a `T`. We can use is as such: + +```C# + public class Lazy + { + private Func _generator; + public Lazy(Func generator) => _generator = generator; + + public T Load() => this._generator(); + + } +``` +All that we're providing to the constructor of the `Lazy` class is a function, that describes how to return a `T`, and whenever we want to actually return that `T`, we just call `Load`. + +Let's see this in action: +```C# +public class Foo +{ + // old code: Bar bar = new(); + Lazy bar_lazy = new Lazy(() => new()); + ... +} +``` + +This looks great! Now, whenever we want our object instance, we can just call `Load` on `bar_lazy`, but the beauty of warping things in a function is that, even if our `Bar` constructor required parameters, this would be fixed with just a small adjustment: + +```C# +public class Foo +{ + //ctor injection, provide `lazy_bar` as a dependency + Foo(Lazy lazy_bar) + ... +} +``` +```C# +// calling code +lazy_bar = new Lazy (() => new Bar(name, age, other_param)) +new Foo(lazy_bar); +... +``` +It's true that now we can't really do an in-line initialization, but that woul have been true even without our static wrapper, unless, of-course, we use static variables. From 0db8339363f2f89617a2e6317c189cc852d27de8 Mon Sep 17 00:00:00 2001 From: Stoian Dan Date: Mon, 16 Sep 2024 17:51:21 +0300 Subject: [PATCH 2/4] Update 2024-09-16-lazy-loading-in-csharp.md --- _posts/2024-09-16-lazy-loading-in-csharp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2024-09-16-lazy-loading-in-csharp.md b/_posts/2024-09-16-lazy-loading-in-csharp.md index 2b8bf774f5e17..8de7294632832 100644 --- a/_posts/2024-09-16-lazy-loading-in-csharp.md +++ b/_posts/2024-09-16-lazy-loading-in-csharp.md @@ -1,7 +1,7 @@ # Lazy Loading in C# (and not only) ## Introduction -_Lazy loading_ is a technique used to dealy the execution of code for later on. There are a couple of reasons as to why you'd want to do that, and we'll enumerate some: +_Lazy loading_ is a technique used to delay the execution of code for later on. There are a couple of reasons as to why you'd want to do that, and we'll enumerate some: - Speed – the best code, is also the fastest code, the most secure and most maintainable, that is to say which means _no code at all_. However, for obvious reasons, we do need at times to write code, but while we can't avoid writing it, we could delay or even, _possibly_, completely avoid _executing_ it. - Memory footprint – RAM memory is still important, avoiding loading a heavy object does not just result in speed, but also in a more efficient system memory-wise. @@ -12,7 +12,7 @@ While the theory sounds great, there still remains the question how do you actua ### Singletons -First, when it comes the the [_singleton pattern_](https://en.wikipedia.org/wiki/Singleton_pattern), objects (if we're talking in a _OOP_ context, but this goes for other paradigms as well) are often _statically_ allocated. This affects us even more, as static objects, often get initialized early on. For example in `.NET Framework` _static_ fields get initialized before the non-static constructor of the class is called. This is also the case for other platforms, like `Java`. Here an `if` check is usually employed for _lazy loading_: +First, when it comes the the [_singleton pattern_](https://en.wikipedia.org/wiki/Singleton_pattern), objects (if we're talking in an _OOP_ context, but this goes for other paradigms as well) are often _statically_ allocated. This affects us even more, as static objects, often get initialized early on. For example in `.NET Framework` _static_ fields get initialized before the non-static constructor of the class is called. This is also the case for other platforms, like `Java`. Here an `if` check is usually employed for _lazy loading_: ```C# class Singleton From e36ff7abd0303e6135495617d66001f10d823980 Mon Sep 17 00:00:00 2001 From: Stoian Dan Date: Mon, 16 Sep 2024 17:54:27 +0300 Subject: [PATCH 3/4] Update 2024-09-16-lazy-loading-in-csharp.md --- _posts/2024-09-16-lazy-loading-in-csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2024-09-16-lazy-loading-in-csharp.md b/_posts/2024-09-16-lazy-loading-in-csharp.md index 8de7294632832..751f60a3c29b1 100644 --- a/_posts/2024-09-16-lazy-loading-in-csharp.md +++ b/_posts/2024-09-16-lazy-loading-in-csharp.md @@ -4,7 +4,7 @@ _Lazy loading_ is a technique used to delay the execution of code for later on. There are a couple of reasons as to why you'd want to do that, and we'll enumerate some: - Speed – the best code, is also the fastest code, the most secure and most maintainable, that is to say which means _no code at all_. However, for obvious reasons, we do need at times to write code, but while we can't avoid writing it, we could delay or even, _possibly_, completely avoid _executing_ it. -- Memory footprint – RAM memory is still important, avoiding loading a heavy object does not just result in speed, but also in a more efficient system memory-wise. +- Memory footprint – RAM is still important, avoiding loading a heavy object does not just result in increased speed, but also in a more efficient system, memory-wise. ## Hands-on From 22f3d92871a5cd0b33be7ee07e3a5b6d6456921e Mon Sep 17 00:00:00 2001 From: Stoian Dan Date: Mon, 16 Sep 2024 18:09:23 +0300 Subject: [PATCH 4/4] Update 2024-09-16-lazy-loading-in-csharp.md --- _posts/2024-09-16-lazy-loading-in-csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2024-09-16-lazy-loading-in-csharp.md b/_posts/2024-09-16-lazy-loading-in-csharp.md index 751f60a3c29b1..98fcb10a44e1a 100644 --- a/_posts/2024-09-16-lazy-loading-in-csharp.md +++ b/_posts/2024-09-16-lazy-loading-in-csharp.md @@ -3,7 +3,7 @@ ## Introduction _Lazy loading_ is a technique used to delay the execution of code for later on. There are a couple of reasons as to why you'd want to do that, and we'll enumerate some: -- Speed – the best code, is also the fastest code, the most secure and most maintainable, that is to say which means _no code at all_. However, for obvious reasons, we do need at times to write code, but while we can't avoid writing it, we could delay or even, _possibly_, completely avoid _executing_ it. +- Speed – the best code, is also the fastest code, the most secure and most maintainable… namely _no code at all_. However, for obvious reasons, we do need at times to write code, but while we can't avoid writing it, we could delay or even, _possibly_, completely avoid _executing_ it. - Memory footprint – RAM is still important, avoiding loading a heavy object does not just result in increased speed, but also in a more efficient system, memory-wise. ## Hands-on