SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
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++?
45.
Thank you!
Alexander Granin
graninas@gmail.com
Any questions?
C++ Siberia, Novosibirsk