Date: Mon, 29 Mar 2021 18:17:06 -0400
On Sat, Mar 27, 2021 at 1:32 PM BogDan via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hi again,
>
> I'm re-posting the link to the proposal as a simple text
> https://github.com/bog-dan-ro/cppstd/blob/master/declarative_c++.md as it
> was altered by mailman .
>
It seems like you're trying to invent a GUI-widgets API at the same time as
a language feature. I recommend sticking to just the API or just the
language feature. Design the API the way you want it, and *then* see if any
new language feature could really improve it or not.
For example, take
https://github.com/bog-dan-ro/cppstd/blob/master/declarative_c++.md#v2-using-object-lambdas
and write that API using standard C++; you'd get something like this:
struct Window : std::enable_shared_from_this<Window> {
template<class F> requires std::invocable<F, Window&>
explicit Window(const F& setup) {
setup(*this);
}
};
auto window = std::make_shared<Window>([](auto& w) {
w.width = 100;
w.height = 10;
w.children = {
std::make_shared<Label>([](auto& label) {
label.y = 10;
label.text = "Some label";
},
std::make_shared<Button>([&](auto& label) {
label.text = "Quit";
label.clicked = [parent = w.shared_from_this()]{
parent->close(); };
},
};
};
Is that where we're starting from? Personally,
- I don't do much GUI-widgets stuff,
- I think that's a "clever" API,
- but I'm not sure I'd want to use it.
It seems to make too much stuff public, and permit too many things to go
uninitialized — see how the first child sets its `y` coordinate but fails
to set its `x` coordinate. We can kinda deal with this via the Builder
pattern — we say that the `const F& setup` lambda actually receives a
WindowBuilder object, not a Window directly, and then the Window itself is
able to sanity-check the (all-public) state of the WindowBuilder before
actually "committing" its changes (into private members of Window). But
still, this is very runtime-oriented — very far from what I personally mean
when I say "declarative." To me, "declarative" means that there's no
runtime code — it's just a bunch of declarations, type-checked at compile
time, and then if it compiles it's guaranteed to work correctly. Any
solution that lets you set `label.y` without also setting `label.x` is the
*opposite* of what I'd call "declarative."
So, I think you (having seen how one'd write that API in standard C++)
should identify some concrete problems with the standard C++ solution, and
then look for solutions to those problems. For example, it sounds like "too
much stuff being public" is *not* one of the problems you're concerned with.
The ideal outcome is that you say "hmm, actually, I don't see any problems
with the present-day-C++ API," and then we're done here. ;)
–Arthur
std-proposals_at_[hidden]> wrote:
> Hi again,
>
> I'm re-posting the link to the proposal as a simple text
> https://github.com/bog-dan-ro/cppstd/blob/master/declarative_c++.md as it
> was altered by mailman .
>
It seems like you're trying to invent a GUI-widgets API at the same time as
a language feature. I recommend sticking to just the API or just the
language feature. Design the API the way you want it, and *then* see if any
new language feature could really improve it or not.
For example, take
https://github.com/bog-dan-ro/cppstd/blob/master/declarative_c++.md#v2-using-object-lambdas
and write that API using standard C++; you'd get something like this:
struct Window : std::enable_shared_from_this<Window> {
template<class F> requires std::invocable<F, Window&>
explicit Window(const F& setup) {
setup(*this);
}
};
auto window = std::make_shared<Window>([](auto& w) {
w.width = 100;
w.height = 10;
w.children = {
std::make_shared<Label>([](auto& label) {
label.y = 10;
label.text = "Some label";
},
std::make_shared<Button>([&](auto& label) {
label.text = "Quit";
label.clicked = [parent = w.shared_from_this()]{
parent->close(); };
},
};
};
Is that where we're starting from? Personally,
- I don't do much GUI-widgets stuff,
- I think that's a "clever" API,
- but I'm not sure I'd want to use it.
It seems to make too much stuff public, and permit too many things to go
uninitialized — see how the first child sets its `y` coordinate but fails
to set its `x` coordinate. We can kinda deal with this via the Builder
pattern — we say that the `const F& setup` lambda actually receives a
WindowBuilder object, not a Window directly, and then the Window itself is
able to sanity-check the (all-public) state of the WindowBuilder before
actually "committing" its changes (into private members of Window). But
still, this is very runtime-oriented — very far from what I personally mean
when I say "declarative." To me, "declarative" means that there's no
runtime code — it's just a bunch of declarations, type-checked at compile
time, and then if it compiles it's guaranteed to work correctly. Any
solution that lets you set `label.y` without also setting `label.x` is the
*opposite* of what I'd call "declarative."
So, I think you (having seen how one'd write that API in standard C++)
should identify some concrete problems with the standard C++ solution, and
then look for solutions to those problems. For example, it sounds like "too
much stuff being public" is *not* one of the problems you're concerned with.
The ideal outcome is that you say "hmm, actually, I don't see any problems
with the present-day-C++ API," and then we're done here. ;)
–Arthur
Received on 2021-03-29 17:17:18