[Geany-Devel] Let's move to C++98 - Re: Lets move to C99

Nick Treleaven nick.treleaven at xxxxx
Thu Sep 5 09:20:03 UTC 2013


On 05/09/2013 09:41, Matthew Brush wrote:
> On 13-09-04 09:20 AM, Nick Treleaven wrote:
>> My C89 & C++ version:
>>
>> guint i;
>> foreach_document(i) {
>>      GeanyDocument *doc = documents[i];
>>      // do stuff with every valid doc
>> }
>>
>
> While this code is short, it's actually sort of nuts too (and also not
> very C++-ish).
>
> 1. You should include the definition of the custom macro used and the
> definitions of the two other non-obvious macros used inside the first
> macro for a fair comparison, since none of them are standard or even
> well-known like the pasted examples.

Most files already include document.h.

> 2. The code does not loop over the windows like the pasted code, so
> you'd need another outer loop which would likely have a 2nd style of
> iteration wrapped around the existing loop.

We don't support accessing multiple windows IIUC.

BTW I was just providing code for that specific case, not necessarily 
for all iteration.

> 3. It's somewhat unclear what type should be passed in looking at the
> macro without the doc comments (I always forget and have to RTFM each
> time I see it since we often use gint where we mean guint).
>
> 4. The argument is not only assigned to but also evaluated multiple
> times (what if you pass `--i` or something weird as argument). I guess
> assigning might be good here since the compiler would catch it rather
> than flying off the end of the array when it hits `(guint)-1` (UINT_MAX)
> on underflow.
>
> 5. It's fairly tricky to debug misuses of the macro (better with Clang).
>
> 6. The implicit check in the loop (failure first) indexes into a macro
> wrapper around a whole other type using a hard cast from the result of
> another function-like macro cast thing off in another file, and is
> dereferenced without any NULL check (although probably safe in this
> case, unless a plugin or something re-assigns the global variable or
> redefines any macro aliases of it).
>
> 7. It forces you to define an indexing variable outside of the loop into
> the wrong scope (C89-style, even if used in > C99 plugin code).
>
> 8. Even though slightly dirtier, it would be more useful to iterate over
> document pointers than document indexes (what are those? tab pages?
> order of opening? arbitrary array indices?), for example (untested, C99
> or GNU89 probably):
>
>      #define foreach_doc(doc) \
>          for (unsigned z_=0; z_ < documents_array->len; z_++) \
>             if ( !((doc) = documents_array->pdata[z_]) || \
>                  !(doc)->is_valid ) { continue; } else
>      ...
>      GeanyDocument *doc;
>      foreach_doc(doc) {
>        // every valid doc
>      }

Yes, that is much better if we have C99/C++. That also solves most of 
the points above.

> 9. I personally find it annoying to use API's that have all their own
> versions of things that are really common and not that hard anyway; it's
> difficult to learn them all, and also all the stuff mentioned above when
> they are macros. Consider this slightly longer example that uses no
> macro madness and common C looping idiom:
>
>      guint i;
>      for (i = 0; i < documents_array->len; i++) {
>        GeanyDocument *doc = documents_array->pdata[i];
>        // do stuff with every *should be* (but isn't) valid doc
>      }
>
> Assuming the API didn't have the weirdness about documents being invalid
> but still sticking around for whatever reason, it's the same number of
> lines as the macro version and no magic.

Yes. Although sometimes bugs do slip through, even in incrementing for 
loops. Suppose someone used <= instead of <, or forgot to initialize i.

> 10. The macro should be named `foreach_document_index()`.

OK.

>> I don't think we should rewrite Geany's API in C++, or maintain a C++
>> wrapper for the C one, except for any cases which are particularly
>> bug-prone.
>>
>
> An idiomatic C++ binding would be quite useful for a plugin written in
> normal C++. In my current C++ plugin I'm working on, I'm actually
> wrapping up a few parts of Geany's API it uses to avoid scattering the
> weird C code containing lots of raw pointers, miscellaneous allocators,
> different string/collection types, and so on, throughout the normal C++
> code.

It would be useful, but also a distraction for the core project.


More information about the Devel mailing list