lmi
[Top][All Lists]
Advanced

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

Re: [lmi] Not urgent: a plausible micro-optimization


From: Greg Chicares
Subject: Re: [lmi] Not urgent: a plausible micro-optimization
Date: Fri, 23 Feb 2018 12:17:21 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2

On 2018-02-23 02:24, Vadim Zeitlin wrote:
> On Thu, 22 Feb 2018 23:26:47 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> On 2018-02-22 13:31, Vadim Zeitlin wrote:
[...]
> GC> > 2. Replace the existing assignment with a copy. This is what I did in a
> GC> >    new https://github.com/vadz/lmi/pull/69
> GC> 
> GC> I'm not opposed to accommodating the wx container classes. But I'd
> GC> rather not use a for-loop to bring one element to the front [and I
> GC> don't think that's exactly the loop you intended to write anyway].
> 
>  To be honest, for me the most straightforward way remains to write the
> code in the way I had done originally, i.e. first update the active child
> and then all the rest in a loop. All the other ones seem more or less
> equally artificial to me.

My native language is still APL, in which the original version
of this code would be:
  Update¨ChildList
where '¨' means "each". C++ can now write that as
  for(auto& i : ChildList) {Update(i);}
but the APL version is easier to read and much harder to get wrong.
The difference is that in APL collections are first-class objects,
so you just say _what_ you want to do with a collection, not _how_
to do it.

Now we want to enhance that code to update the active child first.
In idiomatic APL we can't push that logic into the loop, because
there's no explicit loop...but that doesn't matter, because the
problem is the order of ChildList, so we wouldn't hesitate to do:

  Update¨ActiveChild,(ActiveChild≠ChildList)/ChildList

where
 "≠": bit-vector indicating whether each element != active child
 "/": select elements where that bit-vector is "true"
 ",": concatenate
thus: concatenate ActiveChild with (ChildList without ActiveChild)

Here, "(A≠L)/L" is a universally-known idiom: it's in finger memory,
so we type it without thinking, and it's instantly recognizable even
to a beginner. An expert might simply sort the array by a collating
sequence that puts ChildList first; or, assuming the active child is
in the list, just rotate the list to bring it to the front (because
it's shorter, even if somewhat goofy):

  Update¨(ChildList⍳ActiveChild)⌽ChildList

or, in an extended dialect that provides ∪ (uniquify):

  Update¨∪ActiveChild,ChildList

which is probably the prettiest possible: prepend ActiveChild to
ChildList, remove duplicates, and update each. That's immediately
writable, immediately readable, hard to get wrong, and harder
still to get subtly wrong: any mistake would stand out.

Hieroglyphs like "¨" are the platonic forms we long for--the tools
we actually use for thinking--discovered, not invented--and
translating these thoughts back into the broken world of C++ is
just the burden we must bear.

This isn't mere aesthetics. Another reason why I say that I would...

> GC> rather not use a for-loop to bring one element to the front [and I
> GC> don't think that's exactly the loop you intended to write anyway].

is that it's harder than it looks to write a C++ loop to "bring a
given element to the front", and harder than it should be to see
whether it's correct or what it really does, because it involves
translating "Update¨∪ActiveChild,ChildList" into procedural
instructions at a lower level than our thoughts. The mismatch
between C++ and the way we actually think overtaxes our patience.
Just the other day I investigated a new defect report pertaining
to some simple-as-dirt code that I had already corrected twice
before, and exclaimed that the concept was so simple that I
couldn't possibly code it correctly--my conviction that it was
too trivial to deserve much attention was the obstacle.

> GC> How about the following alternative?
[...]
> GC> +    // Make a local copy of the list for modification.
> GC> +    wxWindowList const&  y = frame_->GetChildren();
> GC> +    std::list<wxWindow*> z(y.begin(), y.end());
[...]
>  This was actually my first attempt, and I should have mentioned it, but it
> doesn't compile because wxWindowList::const_iterator doesn't satisfy the
> input iterator requirements and in C++11 this ctor is only used when this
> is the case.

Then let's solve that problem. I'm sure I could write a function
to copy a wxList<wxWindow> into a std::list<wxWindow*>, using a
loop for instance. But I don't need to do that, because...

>  But to finish with this approach: to make it work, wx containers iterators
> need to be changed and while it's certainly a good idea to do it, I don't
> think you'd want to upgrade wx just for this, so it would be still nice to
> have another solution for now.

If you do that, then lmi HEAD is no longer broken for you: it
works with a default build of wx HEAD. And it never was broken
for me because I use a non-default STL build of wx. The only
remaining issue is that we aren't using the same wx SHA1, and the
way to rectify that is for us to update wx for lmi. But we can't
do that today because of submodules, which brings us back to:

http://lists.nongnu.org/archive/html/lmi/2018-02/msg00015.html

| > GC> yet we might need to upgrade at any time, so we'd better rewrite
| > GC> 'install_wx.make' pretty soon.
| > 
| >  Would you like me to do this or do you prefer to do it yourself?
|
| Let me handle that

which I would like to amend thus:

- Let me handle that
+ Yes, please!



reply via email to

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