-
Notifications
You must be signed in to change notification settings - Fork 1
Basic lens operations
Why would you choose the lens abstraction?
The answer is that it's to enable you to apply divide and conquer to your architecture. By using immutable classes to communicate with different parts, you can ensure that different parts of the system can't accidentally cause data changes. When dealing with immutable classes, there is research and work already done in order to answer the questions around working with immutable data.
In order to find out about the research and theoretical work around lenses you can check out Bartosz Milewski that mentions how to get further. These parts are for those wanting to understand it deeply and is not needed in order to make basic use of the abstraction. I.e. you can still be productive and deliver business code without knowing the details.
You can think of a DataLens as an instance of a class that implements the interface:
public interface IDataLens<T, TValue>
{
TValue Get(T entity);
T Set(T entity, TValue value);
}The library calls the abstraction DataLens in reference to Haskell 98 implementation of lenses.
The basic operations to work with these simple lenses are the following:
The basic operations are combine and compose.
-
Combine
Customer.IdLens.Combine(Customer.NameLens)
Gives you a lens that gets/sets both Id and Name on the same class Customer. Given that the static properties IdLens and NameLens are Id and Name lenses for Customer.
This can be thought of as doing the following for mutable code:
customer.Id = newId; customer.Name = newName;
-
Compose
Customer.NameLens.AndThen(Sale.CustomerLens)
Gives you a lens that gets/sets both Name of the property Customer on the class Sale. Given that the static properties CustomerLens and NameLens are Customer and Name lenses for Sale and Customer.
This can be thought of as doing the following for mutable code:
sale.Customer.Name = newName;
-
AndThen
Is the flipped version of Compose,
Sale.CustomerLens.Compose(Customer.NameLens)
Gives you a lens that gets/sets both Name of the property Customer on the class Sale. Given that the static properties CustomerLens and NameLens are Customer and Name lenses for Sale and Customer.
This can be thought of as doing the following for mutable code:
sale.Customer.Name = newName;
-
View
Read value targeted by lens
static DataLens<Sale,string> saleCustomerLens = Sale.CustomerLens.AndThen(Customer.NameLens);
var customerName = saleCustomerLens.View(sale);
Using property access:
var customerName = sale.Customer.Name;
-
Set
Set value targeted by lens
static DataLens<Sale,string> saleCustomerLens = Sale.CustomerLens.AndThen(Customer.NameLens);
var newInstanceOfSale = saleCustomerLens.Set(sale, "Tamika");
Using mutable instances:
sale.Customer.Name = "Tamika";
-
Over
Set value targeted by lens using function
static DataLens<Sale,decimal> saleProductPriceLens = Sale.ProductLens.AndThen(Product.PriceLens);
var discountedSale = saleProductPriceLens.Over(price=>price-discount, sale);
Using mutable instances:
sale.Product.Price -= discount;