lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Inversion of control


From: Greg Chicares
Subject: Re: [lmi] Inversion of control
Date: Thu, 13 Sep 2018 00:31:24 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1

On 2018-09-08 15:32, Vadim Zeitlin wrote:
> On Sat, 8 Sep 2018 15:19:41 +0000 Greg Chicares <address@hidden> wrote:
[...]
> GC> Right now, I'm just asking you to tell me whether I'm on the right
> GC> track.
> 
>  Yes, I think so. I.e. the most complicated is usually determining the "Fn"
> parts of code and you've already done it.

I've written something that does appear to work:
  http://git.savannah.nongnu.org/cgit/lmi.git/commit/?h=odd/pagination
but it seems too ugly.

> GC> C++ member-function pointers can be unwieldy, so my first
> GC> thought would be to use this as a mixin class: make the paginate()
> GC> demonstration a member function that calls some new virtuals, then
> GC> 
> GC>  class page_with_tabular_report
> GC>      :public numbered_page
> GC>      ,protected using_illustration_table
> GC> +    ,private paginator
> GC> 
> GC> and reimplement that class's render() function. And I guess I'll
> GC> want a default ctor for class paginator, and an init() function
> GC> that I can call from render(). Or does another approach seem
> GC> clearly better?
> 
>  No, this is a perfectly good implementation of this pattern in what I
> called OO style. The main advantage of the functional style is that you do
> not have to create a new class, deriving from paginator, to use it. But in
> this case we already have a class, so this advantage is not very important.

That's where I think I went down the proverbial rabbit hole.

I didn't actually do this...

> GC>  class page_with_tabular_report
> GC>      :public numbered_page
> GC>      ,protected using_illustration_table
> GC> +    ,private paginator

...because I don't see how I can implement the pagination class's virtuals
as members of class page_with_tabular_report. The reason is that the
tabular-report class has only member functions--it doesn't have data members,
so AFAICT an instance has no state. Rather, "state" is imbued by passing
arguments, and most of the member functions take similar arguments:

        (Ledger const&            ledger
        ,pdf_writer_wx&           writer
        ,html_interpolator const& interpolate_html
        )

But arguments can't be added to pagination-class virtuals. For example,
consider (left-aligned '#' comments added for this discussion only):

        void print_a_data_row () override
        {
# The derived pagination class isn't a mixin, so it can't call the
# tabular-report class's members directly--so I pass an instance of that
# class into the paginator by reference. (It's called 'outer_' because
# I originally thought the paginator wanted to be a nested class.)
# Similarly, arguments to render() like 'ledger_' are passed into this
# pagination class by reference.
            auto const v = outer_.visible_values(ledger_, interpolate_html_, 
year_);
# 'pos_y' was a local variable in render(), which wasn't a reference to
# anything external to that function, so I made it a pagination member.
            table_gen_.output_row(pos_y_, v);
# 'year' is a pure local; no problem here.
            ++year_;
        }

> Another advantage of functional style is that you can easily mix and match
> parts of different implementations, which is impossible or at least very
> inconvenient with the OO style, i.e. if you have classes FooBar and BazQuux
> deriving from paginator, you typically can't easily define a class FooQuux
> which takes half of FooBar implementation and half of BazQuux. But again,
> in this particular case, I don't think we're going to need this.

In my 'odd/pagination' branch, I guess that, fundamentally, I was struggling
to invent a closure; and that made me wonder whether a functional style would
be better. But I'm not at all sure that it would be much different: lambdas
can capture state, but class page_with_tabular_report doesn't have any state
to capture--or, alternatively, the required state isn't the state of a class
instance, but rather the arguments passed to all the member functions. But I
don't see how I can write a conjectured virtual member like
    void page_with_tabular_report::print_a_data_row() override
that captures the state of a different member function, namely
    void page_with_tabular_report::render() override

Now that I have something that does have the virtue of actually working, can
you say how it might be reimplemented cleanly?

I have only one question about the original implementation: concerning
its next_page() function, did I guess correctly here...

        void open_page        () override
        {
            // "if": guesswork--next_page() seems to have been called already.
            if(0 != year_) outer_.next_page(writer_);

...and in the following?

        void close_page       () override
        {
// See open_page() above. This causes an assertion to fail:
        // This function may only be called if we had reserved enough physical
        // pages for these logical pages by overriding get_extra_pages_needed().
//      LMI_ASSERT(0 < extra_pages_); <-- fails
// Conjecture: once the last page has been printed, asking for
// the "next" page fails because there is no next page.
//          outer_.next_page(writer_);
        }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]