Should Octave switch to C++17? If so, when?

Octave’s C++ codebase is largely in C++11. Last month, a C++17 polymorphic allocator feature was added (see octave: abb4823df535 and octave: 9b41aba64c12) to fix bug 61472 GNU Octave - Bugs: bug #61472, AddressSanitizer crash in MEX tests [Savannah]. That code has been made optional with a configure-time flag.

Currently there is bug report 61800 about using C++17 to shorten and simplify code pertaining to octave_value GNU Octave - Bugs: bug #61800, possible code simplification with... [Savannah]. It is perceived as too much effort to maintain two different versions of octave_value, favoring a single lane instead, so the following questions need to be discussed.

  • Should Octave raise its minimum C++ level from C++11 to C++17? This will affect minimum compiler versions and standard library versions to build Octave.

  • If so, starting from what Octave version? 8? 9? Beyond 9?

  • What are the consequences for package maintainers, oct files and mex files?

Some data:

The effect on packages or user C++ code depends on where we’d like to use the new language features. If we use them only internally, the effect on packages or user C++ code would probably be minimal.
If we’d like to use these features in the interfaces (API), packages and user C++ code must be compatible with C++17 and they also have to be compiled with that (minimum) version.
Most compilers support most C++17 features currently. However, there are quite a few Octave packages that compile with -std=c++11 or -std=gnu++11 in their build rules. Those packages would no longer compile if features that aren’t available in that standard version are used in Octave’s API. User code might also be affected similarly.

I don’t know if someone has checked in detail why those packages set -std=c++11 or -std=gnu++11 in their build rules. Maybe they need features that were introduced in C++11 (but are also available in later versions of the standard). Maybe, they need that specific version of the standard to work correctly (and won’t work correctly without modifications with newer standard versions)…

Edit: Both features you are hinting at make changes in Octave’s API IIUC.
Taking this into consideration, we should probably give notice sufficiently in advance to give developers time to adapt their code/build rules for this change in requirements. Maybe one or two major versions is enough time for that. I.e., if we decide now to give notification of that change with the release of Octave 7, we could maybe use those features in the API of Octave 8 or 9.

Edit 2: Depending on which features of the C++17 standard we’d like to use, the minimum GCC version might be GCC 8 (according to the above link). The minimum clang might be version 6.
For features that are implemented in the STL, the minimum version might be GCC 12 (libstdc++). Not all features are currently implemented in libc++ (clang or Apple clang).
See also Compiler support for C++17 - cppreference.com

1 Like

I will use this comment to make a list of action items as we go along. I’ll edit as new information comes in and hopefully it’ll help as we converge.

  • Action item for core maintainers: add a note to NEWS for Octave 7 that Octave will require C++17 to build starting from version 8 (based on this discussion.

  • Action item for package maintainers: if your package currently requires -std=c++11 or similar flags, examine whether your package will build without them.

Edited to mention Octave 8.

I don’t think [GNU Octave - Bugs: bug #61800, possible code simplification with... [Savannah]] in its current state changes the API, no data members are changed or added to octave_value, only member functions are added, no existing methods removed or changed.

Compiling octave on an old platform is not for the faint hearted anyway. I have recent experience on a RHEL 6.2, that came for instance with gcc 4.x, qt4.3. In order to built a fully functional recent octave version you will have to install (qt5.7 was the latest pre-built suitable for that platform) or build your own more recent versions of quite a few libraries. gcc 9 was the latest I built on that platform.

I guess anyone determined enough to attempt building a recent version of octave on such a platform can be expected to be able to build a c+±17 compatible environment.

If I read those changes correctly, ov.h will include AnyDiag.h which in turn includes <variant>. That header won’t be available with e.g. -std=gnu++11 (independent of the used compiler version). That means that some Octave packages won’t compile any longer. I’d consider that an API change…

I agree. Most compilers that are able to compile a recent version of Octave should also be able to compile most C++17 features. That’s what I was trying to describe with using those features internally.
However, public facing headers are also included in other projects (mostly Octave packages or C++ user code). If newer features are used in those public facing headers, we should probably measure differently…

I propose requiring C++17 starting from Octave 8, the changeover to be made to the dev sources sometime after Octave 7.1 is released in the next several weeks.

I believe that will give enough time (a year or more) for package maintainers to switch if necessary, based on time intervals between major releases for recent releases.

Does anyone see anything wrong with adding C++17 for Octave 8?

IIRC, Qt6’s API requires C++17, too. Another possible timeframe could be to allow C++17 in Octave’s API when we start supporting Qt6 or stop supporting Qt5.
That’s likely not going to happen before Qt6 is readily available on Debian based distributions though…
See also: Qt5.15 already unsupported upstream (except commercial license)?

1 Like

I have edited a previous comment to indicate we should switch to C++17 starting from Octave 8. The dev sources should probably be switched over sometime this year as is convenient. Some choices are the release of Qt6 or earlier.

@mmuetzel, are you OK editing the news file for 7 to warn users and package developers of this?

Just fyi – RedHat 8 and derivatives have gcc version 8.5.0 which does not have full C++17 support.
RedHat 9 (gcc 11.2+) is expected to be released in May or about.

1 Like

Imho, we shouldn’t rush bumping the minimum required C++ version. The implementation of the full feature set of C++17 was finished in the compiler/STL very recently (libstdc++ from GCC 12) or isn’t even done yet (as of libc++ from LLVM 13).
Octave 8 might be too early.

I added the topic to the schedule for next developers meeting:
Online Developer Meeting (2022-01-25) - Octave

Maybe, we could collect more information until then…

An alternative might be to provide different implementations of the same features targeting different C++ standard versions (or better use feature tests). But that increases the maintenance burden and might not work very well when it comes to the API…

1 Like

I agree with you on not maintaining two versions of the same code in parallel for C++11 and C++17. That is asking for a lot of maintenance work without building new functionality. So the main question seems to be to find out the best time to switch. Hopefully the devs meeting will provide some clarity.

I acknowledge that my own distro is a bit ahead of the curve in adopting recent compiler versions, and that other distros may be more conservative. That should not affect the end user if they are only downloading the Octave binary from their repository, but it might affect package maintainers running older compilers.

In the meantime, there’s C++17 code contributions like what @ARBurgers made in the original Savannah post and more such to come this year. What is the best way to make sure that such code contributions don’t get lost over time?

Like we decided in yesterday’s meeting, I enabled the polymorphic allocators for default Octave in MXE Octave here:
mxe-octave: 7c82402297b2

I took the time to hunt down where the two packages (I know of) that were failing last time were setting -std=gnu++11. I added some patches that removed that switch here:
mxe-octave: 0bf2a154ef3e
mxe-octave: 8d1aecf2d2d6

Those simple patches are probably not enough for the upstream packages. But we know our (cross-)compiler in MXE Octave. So, it should be safe here.

Let’s see what the buildbots will make out of this.

Edit: The first one failed:
Buildbot (octave.org)
Hmmm…
It might have started before I pushed the patch for ltfat. Let’s wait for the next run tomorrow.

There are no compilation errors for the buildbots since these changes.
Did anyone test whether those packages (and potentially also the others) still work correctly?

The following packages fail to install for me on API v57+ with current dev Octave 8: communications strings stk image parallel ocl signal struct optim quaternion geometry.

Most of them do install on API v56 or v55.

Is that related to C++17 or is it a different problem?

Compatibility with Octave 8 might be an orthogonal issue.
Try compiling those package with Octave 7 with enabled pmr. Do all of them compile and function correctly?

I did a complete uninstall of all Octave versions and packages, and started over. Starting with a clean build of 7.0.90 from https://alpha.gnu.org/gnu/octave/octave-7.0.90.tar.xz.sig, after configure, make, make install:

octave:1> ver
----------------------------------------------------------------------
GNU Octave Version: 7.0.90 (hg id: 347dbc9049d5)
GNU Octave License: GNU General Public License
Operating System: Linux 5.10.93-1-MANJARO #1 SMP PREEMPT Thu Jan 20 09:46:07 UTC 2022 x86_64
----------------------------------------------------------------------
no packages installed.

The following packages install OK:

statistics, io, struct, symbolic, video, matgeom, geometry, audio, instrument-control, arduino, dataframe, linear-algebra, miscellaneous, general, ga, cgi, control, vrml, interval, lssa, mvn, nan, nurbs, octproj, optiminterp, sockets, 

The following install with warnings about deprecated operators:

mapping, financial, fuzzy-logic-toolkit, image-acquisition, queueing, splines

Package optim has an error with the decrement operator having a space (not a C++17 error, but I thought this was fixed in the package so I’m not sure why it is showing up again now with a clean install). This prevents packages econometrics and data-smoothing from being installed because optim is a prerequisite for those two packages:

octave:7> pkg install -forge optim
...
error: parse error near line 118 of file .../optim-1.6.1/lsqlin.m

  n_out: invalid use of symbol as both variable and command

>>>     n_out --;
       ^
error: called from
    doc_cache_create>create_cache at line 116 column 20
    gen_doc_cache_in_dir>@<anonymous> at line 150 column 16
    doc_cache_create>gen_doc_cache_in_dir at line 151 column 9
    doc_cache_create at line 62 column 12
    install>generate_lookfor_cache at line 840 column 5
    install at line 241 column 7
    pkg at line 603 column 9

Package signal has the same error:

pkg install -forge signal
error: parse error near line 123 of file .../signal-1.4.1/buffer.m

  off: invalid use of symbol as both variable and command

>>>             off --;
               ^

Package gsl has several errors like this. Not sure if C++17 errors or unrelated errors:

octave:3> pkg install -forge gsl
gsl_sf.cc:53:3: error: use of undeclared identifier 'feval'; did you mean 'octave::feval'?
  feval ("help", octave_value ("gsl_sf"));
  ^~~~~
  octave::feval
/usr/local/include/octave-7.0.90/octave/../octave/parse.h:926:3: note: 'octave::feval' declared here
  feval (const char *name,
  ^
gsl_sf.cc:124:11: error: no member named 'is_real_type' in 'octave_value'
    if (! ISREAL(args(i)))
          ^~~~~~~~~~~~~~~
gsl_sf.cc:32:24: note: expanded from macro 'ISREAL'
#define ISREAL(x) ((x).is_real_type ())
                   ~~~ ^

Package quaternion has the following errors, not C++17 but API-related:

is_real_array.cc:49:32: error: no member named 'is_numeric_type' in 'octave_value'
                || ! ((args(i).is_numeric_type () && args(i).is_real_type ())
                       ~~~~~~~ ^
is_real_array.cc:49:62: error: no member named 'is_real_type' in 'octave_value'
                || ! ((args(i).is_numeric_type () && args(i).is_real_type ())
                                                     ~~~~~~~ ^
is_real_array.cc:50:34: error: no member named 'is_bool_type' in 'octave_value'
                      || args(i).is_bool_type ()))
                         ~~~~~~~ ^

Did you configure with enabled pmr?

Yes, this was with the polymorphic allocator. It looks like the package installation errors are all API errors and not C++17 errors, so at least the C++17 parts are good. Are you not getting any errors installing these packages?