Page MenuHomePhorge

No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None
diff --git a/doc.org b/doc.org
index 7af3c8d..ebfc65f 100644
--- a/doc.org
+++ b/doc.org
@@ -1,149 +1,156 @@
#+PROPERTY: header-args :exports code
+#+HTML_HEAD: <link rel="stylesheet" href="./style.css">
+* Intro
+Using [[https://github.com/arximboldi/lager][lager]] with Qt/QML
+
+- tusooa, maintainer of [[https://kazv.chat][kazv]], [[https://lily-is.land/tusooa]] [[https://invent.kde.org/tusooaw]]
+- Dmitry Kazakov, developer of [[https://krita.org][Krita]], https://invent.kde.org/dkazakov
* What is lager?
- library to help with *value-oriented design*
- store application state as a *value* type
-- state transformations are described in pure functions (*reducers*), src_c++{auto update(Model, Action) -> Model;}
+- state transformations are described in pure functions (*reducers*)
+ - src_c++{auto update(Model, Action) -> Model;}
- actions are also value types
* What is a value type?
- copyable
- equality comparable
#+BEGIN_SRC c++
T a = ...;
T b = a;
REQUIRE(a == b);
#+END_SRC
- identity does not depend on a reference
#+BEGIN_SRC c++
// not a value type
struct Person
{
std::string name;
std::vector<std::weak_ptr<Person>> contacts;
};
// value type
struct Person
{
using IdType = std::string;
IdType id;
std::string name;
std::vector<IdType> contacts;
};
#+END_SRC
* Basic example of a value-oriented program
=logic.hpp=
#+INCLUDE: "src/basic-example/logic.hpp" src c++
=logic.cpp=
#+INCLUDE: "src/basic-example/logic.cpp" src c++
=main.cpp=
#+INCLUDE: "src/basic-example/main.cpp" src c++
The basic example just covered doesn't even make use of lager (!!!)
* Benefits of using lager?
- Testability
- libkazv: [[https://lily-is.land/kazv/libkazv][76.9%]] test coverage
- libQuotient: [[https://sonarcloud.io/component_measures?metric=coverage&selected=quotient-im_libQuotient%3AQuotient&id=quotient-im_libQuotient][41.6%]] (raw), 46.9% (adjusted)
=test.cpp=
#+INCLUDE: "src/basic-example/test.cpp" src c++
- Offload work into worker threads
#+BEGIN_SRC c++
QtConcurrent::run([model]() { // capture model by value
save(model);
});
#+END_SRC
- Performance of copying? Structural sharing, immer containers
- Undo/redo for free
- History is a list of models
- Undo/redo = changing the current index
- Normal actions = push a new model onto the list
* How to do IO?
** Reducers revisited
- src_c++{auto update(Model, Action) -> Model;}
- But also src_c++{auto update(Model, Action) -> std::pair<Model, Effect>;}
- What is an effect? A (maybe non-pure) function that takes a *context* as an argument.
- A *store* contains the model and the context. It also has an event loop. Reducers will be run in the event loop.
- The store can be constructed with *dependencies*, which can be accessed through the context.
- The context can also be used to dispatch actions.
=model.hpp=
#+INCLUDE: "src/effects-example/model.hpp" src c++
=main.cpp=
#+INCLUDE: "src/effects-example/main.cpp" src c++
* How can lager help you integrate value-oriented design with a Qt application?
** Missing part: view
- In the example, src_c++{show()} is the view.
- We want to show the state as a src_c++{QWidget} or src_c++{QQuickItem}.
- Signal/slot connections to update display values.
- [[https://sinusoid.es/lager/cursors.html][Cursors]]
- src_c++{lager::reader} - readonly cursors
- readers can be watched
- src_c++{lager::store} is a reader
- map-transformations and some lenses
- src_c++{LAGER_QT} and src_c++{LAGER_QT_READER}
=demo-app.hpp=
#+INCLUDE: "src/qml-example/demo-app.hpp" src c++
=demo-app.cpp=
#+INCLUDE: "src/qml-example/demo-app.cpp" src c++
=Main.qml=
#+INCLUDE: "src/qml-example/Main.qml" src c++
=main.cpp=
#+INCLUDE: "src/qml-example/main.cpp" src c++
* Practical application problems
* List views
[[https://github.com/arximboldi/lager/issues/179]]
** Number as model in QML ListView
=main.cpp=
#+INCLUDE: "src/list-view/main.cpp" src c++
=demo-app.hpp=
#+INCLUDE: "src/list-view/demo-app.hpp" src c++
=demo-app.cpp=
#+INCLUDE: "src/list-view/demo-app.cpp" src c++
=demo-list.hpp=
#+INCLUDE: "src/list-view/demo-list.hpp" src c++
=demo-list.cpp=
#+INCLUDE: "src/list-view/demo-list.cpp" src c++
=demo-item.hpp=
#+INCLUDE: "src/list-view/demo-item.hpp" src c++
=demo-item.cpp=
#+INCLUDE: "src/list-view/demo-item.cpp" src c++
=Main.qml=
#+INCLUDE: "src/list-view/Main.qml" src qml
- Problem: scroll will reset every time we add/remove an item
- https://github.com/arximboldi/lager/issues/179
** Using a src_c++{QAbstractListModel}
=demo-list.hpp=
#+INCLUDE: "src/list-view-qt-model/demo-list.hpp" src c++
=demo-list.cpp=
#+INCLUDE: "src/list-view-qt-model/demo-list.cpp" src c++
=Main.qml=
#+INCLUDE: "src/list-view-qt-model/Main.qml" src qml
* Post-dispatch then-continuations
[[https://github.com/arximboldi/lager/issues/96]], [[https://github.com/arximboldi/lager/issues/106]]
- lager does not support this
- Resolved by creating another kind of store
- Effects return a Promise (for C++ programmers, it's more like src_c++{std::future}) instead of void
- src_c++{dispatch} can be src_c++{then}-ed, the callback will be run after the returned future becomes ready
#+INCLUDE: "src/libkazvstore-example/main.cpp" src c++
* Offloading work into worker threads
- src_c++{ctx.dispatch} is thread-safe, can use it to pass down the result of a heavy computation
- When heavy computation needs to be atomic, put the event loop into a worker thread
- Create a secondary store that has an event loop in the UI thread
- This is needed because cursor operations are not thread-safe [[https://github.com/arximboldi/lager/issues/118]]
* Using src_c++{lager::state} (leave to Dmitry)
* Appendix
** Calculating libQuotient coverage adjusted
libQuotient includes the generated csapi folder into coverage, while libkazv does not. Here is the code that calculates the coverage of libQuotient excluding the csapi folder.
#+NAME: libquotient-coverage
#+BEGIN_SRC perl
my $csapiCoverage = 0.169;
my $csapiUncovered = 1_668;
my $totalLines = 11_229;
my $totalUncovered = 6_561;
my $csapiLines = $csapiUncovered / (1-$csapiCoverage);
my $remainingLines = $totalLines - $csapiLines;
my $remainingUncovered = $totalUncovered - $csapiUncovered;
my $remainingCoverage = 1 - $remainingUncovered / $remainingLines;
$remainingCoverage;
#+END_SRC
#+RESULTS: libquotient-coverage
: 0.46940827964562
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..3c83e99
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+.src {
+ text-wrap: wrap;
+}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:28 PM (23 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39020
Default Alt Text
(6 KB)

Event Timeline