Swiftpack.co - Package - RougeWare/Swift-Lazy-Patterns

CodeFactor

Swift Lazy Containers

A few ways to have a lazily-initialized value in Swift 5.1. Note that, if you are OK with the behavior of Swift's lazy keyword, you should use that. This is for those who want very specific behaviors:

  • Lazy: A non-resettable lazy pattern, to guarantee lazy behavior across Swift language versions
  • ResettableLazy: A resettable lazy pattern, whose value is generated and cached only when first needed, and can be destroyed when no longer needed.
  • FunctionalLazy: An idea about how to approach the lazy pattern by using functions instead of branches.

Compatibility Notice

The entire repository structure had to be changed in order to be compatible with Swift Package Manager (#4). Because of this, the API version changed from 2.0.0 to 3.0.0. Very little of the actual API changed along with this (#8); it was almost entirely to service Swift Package manager.

In version 2.0.0, this readme recommended that you change any reference to ./Lazy.swift to ./LazyContainers/Sources/LazyContainers/LazyContainers.swift. Unfortunately, that wasn't compatible with Swift Package Manager, so ./Lazy.swift was changed to ./Sources/LazyContainers/LazyContainers.swift. Because of this, please change any reference to ./LazyContainers/Sources/LazyContainers/LazyContainers.swift to ./Sources/LazyContainers/LazyContainers.swift. Sorry about that 🤷🏽‍

Examples

It's easy to use each of these. Simply place the appropriate one as a property wrapper where you want it.

Lazy

The simple usage of this is very straightforward:


@Lazy
var myLazyString = "Hello, lazy!"

print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"

This will print:

Hello, lazy!
Hello, lazy!
Overwritten
Overwritten

More complex initializer

If you have complex initializer logic, you can pass that to the property wrapper:


func makeLazyString() -> String {
    print("Initializer side-effect")
    return "Hello, lazy!"
}

@Lazy(initializer: makeLazyString)
var myLazyString: String

print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"

You can also use it directly (instaed of as a property wrapper):

var myLazyString = Lazy<String>() {
    print("Initializer side-effect")
    return "Hello, lazy!"
}

print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"

myLazyString.wrappedValue = "Overwritten"
print(myLazyString.wrappedValue) // Just returns the value "Overwritten"
print(myLazyString.wrappedValue) // Just returns the value "Overwritten"

These will both print:

Initializer side-effect
Hello, lazy!
Hello, lazy!
Overwritten
Overwritten

ResettableLazy

The simple usage of this is very straightforward:


@ResettableLazy
var myLazyString = "Hello, lazy!"

print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

_myLazyString.clear()
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"

This will print:

Hello, lazy!
Hello, lazy!
Hello, lazy!
Hello, lazy!
Overwritten
Hello, lazy!

More complex initializer

If you have complex initializer logic, you can pass that to the property wrapper:


func makeLazyString() -> String {
    print("Initializer side-effect")
    return "Hello, lazy!"
}

@ResettableLazy(initializer: makeLazyString)
var myLazyString: String

print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

_myLazyString.clear()
print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString) // Just returns the value "Hello, lazy!"

myLazyString = "Overwritten"
print(myLazyString) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"

You can also use it directly (instaed of as a property wrapper):

var myLazyString = ResettableLazy<String>() {
    print("Initializer side-effect")
    return "Hello, lazy!"
}

print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"

myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"

myLazyString.wrappedValue = "Overwritten"
print(myLazyString.wrappedValue) // Just returns the value "Overwritten"
_myLazyString.clear()
print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"

These will both print:

Initializer side-effect
Hello, lazy!
Hello, lazy!
Initializer side-effect
Hello, lazy!
Hello, lazy!
Overwritten
Initializer side-effect
Hello, lazy!

FunctionalLazy

This is functionally (ha!) the same as Lazy. The only difference is I thought it'd be fun to implement it with functions instead of enums. 🤓

Github

link
Stars: 5
Help us keep the lights on

Dependencies

Used By

Total: 0

Releases

3.0.1 - Aug 31, 2019

Resolved some assumptions about Swift Package Manager and updated to yet another Swift 5.1 beta syntax.

Important changes since 2.x are listed in the readme: https://github.com/RougeWare/Swift-Lazy-Patterns/commit/84c7de0730ff0a4331bb47435a582293a2dac4e4#diff-04c6e90faac2675aa89e2176d2eec7d8 Important changes since 1.x are listed here: https://github.com/RougeWare/Swift-Lazy-Patterns/releases/tag/2.0.0

With the 3.0.0 release, this package will no longer be distributed as a binary. Please consume this as a Swift Package and compile it as a part of your build process.

2.0.0 - Aug 11, 2019

New Features

  • Rebranded to Lazy Containers, since this repo focuses on providing containers that lazily hold values, but doesn't focus providing patterns for how to do this (although, it does provide the tools to do that).
  • You can now use Lazy, ResettableLazy, and FunctionalLazy as property wrappers!
  • FunctionalLazy is now passed by value, rather than by reference.
  • You can still lazily initialize the value held within a Lazy, ResettableLazy, nor a FunctionalLazy in a non-mutating way, but you can no longer manually set it. This remains consistent with the goal of this repo (to provide a way to lazily initialize a value). In order to set a value-passed instance in a non-mutating way, see Swift-Safe-Pointer.
  • You can now create an instance of any lazy container with a value already initialized inside it. This is useful when you need a uniform API (for instance, when implementing a protocol that requires a Lazy), but require it to already hold a value up-front.
  • Added repo format which allows this to be a Swift Package.
  • Added unit tests to continue proving stability.

1.1.1 - Oct 2, 2018

1.1.0 - May 4, 2018

1.0.0 - May 4, 2018