Theexample uses the Lazy(Func) constructor. It also demonstrates the use of the Lazy(Func, Boolean) constructor (specifying true for isThreadSafe) and the Lazy(Func, LazyThreadSafetyMode) constructor (specifying LazyThreadSafetyMode.ExecutionAndPublication for mode). To switch to a different constructor, just change which constructors are commented out.
The example defines a LargeObject class that will be initialized lazily by one of several threads. The four key sections of code illustrate the creation of the initializer, the factory method, the actual initialization, and the constructor of the LargeObject class, which displays a message when the object is created. At the beginning of the Main method, the example creates the thread-safe lazy initializer for LargeObject:
The example pauses, to indicate that an indeterminate period may elapse before lazy initialization occurs. When you press the Enter key, the example creates and starts three threads. The ThreadProc method that's used by all three threads calls the Value property. The first time this happens, the LargeObject instance is created:
The constructor of the LargeObject class, which includes the last key section of code, displays a message and records the identity of the initializing thread. The output from the program appears at the end of the full code listing.
Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program.
To prepare for lazy initialization, you create an instance of Lazy. The type argument of the Lazy object that you create specifies the type of the object that you want to initialize lazily. The constructor that you use to create the Lazy object determines the characteristics of the initialization. Lazy initialization occurs the first time the Lazy.Value property is accessed.
Will the lazily initialized object be accessed from more than one thread? If so, the Lazy object might create it on any thread. You can use one of the simple constructors whose default behavior is to create a thread-safe Lazy object, so that only one instance of the lazily instantiated object is created no matter how many threads try to access it. To create a Lazy object that is not thread safe, you must use a constructor that enables you to specify no thread safety.
Making the Lazy object thread safe does not protect the lazily initialized object. If multiple threads can access the lazily initialized object, you must make its properties and methods safe for multithreaded access.
Does lazy initialization require a lot of code, or does the lazily initialized object have a parameterless constructor that does everything you need and doesn't throw exceptions? If you need to write initialization code or if exceptions need to be handled, use one of the constructors that takes a factory method. Write your initialization code in the factory method.
You can use a lambda expression to specify the factory method. This keeps all the initialization code in one place. The lambda expression captures the context, including any arguments you pass to the lazily initialized object's constructor.
Exception caching When you use factory methods, exceptions are cached. That is, if the factory method throws an exception the first time a thread tries to access the Value property of the Lazy object, the same exception is thrown on every subsequent attempt. This ensures that every call to the Value property produces the same result and avoids subtle errors that might arise if different threads get different results. The Lazy stands in for an actual T that otherwise would have been initialized at some earlier point, usually during startup. A failure at that earlier point is usually fatal. If there is a potential for a recoverable failure, we recommend that you build the retry logic into the initialization routine (in this case, the factory method), just as you would if you weren't using lazy initialization.
Alternative to locking In certain situations, you might want to avoid the overhead of the Lazy object's default locking behavior. In rare situations, there might be a potential for deadlocks. In such cases, you can use the Lazy(LazyThreadSafetyMode) or Lazy(Func, LazyThreadSafetyMode) constructor, and specify LazyThreadSafetyMode.PublicationOnly. This enables the Lazy object to create a copy of the lazily initialized object on each of several threads if the threads call the Value property simultaneously. The Lazy object ensures that all threads use the same instance of the lazily initialized object and discards the instances that are not used. Thus, the cost of reducing the locking overhead is that your program might sometimes create and discard extra copies of an expensive object. In most cases, this is unlikely. The examples for the Lazy(LazyThreadSafetyMode) and Lazy(Func, LazyThreadSafetyMode) constructors demonstrate this behavior.
Equivalent constructors In addition to enabling the use of LazyThreadSafetyMode.PublicationOnly, the Lazy(LazyThreadSafetyMode) and Lazy(Func, LazyThreadSafetyMode) constructors can duplicate the functionality of the other constructors. The following table shows the parameter values that produce equivalent behavior.
By default, all public and protected members of the Lazy class are thread safe and may be used concurrently from multiple threads. These thread-safety guarantees may be removed optionally and per instance, using parameters to the type's constructors.
John D. Rockefeller was the most successful businessman of all time. He was also a recluse, spending most of his time by himself. He rarely spoke, deliberately making himself inaccessible and staying quiet when you caught his attention.
Everyone eventually has to sit down and produce their work, and are held to goals and quotas. But as the economy shifts to knowledge work, we should respect that what actually produces good work can at first look lazy, and (even more so) vice versa.
I was under the impression that private vars weren't synthesised in @Observable classes.
When I tried to use a lazy var, I get the error 'lazy' cannot be used on a computed property, which I infer as meaning the var is the synthesised version.
private vars are synthesized; since they can compose to public accessors. lazy cannot be transformed due to not being able to synthesize that effect (hence the error). If you need a lazy property you can add the @ObservationIgnored macro on it and the observation system will ignore synthesis for that property.
In programming language theory, lazy evaluation, or call-by-need,[1] is an evaluation strategy which delays the evaluation of an expression until its value is needed (non-strict evaluation) and which also avoids repeated evaluations (by the use of sharing).[2][3]
Lazy evaluation is often combined with memoization, as described in Jon Bentley's Writing Efficient Programs.[4] After a function's value is computed for that parameter or set of parameters, the result is stored in a lookup table that is indexed by the values of those parameters; the next time the function is called, the table is consulted to determine whether the result for that combination of parameter values is already available. If so, the stored result is simply returned. If not, the function is evaluated, and another entry is added to the lookup table for reuse.
Lazy evaluation was introduced for lambda calculus by Christopher Wadsworth[5] and employed by the Plessey System 250 as a critical part of a Lambda-Calculus Meta-Machine, reducing the resolution overhead for access to objects in a capability-limited address space.[6] For programming languages, it was independently introduced by Peter Henderson and James H. Morris[7] and by Daniel P. Friedman and David S. Wise.[8][9]
Delayed evaluation is used particularly in functional programming languages. When using delayed evaluation, an expression is not evaluated as soon as it gets bound to a variable, but when the evaluator is forced to produce the expression's value. That is, a statement such as x = expression; (i.e. the assignment of the result of an expression to a variable) clearly calls for the expression to be evaluated and the result placed in x, but what actually is in x is irrelevant until there is a need for its value via a reference to x in some later expression whose evaluation could itself be deferred, though eventually the rapidly growing tree of dependencies would be pruned to produce some symbol rather than another for the outside world to see.[10]
Lazy evaluation allows control structures to be defined normally, and not as primitives or compile-time techniques. For example, one can define if-then-else and short-circuit evaluation operators:[11][12]
Conversely, in an eager language the above definition for ifThenElse a b c would evaluate (a), (b), and (c) regardless of the value of (a). This is not the desired behavior, as (b) or (c) may have side effects, take a long time to compute, or throw errors. It is usually possible to introduce user-defined lazy control structures in eager languages as functions, though they may depart from the language's syntax for eager evaluation: Often the involved code bodies need to be wrapped in a function value, so that they are executed only when called.
Delayed evaluation has the advantage of being able to create calculable infinite lists without infinite loops or size matters interfering in computation. The actual values are only computed when needed. For example, one could create a function that creates an infinite list (often called a stream) of Fibonacci numbers. The calculation of the n-th Fibonacci number would be merely the extraction of that element from the infinite list, forcing the evaluation of only the first n members of the list.[13][14]
In the function .mw-parser-output .monospacedfont-family:monospace,monospacenumberFromInfiniteList, the value of infinity is an infinite range, but until an actual value (or more specifically, a specific value at a certain index) is needed, the list is not evaluated, and even then, it is only evaluated as needed (that is, until the desired index.) Provided the programmer is careful, the program completes normally. However, certain calculations may result in the program attempting to evaluate an infinite number of elements; for example, requesting the length of the list or trying to sum the elements of the list with a fold operation would result in the program either failing to terminate or running out of memory.
3a8082e126