Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Qwertycoatl
Dec 31, 2008

Munkeymon posted:

I thought the 2d graphics thing was a joke :cripes:

Guessing it still is, just baked into stdlib now

I'm pretty sure it got dropped

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
There are several major things giving rise to language lawyers in C++.

First, there's no canonical implementation. A lot of languages don't have multiple meaningful implementations at all: for example, Haskell used to have a second implementation, Hugs, but it's been rotting unused for years, and I would say that the language can longer be meaningfully re-implemented because a large amount of Haskell code in practice is written specifically to GHC's vast extension set. In contrast, C++ evolved as an extension to a language, C, which platform vendors commonly re-implemented more or less from scratch; early on, it seemed reasonable enough to do this to C++, and so there were a lot of implementations from the first days. None of those implementations ever became "canonical", in part because they were too early: they preceded standardization and so are now stuck supporting code that's no longer considered valid. So even in the absence of real differences in "law", there are practical differences in enforcement that leave a lot of room for "legal expertise".

Second, low-level mechanisms always rely on abstract contracts between cooperating systems. That's true at basically every level, from system components talking over the bus, down to user code talking to libraries, all the way down to basic language ABI within a single function. These contracts are not usually possible to enforce at a micro level: to use some calling-convention examples, I can verify that the stack is aligned when functions call me (but it'd be pretty expensive!), but I can't verify that other functions won't somehow scribble on my stack frame or that functions I call will always preserve EBX. Now, those calling-convention rules happen to be something we know how to automatically follow in programming language implementations (but there are still real questions about them sometimes!). However, a lot of rules aren't so simple, and there are basically three choices for how to deal with them:

  • Encapsulate the contract so that the programmer can't actually get it wrong, or it's at least checkable. Usually this means adding overhead, making the performance of your program contingent on the quality of the implementation. For example, a low-level sockets API probably allows you to request that data be read into a specific buffer, but that creates an ownership problem for the buffer, so instead you can wrap it in an interface that always logically returns a new array of data and maybe recycles the buffers it uses behind the scenes.

  • Make the contract the programmer's responsibility by adding the right preconditions/postconditions/expectations/whatever to the higher-level interface. By no means is C++ the only language that makes this choice: I'd actually say that most languages do it in at least some situations. For example, in Java it is the programmer's responsibility to synchronize between threads; if they don't, the code might apparently work, but it's still illegal. When there are real consequences for not following the "law", but there's no authority that can just check your work, you get lots of lawyers: people have questions, and someone has to become enough of an expert to answer them. Java definitely still has language lawyers, and concurrency is one of the things that they usually know about. But C and C++ take this to an extreme by imposing it on really basic language mechanics (like taking the address of a variable) and reserving so much flexibility for the implementation (usually to permit optimization).

  • Come up with some way for the language to enforce the contract automatically. This is great if it's possible, but historically we haven't known how to do it both reliably and generically. Rust, of course, has taught us that a relatively straightforward static ownership system can holistically solve this well enough, but it does require the cooperation of the whole program, and it is limiting in some important ways, and C++ does not have the virtue of being thirty years younger and getting to learn the lessons of its own history.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Qwertycoatl posted:

I'm pretty sure it got dropped

It didn't get dropped, but there's basically zero chance of it ever getting in. One of the implications of pure volunteer work is that someone can decide to keep working on something even after being told it's a total waste of time that'll never go anywhere.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

just gonna say i absolutely love your posting and this one is really good

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

QuarkJets posted:

What does it do?
"auto" assumes the type of a variable depending on context, and like a lot of things in C++, it may make an rear end out of you and me.
In a lot of cases it defaults to an unwanted copy so being explicit with "const auto &" avoids this.

qsvui
Aug 23, 2003
some crazy thing
otoh indiscriminately using references everywhere seems like a recipe for lifetime errors which will make those unwanted copies look desirable

raminasi
Jan 25, 2005

a last drink with no ice

Munkeymon posted:

Who are these people? I want to know so I can avoid them.

It's your users when your app is leaky enough that it has to start delaying requests so it can shovel more and more cycles into the garbage collector. You don't have to go too far out of your way to get this to happen with sufficiently high traffic.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

rjmccall posted:

"legal expertise"

Not sure why but these scare quotes are cracking me up.

(Also, good post!)

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

raminasi posted:

It's your users when your app is leaky enough that it has to start delaying requests so it can shovel more and more cycles into the garbage collector. You don't have to go too far out of your way to get this to happen with sufficiently high traffic.

Your users probably get more annoyed when your site just stops working for a bit whenever you push an update, seeing as you apparently have no load balancing whatsoever.

boo_radley
Dec 30, 2005

Politeness costs nothing

amazing to see a git-resistant programming language.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

boo_radley posted:

amazing to see a git-resistant programming language.

".gitkeep is an esoteric programming language isomorphic to the esolang 'Folders'"

raminasi
Jan 25, 2005

a last drink with no ice

Jabor posted:

Your users probably get more annoyed when your site just stops working for a bit whenever you push an update, seeing as you apparently have no load balancing whatsoever.

You’re right, we don’t! Our users don’t generally get annoyed by updates, seeing as we do them outside of their business hours, but you’re right that our current architecture could use a serious revision, which is why we’re investing in doing that.

But even once we finish, horizontal scaling will just allow us to throw money at our leaky application. Maybe that tradeoff will be worth it, and maybe it won’t, but “load balancing means GC performance is never an issue” is overly simplistic at best.

boo_radley
Dec 30, 2005

Politeness costs nothing

pokeyman posted:

".gitkeep is an esoteric programming language isomorphic to the esolang 'Folders'"

that's the good stuff. thank you, friend.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

boo_radley posted:

amazing to see a git-resistant programming language.

VSS 6.0 would like a word

The version control system that used the filesystem as a database.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

raminasi posted:

But even once we finish, horizontal scaling will just allow us to throw money at our leaky application. Maybe that tradeoff will be worth it, and maybe it won’t, but “load balancing means GC performance is never an issue” is overly simplistic at best.

I mean, you do need to have gc feedback piped back to your load balancer, but other than that it's pretty fine? Like, if you were the only company in the world running Java as your backend infrastructure and had to solve these problems from scratch then you might be in trouble, but you can just leverage all the work that everyone else has put into virtual machines and load balancers and the like to make that situation work.

Falcorum
Oct 21, 2010

QuarkJets posted:

What does it do?

As mentioned, "auto blah = bleh" makes a copy so it can be pretty expensive. The most common issue is using it in "for (auto blah : bleh)" which may mean you could be doing a lot of expensive copies at once.

That doesn't apply if you're just dealing with elementary types like int, bool, etc, since those are cheap to copy, but for anything larger/more complex you'd probably want to use const auto& instead. However to add to the confusion:

code:
int x = 5;

int& y = x;
auto n = y; // auto is deduced as "int"

int* z = &x;
auto m = z; // auto is deduced as "int*"
auto* l = z; // auto is deduced as "int*"

more falafel please
Feb 26, 2005

forums poster

Falcorum posted:

As mentioned, "auto blah = bleh" makes a copy so it can be pretty expensive. The most common issue is using it in "for (auto blah : bleh)" which may mean you could be doing a lot of expensive copies at once.

That doesn't apply if you're just dealing with elementary types like int, bool, etc, since those are cheap to copy, but for anything larger/more complex you'd probably want to use const auto& instead. However to add to the confusion:

code:
int x = 5;

int& y = x;
auto n = y; // auto is deduced as "int"

int* z = &x;
auto m = z; // auto is deduced as "int*"
auto* l = z; // auto is deduced as "int*"

Christ, I somehow didn't realize that auto would deduce to the base type and cause a copy. I've written for (auto member : members) quite a bit.

Ola
Jul 19, 2004

If you simply want to avoid this:
code:
MyLonglyTypedTypeThatIsBoringToTypeOut x = raii();
Like this:

code:
var x = raii();
Then it's possibly something the tooling could figure out if the committee won't.

Xarn
Jun 26, 2015
Of course you need to be careful not to mistake auto and decltype(auto).

Xarn
Jun 26, 2015

Suspicious Dish posted:

just gonna say i absolutely love your posting and this one is really good

:same:

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

rjmccall posted:

Rust, of course, has taught us that a relatively straightforward static ownership system can holistically solve this well enough, but it does require the cooperation of the whole program
Sorry for only cherry-picking this part of your post and possibly hijacking the thread, but this definition should probably be even broader: Because the memory management choices you make in Rust are essentially not abstractable (AFAICT) you end up writing APIs that either expose your choice of memory management (i.e. your API might return an "Arc<Mutex<Foo>>" or some kind of MutexGuard to the caller), or you limit your API to the Hollywood principle of requiring people to pass in callbacks that will receive the object they want to manipulate. Sure, you can also return an "impl Deref<Target = Foo>" but that quickly becomes a lifetime hell that I can't punch my way out of.

So anyway, the cooperation extends not just to your code but to anyone that potentially consumes it as well.

I've enjoyed writing Rust for the last ~6 months or so, but the memory management stuff is so extremely pervasive and not really 'hidden' by the language that it can be a real chore. Now, I'm not talking about the borrow checker itself, but just the sheer amount of generic types that are related to memory management: Arc, Rc, Box, Cow, Pin, Cell, RefCell, Ref, RefMut, the list goes on. I feel Rust sort of dropped the ball by not making this more part of the language itself (instead of in the stdlib as it is now). IIRC the pre-1.0 Rust did a bit more of that, not sure why they ended up not going down that path.

It feels like C++ is perhaps doing too much non-obvious magic in its reference system, but Rust is erring too far to the other side, IMO. It's still quite usable, but it doesn't feel particularly ergonomic.

raminasi
Jan 25, 2005

a last drink with no ice

Jabor posted:

I mean, you do need to have gc feedback piped back to your load balancer, but other than that it's pretty fine? Like, if you were the only company in the world running Java as your backend infrastructure and had to solve these problems from scratch then you might be in trouble, but you can just leverage all the work that everyone else has put into virtual machines and load balancers and the like to make that situation work.

I don’t understand how this solves anything. Sure, knowing relative memory pressure lets my LB route to the least loaded host or trigger a new one to be spun up, but if my application is written like crap and leaking all over the place all I’ve done is given myself a way to pay for the privilege of ignoring my fundamental problem.

Spatial
Nov 15, 2007

auto is great, simple, and i won't hear any criticism of it itt

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



raminasi posted:

It's your users when your app is leaky enough that it has to start delaying requests so it can shovel more and more cycles into the garbage collector. You don't have to go too far out of your way to get this to happen with sufficiently high traffic.

We deploy .Net on Azure where DB connections aren't guaranteed to work in ideal conditions, so "too much GC time" is way the hell down low on my list of things to look into if some user somehow notices that some requests are taking longer sometimes. Way, wayyy more likely a query has become pathological* as data changed underneath it, IME.

* it was always badly written lol

Tei
Feb 19, 2011

Munkeymon posted:

We deploy .Net on Azure where DB connections aren't guaranteed to work in ideal conditions, so "too much GC time" is way the hell down low on my list of things to look into if some user somehow notices that some requests are taking longer sometimes. Way, wayyy more likely a query has become pathological* as data changed underneath it, IME.

How that even works? with a lot of commits and rollbacks? Do you guys use some sort of queue of atomic operations with laser eyes?

ToxicFrog
Apr 26, 2008


raminasi posted:

I don’t understand how this solves anything. Sure, knowing relative memory pressure lets my LB route to the least loaded host or trigger a new one to be spun up, but if my application is written like crap and leaking all over the place all I’ve done is given myself a way to pay for the privilege of ignoring my fundamental problem.

This is true but is also pretty far removed from the original argument of "garbage collection is Bad, actually"

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Tei posted:

How that even works? with a lot of commits and rollbacks? Do you guys use some sort of queue of atomic operations with laser eyes?

https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.sqlserver.sqlazureexecutionstrategy

Absurd Alhazred
Mar 27, 2010

by Athanatos

Falcorum posted:

code:
auto* l = z; // auto is deduced as "int*"

This is the first time I've ever seen this and, let me tell you, I don't like it.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

raminasi posted:

I don’t understand how this solves anything. Sure, knowing relative memory pressure lets my LB route to the least loaded host or trigger a new one to be spun up, but if my application is written like crap and leaking all over the place all I’ve done is given myself a way to pay for the privilege of ignoring my fundamental problem.

I thought you were caring about GC pauses? If your entire application is just a steaming pile of crap then that's more of a you problem than a GC problem.

The fundamental conceit of garbage collection is that allocation becomes free (because you're not loving around slicing bits out of freelists and sticking the leftovers into different ones), and you pay all the costs at deallocation time. With a GC-aware load balancer, you can move all that "deallocation time" out of the serving path, because your machine isn't actually serving requests when it's doing GC.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Sagacity posted:

It feels like C++ is perhaps doing too much non-obvious magic in its reference system, but Rust is erring too far to the other side, IMO. It's still quite usable, but it doesn't feel particularly ergonomic.

Yeah, this is a really important point about it, too.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Falcorum posted:

As mentioned, "auto blah = bleh" makes a copy so it can be pretty expensive. The most common issue is using it in "for (auto blah : bleh)" which may mean you could be doing a lot of expensive copies at once.

That doesn't apply if you're just dealing with elementary types like int, bool, etc, since those are cheap to copy, but for anything larger/more complex you'd probably want to use const auto& instead. However to add to the confusion:

code:
int x = 5;

int& y = x;
auto n = y; // auto is deduced as "int"

int* z = &x;
auto m = z; // auto is deduced as "int*"
auto* l = z; // auto is deduced as "int*"

what does "auto is deduced as int*" mean on the last line? are you saying l is int**?

Ola
Jul 19, 2004

Hammerite posted:

what does "auto is deduced as int*" mean on the last line? are you saying l is int**?

Put it in cpp.sh. It's int*, auto or auto* seems to do the same. Added x=555 after to see what moves.
code:
y: 555
n: 5
z: 0x77627dff1dbc
m: 0x77627dff1dbc
l: 0x77627dff1dbc

Spatial
Nov 15, 2007

It would be pretty dumb if the auto type wasn't a pointer when you assigned a pointer to it. Likewise if the type is const the variable declared with auto will also be const, even if you don't write const.

Of course you can also enforce that a certain variable must be a pointer by manually writing *, or you can add constness to the type by writing const. All very nice and good, especially for templates.

More examples:
code:
int       x = 100;
const int y = 100;

auto        a = x; // int
auto&       b = x; // int&
const auto& c = x; // const int&

auto        d = y; // int
auto&       e = y; // const int&
const auto& f = y; // const int&

auto              g = &y; // const int*;
const auto*       h = &y; // const int*;
const auto* const j = &y; // const int* const;
e: typo

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
auto works essentially the same way as template argument deduction where the auto keyword stands in for an anonymous template parameter. Just like TAD, it will resolve by default to the underlying value type rather than a reference unless you’re explicit about the reference. Sometimes this is good and sometimes it’s bad.

Absurd Alhazred
Mar 27, 2010

by Athanatos

Spatial posted:

It would be pretty dumb if the auto type wasn't a pointer when you assigned a pointer to it. Likewise if the type is const the variable declared with auto will also be const, even if you don't write const.

Of course you can also enforce that a certain variable must be a pointer by manually writing *, or you can add constness to the type by writing const. All very nice and good, especially for templates.

More examples:
code:
int       x = 100;
const int y = 100;

auto        a = x; // int
auto&       b = x; // int&
const auto& c = x; // const int&

auto        d = y; // int
auto&       e = y; // const int&
const auto& f = y; // const int&

auto              g = &y; // const int*;
const auto*       h = &y; // const int*;
const auto* const j = &y; // const int* const;
e: typo

It's stupid, though. Because auto& means "I want a reference to what you have on the right side", which is fine. If it was already a reference, bully for you!. And const auto& means "I want a reference that won't allow me to change the referent", also fine. If it was already a reference, great! I'm adding restriction on changes! if it's already a const reference, great! I'm not changing anything, I just have another reference of the same nature with a different name. But what does auto* mean? "I want a copy of that other thing but also make it a pointer"? What if I'm assigning a non-pointer. Should it dereference it and give you a pointer, the equivalent to the reference auto? No, it causes a compilation error. A terrible idea all around.

Foxfire_
Nov 8, 2010

auto* = "Deduce me a type and it should be a pointer or I screwed something up"

It may not be parallel to the other constructions depending on your point of view, but it's certainly useful for making code more readable and less error prone.

netcat
Apr 29, 2008

Sagacity posted:

It feels like C++ is perhaps doing too much non-obvious magic in its reference system, but Rust is erring too far to the other side, IMO. It's still quite usable, but it doesn't feel particularly ergonomic.

I've had many false starts with trying to learn Rust and I think this is the main thing for me. Reading examples etc I just think it looks ugly and tedious and I get enough of that with C++.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Yeah, that's me. I mean, I've written some fairly complex stuff with it, but I don't enjoy using it.

This sucks because I really want to like it.

Absurd Alhazred
Mar 27, 2010

by Athanatos
Is there a good systems language? Can such a thing be possible?

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Foxfire_ posted:

auto* = "Deduce me a type and it should be a pointer or I screwed something up"

It may not be parallel to the other constructions depending on your point of view, but it's certainly useful for making code more readable and less error prone.

It makes it really annoying to add encapsulation or smart pointers because you have to go clean up a million useless auto* declarations, and it doesn't actually communicate any useful information.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply