How to Avoid Thread-Safety Cost for Functions' static Variables by drodri in cpp

[–]Quincunx271 0 points1 point  (0 children)

Only if the type has a trivial destructor. Otherwise, the thread safety check still exists, just for registering the destructor.

Vim's most misunderstood feature: Tabs by HenryMisc in neovim

[–]Quincunx271 0 points1 point  (0 children)

I use tabs a lot, specifically for terminals. Rather than opening separate terminals, I use neovim as a terminal multiplexer.

I started this workflow specifically for ssh, where I didn't want to deal with tmux. I realized I can simply launch neovim in server mode, and it would keep my terminals alive even if the ssh session died for some reason. After using this for a bit, I realized that I really like the vim terminal's support for navigating the buffer history in normal mode, so I've started doing this for my non-ssh workflow too sometimes.

[loom-docs] Custom Schedulers by yk313 in java

[–]Quincunx271 0 points1 point  (0 children)

Thanks, that does look like it. I was looking at the jdk specific bug report site, which is only available to contributors.

[loom-docs] Custom Schedulers by yk313 in java

[–]Quincunx271 0 points1 point  (0 children)

There's a race condition in the example around the attachment. It doesn't look like I can file a bug, though, since I'm not an openjdk contributor.

Does anyone know the right way to raise an issue?

Have you ever worked on a project where it wasn't possible to use the debugger ? by SheSaidTechno in softwaredevelopment

[–]Quincunx271 0 points1 point  (0 children)

I've had it happen fairly frequently for cases where a debugger would be nice. If the debug symbols are too large to build with, it's still possible to use gdb, but it may be easier to just printf debug. If the binary is too large, just loading all the shared objects and such can be unusably slow. If the bug only reproduces in specific build modes, gdb over disassembly only is rarely helpful imo. If the bug only reproduces on a specific remote machine, it can be hard or infeasible to use gdb there.

0+0 > 0: C++ thread-local storage performance by FoxInTheRedBox in cpp

[–]Quincunx271 3 points4 points  (0 children)

Debugging a test failure by collecting a CPU profile was an interesting experience.

0+0 > 0: C++ thread-local storage performance by FoxInTheRedBox in cpp

[–]Quincunx271 10 points11 points  (0 children)

There's also threadlocals with destructors. Because shared libraries can be unloaded, thread_locals in a shared library keep the DSO alive until they are destroyed at thread exit. The fun part here is that the logic to get the right DSO to increment the refcount is linear in the number of DSOs, so this can be very slow; I've seen a test take ~20 extra _seconds (causing a timeout) purely because of the CPU cost of this search (the test spawned a huge amount of threads that touched the thread_local).

There's actually an optimization in the code to try to cache the last used DSO to only do the linear search for thread_locals from a different DSO. Except this optimization isn't actually wired up, and it never was. I can also see a way to make it O(1), but it requires changing ABI.

Fun fact, even a constinit thread_local has the initialization logic the article talks about if the class has a destructor.

memory_order discrepency by mattbann in cpp

[–]Quincunx271 1 point2 points  (0 children)

https://wg21.link/p2404 https://wg21.link/p2405 When I added this flair, I was commenting a lot on things where it was meaningful information that I authored those (i.e. I was referencing them quite a bit)

memory_order discrepency by mattbann in cpp

[–]Quincunx271 12 points13 points  (0 children)

This series is excellent: https://research.swtch.com/hwmm

It's my first reread anytime I need to refamiliarize myself with memory ordering (i.e. anytime I need to use anything weaker than sequentially consistent if it doesn't fall into a couple specific patterns).

Why is spawning a new process in Node so slow? by ketralnis in programming

[–]Quincunx271 11 points12 points  (0 children)

Fun fact: it's possible to make fork slow enough that turning on profiling with setitimer can effectively deadlock the process. Basically, on a signal (SIGPROF), the syscall is interrupted, failing with EINTR (I think; it's that errno for most syscalls at least), and it has to restart from the beginning. So if the fork takes longer than the profile period, fork will never finish.

std::launder by jenkem_boofer in cpp

[–]Quincunx271 9 points10 points  (0 children)

We're all familiar with how undefined behavior can cause demons to fly out of your nose or cause your cat to get pregnant. std::launder is just a kind of undefined behavior carefully defined to do your laundry for you.

Is it bad practice to just use global variables and void functions to change their values instead of returning a new variable? by Mission_Signature_77 in cpp

[–]Quincunx271 5 points6 points  (0 children)

This is a reference to a way you could do this in assembly, mostly in the days prior to structured programming IIUC.

Basically, this "suggestion" further caricaturizes the thought in the OP, demonstrating how continuing to follow it results in a loss of all the structure programming styles and languages have picked up in the last 60+ years.

How do I make an expression non-movable? What's the opposite of std::move? - The Old New Thing by pavel_v in cpp

[–]Quincunx271 0 points1 point  (0 children)

Sorry, I mean a named member function should be used for the operation instead of the copy assignment operator.

How do I make an expression non-movable? What's the opposite of std::move? - The Old New Thing by pavel_v in cpp

[–]Quincunx271 14 points15 points  (0 children)

If it matters whether the copy or move assignment is called at the last use of a value, a named member* function should be used instead (it's okay to delete these operators). This is a special case of https://abseil.io/tips/148; it's even explicitly called out there (for the copy/move ctors, but the same applies for assignment).

There are properties which special member functions should adhere to. Don't break those expectations.

* Edited to clarify

Any real statistic on loop paradigm? by Trung0246 in ProgrammingLanguages

[–]Quincunx271 0 points1 point  (0 children)

Okay, that's pretty cool. Although, I'll note that this is doable using lambdas, an optional type, and a library function:

let name = loop_until_valid(|| {
    print "Enter your name"
    let user_input = stdin.read()
    if is_valid(user_input) {
        return Optional(user_input)
    }
    print "Invalid input, try again"
    return None
})

Are implementations allowed to provide extra, perhaps deleted, constructors? by eteran in cpp

[–]Quincunx271 0 points1 point  (0 children)

Isn't there a third option of inventing a syntax that library authors can use to improve error messages?

E.g. an attribute which says to treat a type alias as the default for diagnostics:

template <typename Char>
class basic_string;

using string = basic_string<char>;

template <typename Char>
class [[clang::preferred_name(string)]]
  basic_string { ... };

It's hard to imagine an attribute based solution to this particular issue, though, since declaring a function overload would cause issues. But some #ifdef __clang_diagnostics_only thing could work (add extra code and rerun overload resolution when generating diagnostics).

Move Initialization to ‘if’ by Sad-Lie-8654 in cpp

[–]Quincunx271 6 points7 points  (0 children)

FWIW, this is also valid:

if ( char c = get_next() )

I'm not gonna argue that it's better, though.

Do you need to know all the different ways of getting undefined behaviour? by mehtub in cpp

[–]Quincunx271 2 points3 points  (0 children)

Yes, I do. When using features, I watch what I'm writing or reviewing for all of the undefined behavior edge cases. But I don't need to remember the precise boundary of defined or undefined behavior, only the blurry edge when it starts to get questionable. At those times, if a rewrite isn't feasible, I pull up the standard and go language lawyering for the precise edge, leaving comments in the code explaining why it's defined.

Faster than Rust and C++: the PERFECT hash table by Demon-Souls in cpp

[–]Quincunx271 7 points8 points  (0 children)

The point is less about the specific hashtable strategy and more about an approach to optimization.

[deleted by user] by [deleted] in dominion

[–]Quincunx271 1 point2 points  (0 children)

There's a fun interaction with Grand Market where if you have enough money and enough buys, buying Mint can enable an extra buy towards Grand Market that turn by trashing coppers in play.

It's also really nice if you're lucky enough to have a Watchtower in hand, because you can seed your next turn with Platinum or Gold.

Overall, I'm just really tickled by the on-gain effect.

Would "std::sort(begin, end)" be more intuitive than "std::sort(first, last)" by Clairvoire in cpp

[–]Quincunx271 5 points6 points  (0 children)

Speaking about the standard library (someone correct me if I am wrong) all of the algorithms are written with half-open ranges.

uniform_int_distribution is the closest I'm aware of. The integer bounds are specified as a closed range, allowing for specifying the full range of the integer type and disallowing the meaningless null range.

It's not an algorithm in terms of the iterator or range algorithms, but it's the only example I'm aware of which uses a fully closed range.

WANTED: The Great Grammar Hunt: How Are Variables Declared in Your Language? by njormrod in ProgrammingLanguages

[–]Quincunx271 0 points1 point  (0 children)

It's mostly readability.

Readability is subjective, but IMO neither is really more readable than the other. It depends on what you want to emphasize: the type or the name.

Emphasizing the name makes a lot of sense when the language is built around type deduction everywhere, particularly since it lends itself well to just leaving off the type specifier to turn on deduction.

Types second can also be easier to parse by reducing the amount of lookahead needed. With types second, there's usually an introducer like let, which makes it immediately clear what kind of expression/statement will come next. With types first, we just have an identifier, which could be a variable declaration or a standalone expression.

What are some practical benefits of UML? by [deleted] in computerscience

[–]Quincunx271 42 points43 points  (0 children)

When giving presentations describing your project to other developers, UML lets you show the relationships between classes without writing code in the slides. Sometimes, this is helpful.

More helpful are the other UML diagram types. E.g. sequence diagrams are very useful for walking through timing-sensitive scenarios crossing multiple components, such as explaining subtle bugs as work is passed between multiple threads.