Live data from Hacker News

F-strings for C++26 proposal [pdf]

open-std.org

201–210 of 216 posts

Re: F-strings for C++26 proposal [pdf]

#201
post #150

Earlier quoted context omitted.

> "preventing themselves from accidentally mutating a variable" (when has that ever happened?) I can't count the number of times I've seen someone new to the language use map::operator[] without realizing that it's a mutating operation.

map::operator[] should just be [[deprecated]] - even if you want to mutate the map it's probably not the best way to do what you want.

I kinda like it on occasion. Works like pythons defaultdict. Like, if you wanna count something:

    for (const auto &thing: collection) {
        counts[thing]++;
    }
Works nicely, you don't have to check if it's already there before ++ing it. As long as you know that's what operator[] does, it comes in handy more than I would've expected.

Re: F-strings for C++26 proposal [pdf]

#202
post #201

Earlier quoted context omitted.

map::operator[] should just be [[deprecated]] - even if you want to mutate the map it's probably not the best way to do what you want.

I kinda like it on occasion. Works like pythons defaultdict. Like, if you wanna count something: for (const auto &thing: collection) { counts[thing]++; } Works nicely, you don't have to check if it's already there before ++ing it. As long as you know that's what operator[] does, it comes in handy more than I would've expected.

Yeah. It has its uses. You could accomplish the same with the rather verbose `counts.try_emplace(thing).first->second++` but nobody wants to type that (even if it is more explicit about what it's doing).

Another popular use case is something along the lines of:

    std::unique_ptr& ptr = ptrs[key];
    if (ptr != nullptr) {
      ptr = std::make_unique(...);
    }
That said, I don't know what behavior I'd want if maps didn't automatically insert an element when the key was absent. UB (as with vector)? Throw an exception? Report the incident to Stroustrop? All these options feel differently bad.

Re: F-strings for C++26 proposal [pdf]

#203
post #110

Earlier quoted context omitted.

The safety and readability are nice; but WHY do they have to be in order? That is so typically clueless. Such an obvious feature, screwed up in a way that only a C++ committee member could.

Initializers for members are _always_ run in the order the member is declared - this applies even in constructor initializing lists, see https://en.cppreference.com/w/cpp/language/constructor#:~:te... - it doesn't matter what order you declare the initializers in, and clang will warn you if you write your initializers in an order other than what they will be executed in. Designated initializers are the same way, it's…

> Why is it this way? As best as I can find it's so that destructors always run in reverse order of construction, I guess there could be some edge cases there that matter. It's not the strongest argument, but it's not nothing.

I have seen my share of teardown races that were fixed by reordering data members. There's nothing quite like having a mutex torn down before the object that it's guarding.

Running destructors in reverse order of construction is really the only thing that makes sense in an RAII world. It's the same argument as running the destructors in reverse order of construction when exiting a scope.

That's still not a great reason for designated initializers being restricted in the same way they were in C90, especially given the advantage of hindsight. It makes a ton of sense if you have explicit dependencies between data members created during construction, but I can't see a way that you can create those dependencies with designated initializers.

Re: F-strings for C++26 proposal [pdf]

#204
post #131

Earlier quoted context omitted.

const is different in C++ from const in C. const variables in C++ are proper compile-time constants. In C they are not (the nearest equivalents are #define and enum values). So in C++ "const x = EXPR" would make sense to request compile-time evaluation, but in C it wouldn't.

They absolutely are not. Look at this range for-loop: for (const auto item: vec) { ... } `item` is not a compile-time constant. It's different every run of the loop.

Ouch, but thanks. I learned something today - something I'd long forgotten. I like your example, it shows the point well. (Though, there are circumstances when a compiler can unroll such a loop and infer a compile-time constant, it wouldn't qualify as a constant expression at the language level.)

It's been so long since I used C++ for serious work that we weren't using C++11, so neither auto nor range-for were available. It would be uncommon to see "const type = " with a non-reference type and a non-constant initialiser.

Even with your example, some styles avoid "const auto item", using either "auto item" or "const auto& item" instead, because the "const" matters when taking a reference, not so much with a copy.

But I appreciate your point applies to const variables with non-constant initialisers in general, in the language.

There was once a big deal in literature about const in C++ being the "better" alternative to how #define is commonly used with C for constant values, and it seemed applicable to the thread as a key distinction between C and C++, which the parent commenter seemed to have conflated by mistake.

But I'd forgotten about const (non-reference) variables accepting non-constant initialisers, and as I hadn't used C++ seriously in a while, and the language is always changing, I checked in with a couple of C++ tutorials before writing. Unfortunately those tutorials were misleading or too simple, as both tutoruals said nothing about "const type x = " (non-reference/pointer) being uwed in any other way than for defining compile-time constants.

It's bit embarrssing, as I read other parts of the C++ standard quite often despite not using it much these days. (I'm into compiler guts, atomics, memory models, code analysis, portability issues, etc.). Yet I had forgotten this part of the language.

So, thanks for sending me down a learning & reminder rabbit-hole and correcting my error :-)

Re: F-strings for C++26 proposal [pdf]

#205

Earlier quoted context omitted.

> [...] another leading character was the only ASCII syntax left for such a thing. Not really? The original PEP [1] for example considered `i"asdf"` as an alternative syntax. Any ASCII Latin letter besides from `b`, `r` and `u` would have been usable. [1] https://peps.python.org/pep-0498/#how-to-denote-f-strings

As an alternative to another leading ascii character, you offer another leading ascii character?

Why is this reply to someone who misunderstood downvoted?

Re: F-strings for C++26 proposal [pdf]

#206

Earlier quoted context omitted.

17 is worth it for std::filesystem alone. It also has optional and variant.

std::filesystem is useless because like so many platform abstractions it doesn't handle the last 1% correctly. IMO the C++ standard should focus platform-agnostic functionality and leave the nitty gritty platform interaction to standalone libraries that can be patched and/or replaced as needed.

Why does that make it useless? paths can be converted to basic_strings for passing to platform-specific functions to handle that 1%.

Re: F-strings for C++26 proposal [pdf]

#207
post #184

Earlier quoted context omitted.

Close. But wrong. Swift doesn't have raw strings and normal strings. Swift has ONE syntax: {# n}"string {# n}\(interpolation)"{#*n} Where n can be zero or more. So let's recap: 1. ONE rule for start/end/escape prefix: A number of # that has to match. 2. ONE rule for escape: \. I do Python full time and I wouldn't consider switching to Swift, but the string situation is horrible compared to Swift.

Yes it does, because normal strings aren't just a special case of raw strings when the number of #s is 0. The presence of #s change the string syntax. Otherwise you could as well say Python has one syntax, with optional f and r prefixes.

No, you can't. Because r/f changes and/or adds escape sequences, AND you can't have double-raw strings for example. In Swift there's 0, 1, 2, 3, 4, etc number of #. It's not raw strings at all! There's no -1 number of #. So for example to do regexes in python you normally use r-strings, to avoid \ escaping in the regex. In Swift you could do the same the opposite way: not by removing \ escaping, but by changing it to \#. And if you want to regex match for \#, you can do ##. And if you want to match for \## you can use ###, etc.

There is always a clean escape where you can write the literal that you want to write. Unlike in Python where there is no escape (amusingly).

Re: F-strings for C++26 proposal [pdf]

#208
post #207

Earlier quoted context omitted.

Yes it does, because normal strings aren't just a special case of raw strings when the number of #s is 0. The presence of #s change the string syntax. Otherwise you could as well say Python has one syntax, with optional f and r prefixes.

No, you can't. Because r/f changes and/or adds escape sequences, AND you can't have double-raw strings for example. In Swift there's 0, 1, 2, 3, 4, etc number of #. It's not raw strings at all! There's no -1 number of #. So for example to do regexes in python you normally use r-strings, to avoid \ escaping in the regex. In Swift you could do the same the opposite way: not by removing \ escaping, but by changing it to…

Ah, I see. That is better.

Re: F-strings for C++26 proposal [pdf]

#209
post #207

Earlier quoted context omitted.

No, you can't. Because r/f changes and/or adds escape sequences, AND you can't have double-raw strings for example. In Swift there's 0, 1, 2, 3, 4, etc number of #. It's not raw strings at all! There's no -1 number of #. So for example to do regexes in python you normally use r-strings, to avoid \ escaping in the regex. In Swift you could do the same the opposite way: not by removing \ escaping, but by changing it to…

Ah, I see. That is better.

Yea, it's a super nice system. It's such a pity that most language designers don't look at other languages before implementing stuff.

I tried to warn the D guys not to make this exact mistake, but they didn't listen :/

Re: F-strings for C++26 proposal [pdf]

#210

So the f-string literal produces a basic_formatted_string, which is basically a reified argument list for std::format, instead of a basic_string. This allows eg. println to be overloaded to operate on basic_formatted_string without allocating an intermediate string std::println("Center is: {}", getCenter()); std::println(f"Center is: {getCenter()}"); // same thing, no basic_string allocated In exchange we have the fo…

C++ desperately needs a solution for wrapper types that should eagerly decay into the wrapped type unless you pass it somewhere that explicitly wants the wrapper type.

"operator auto" has been proposed a few times. But nailing down the semantics has proven elusive.
Post reply on HN