12. 12
Mutable state...
void Account::setStreet(const std::string& newStreet)
{
this->person.address.street = newStreet;
}
● Demetra law is violated
● Highly specific code
● Mixing of different layers
● SRP is violated
● Not a POD type
14. 14
Account setStreet(Account account, const std::string& newStreet)
{
account.person.address.street = newStreet;
return account;
}
Immutable approach… Not so good.
● Easy to break the client code
● Demetra law is violated
● Highly specific code
● Boilerplate
15. Ok, Lenses!
auto lens = zoom(personLens, addressLens, streetLens);
auto newAccount = set(lens, oldAccount, std::string("New street"));
● “Focused” internal element of the structure
● Do something with the element from outside
● Hiding data structure realization
● Fully immutable, composable and reusable
16. Ok, Lenses!
auto lens = zoom(personLens, addressLens, streetLens);
auto newAccount = set(lens, oldAccount, std::string("New street"));
So, how does this work?
17. Open matryoshka, pull out matryoshka...
Account account = {...};
Person person = getPerson(account);
Address address = getAddress(person);
std::string street = getStreet(address);
std::string newStreet = "Churchill's " + street;
Address newAddress = setStreet(address, newStreet);
Person newPerson = setAddress(person, newAddress);
Account newAccount = setPerson(account, newPerson);
33. Infix literal `to` combinator!
auto lens1 = addressL to houseL;
auto lens2 = personL to lens1;
auto lens3 = aL to bL to cL to dL to … to theLastOneLens;
auto lens = (a to b) to c; // OK, left-associative
auto lens = a to (b to c); // Error
35. set
auto lens = personL() to addressL() to houseL();
Account account1 = {...};
Account account2 = set(lens, account1, 20); // house == 20
36. set, over
auto lens = personL() to addressL() to houseL();
Account account1 = {...};
Account account2 = set(lens, account1, 20); // house == 20
std::function<int(int)> modifier = [](int old) { return old + 6; };
Account account3 = over(lens, account2, modifier); // house == 26
37. What about containers?
struct Car { std::string model; };
std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
38. toListOf *
struct Car { std::string model; };
std::vector<Car> cars = { Car{"Ford Focus"}, Car{"Toyota Corolla"} };
std::list<std::string> result = toListOf(folded<Car>() to modelL(), cars);
// result: {"Ford Focus", "Toyota Corolla"}
* toListOf() and folded<T>() is a hack now, sorry...
39. traversed
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
40. traversed + set
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”));
41. traversed + over
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number; };
auto toCarL = personL() to carsL() to traversed<Car>();
Account newAccount1 = set(toCarL to modelL(), oldAccount, std::string(“Toyota”));
std::function<std::string(std::string)> modifier = [](int old) { return old + 6; };
Account newAccount2 = over(toCarL to numberL(), newAccount1, modifier);
42. traversed + traversed!
struct Account { Person person; };
struct Person { std::vector<Car> cars; };
struct Car { std::string model;
int number;
std::list<std::string> accessories; };
auto toAccessoryL = personL() to carsL() to traversed<Car>()
to accessoriesL() to traversed<std::string>();
43. cpp_lenses library
● Highly experimental
● Done: composing; set, view, over, traverse
● TODO: filter, traverse++, fold, prisms, fusion…
● TODO: clean it, make it wise, short and robust
● github.com/graninas/cpp_lenses
44. ● Complex structures processing
● Test data preparation
● Some XPath, LINQ analogue
● Functional approach
● Much better than just <algorithm>
● ...Why not? Functional C++ is reality coming now
Why lenses in C++?