Skip to content

Conversation

@daljit46
Copy link
Member

@daljit46 daljit46 commented Jul 10, 2025

This PR introduces a new string formatting utility, MR::format_string, and integrates it into the primary logging macros (CONSOLE, FAIL, WARN, INFO, DEBUG) to provide a more modern and convenient way to format log messages.

Previously, formatting log messages with dynamic values required manual string concatenation or the use of std::ostringstream, which can be verbose and less readable.

Now, instead of this:

WARN("Failed to open file " + filename + " with error code: " + std::to_string(errno));

you can do the following:

WARN("Failed to open file {} with error code: {}", filename, errno);

Perhaps this could be made more robust to check at compile time whether the number of {} parameters match the number of arguments provided (amongst other things), but I think that will make the implementation significantly more complex. This is a good enough solution until we move onto C++20, which introduces std::format (an alternative would be to implement #2951).

@daljit46 daljit46 self-assigned this Jul 10, 2025
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Previously, formatting log messages with dynamic values required manual
string concatenation or the use of `std::ostringstream`, which can be
verbose and less readable.
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

@daljit46 daljit46 requested a review from a team July 10, 2025 17:43
@jdtournier
Copy link
Member

Something like this would be nice. Having recently started playing around with std::format(), I have to say that the C++ streams interface feels really clunky, overly verbose, and generally old-school.

However, the implementation you're suggesting seems quite primitive, if I'm not mistaken? I was assuming we'd instead opt for something with a few more features, such as the fmt library - is that an option? The license seems pretty permissive, and it seems to be very widely used.

@daljit46
Copy link
Member Author

daljit46 commented Jul 11, 2025

However, the implementation you're suggesting seems quite primitive, if I'm not mistaken? I was assuming we'd instead opt for something with a few more features, such as the fmt library - is that an option? The license seems pretty permissive, and it seems to be very widely used.

Yes, this implementation is indeed quite simplistic. Integrating proper formatting support, as mentioned in #2951, using the fmt library (on which the std::format proposal was based) would be a solid improvement. If we want to go that route, I'm happy to open a new PR that supersedes this one with fmt integrated.

@Lestropie
Copy link
Member

I'd be concerned about there being a distinction in syntax between construction of a string within one of these macros versus construction of a std::string causing confusion, including among those outside the core development team.

If there's a comparable capability in C++20, and compilation from source is increasingly restricted to developers only, then I'd have thought that changing the language standard would make more sense? Though we probably have a lot more to resolve with 17 before progressing further.

@daljit46
Copy link
Member Author

daljit46 commented Jul 12, 2025

Personally, I would be in favour of upgrading the standard of compilation to C++20 (which doesn't necessarily mean utilising all of its features). Compiler support is quite good nowadays(modulo C++20 modules).
That said, fmt provides a virtually equivalent interface to std::format, so switching between the two shouldn't be a major effort. In addition to std::format, fmt also provides support for std::print introduced in C++23.

@jdtournier
Copy link
Member

That's a good suggestion, I've just been getting up to speed with the C++20 standard, and there are a few nice features in there that would be good to have access to. Compilation is still tricky on older versions of the OS, but these are diminishing concerns, especially as most users will install pre-compiled binaries, and we can provide feature binaries on demand. There is now first-class support for C++20 modules in CMake, which I think would be good to explore in due course (not for now though, that will require quite a bit of rejigging). Either way, we should be able to compile against C++20 now with minimal changes, and we can gradually start to make use of the new functionality as opportunities arise. Happy to go with that plan!

@daljit46
Copy link
Member Author

daljit46 commented Jul 12, 2025

I checked the minimum compiler versions needed for std::format: GCC >=13 and Clang >=14. Clang 14 is available on the most recent Linux distros, but GCC 13 was released in April 2023, so distros like Ubuntu 22.04 LTS don't package it by default (you will need to set up an external PPA to install it).

@Lestropie
Copy link
Member

If fmt is reasonably well-used, and the syntax means that it would translate very easily to C++20 after the fact, and it's easy for cmake to integrate as a compile dependency, then I wouldn't be against using that. But I'm conscious that us old hands are likely to persist with legacy syntax out of habit, and having an extra layer of complexity present for no benefit doesn't make sense. It may not be something that warrants inclusion in check_syntax, but would it be possible to:

  1. Mass auto-refactor the code base?
  2. Have clang-format issue a warning on use of std::string::operator+() where fmt could be used?

@jdtournier
Copy link
Member

Just jotting down some thoughts about this:

  • I think we definitely want to use a more mature implementation, either using the fmt library or C++20 std::format()
  • Using std::format() implies a move to C++20, which I'd be happy with, though it will make building on older systems a bit tricky. That said, Ubuntu 22.04 comes with clang++ v14, which supports most of the C++20 functionality we're likely to use in the short term (modules being a notable exception). On the other hand, Ubuntu 20.04 doesn't include sufficient support (gcc 9,4, clang v10).
  • the fmt library seems to provide more features than std::format() out of the box, and might be worth using regardless, even if we do eventually decide to move to C++20 for other reasons. It also claims their implementation of format() is compatible with C++20, so it would presumably be trivial to switch back to the C++20 std version if we choose to at a later stage.

Basically, I'm happy with either using the fmt library or moving to C++20 and using std::format().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants