Ranter
Join devRant
Do all the things like
++ or -- rants, post your own rants, comment on others' rants and build your customized dev avatar
Sign Up
Pipeless API
From the creators of devRant, Pipeless lets you power real-time personalized recommendations and activity feeds using a simple API
Learn More
Comments
-
kiki3572134d@12bitfloat add three more nesting levels to unlock “Git Conflict Markers Are Now Valid Rust” achievement
-
lorentz1539834dC++ accommodates zero-cost better. Rust is a lot easier if you ppermit sacrificing some pperformance in the interest of convenience, for example by returning trait objects when you could technically spell out a ridiculous, 10 lines long concrete type.
-
lorentz1539834dThen again, C++ doesn't really have third party impls so interoppperability always must hhappen through an additional object. I honestly don't know enough about it to determine whether this is a problem.
-
12bitfloat977533d@lorentz I mean... you could also just use a type alias
C++ and Rust are really similar when it comes to generated machine code. Both are suboptiomal for a lot of very specific reasons
In Rust for example a for loop over an inclusive range like 1..=10 can be quite a bit slower since it has to guard against overflow
In C++ you can get bad codegen if you use std::move where you shouldn't because I think that prevents named return value optimization
Fun! -
CoreFusionX358833d@lorentz
C++ does have "third party" implementations, in the sense that the committee only defines the language, it doesn't implement anything. And oh boy shit will happen if you try and mix different g++, msvc++ and clang.
However I think the "competition" results in better implementations.
@12bitfloat
Compilers nowadays are smart enough to prevent those footguns, since it's easy to statically determine when something acts as a rvalue, and will always perform RVO when possible even if you do retarded shit.
std::move is just a lexicographically fancy static_cast<T&&>(), which doesn't really have any implications for auto variables.
The problem, as always, is people wanting to write fancy code and not knowing what they are doing.
Cppreference explicitly states that manually using std::move is, 99% of the time, a mistake, and hence compilers try to protect you from it. -
retoor252033d@CoreFusionX hmm, I used it once quite long ago, don't remember the use case. But not a c++ expert in general. Not a big fan.
-
CoreFusionX358833dAlso, while not really being an example of zero cost abstractions, I love that c++'s *runtime* safety is opt-in.
Shit like iterator/range checking is done by pretty much all major c++ runtimes... When using their debug version.
Not a fan of paying for that shit in release mode. -
CoreFusionX358833d@retoor
The use case is really making sure you get a rvalue reference to whatever you will be requesting to move (really std::move should have been called std::rvalue_ref_cast), because you intend to pass it to (possibly external) other code that might optimize based on copy or move semantics.
However, except very few and far corner cases, good library implementors will either
- explicitly delete copy or move semantics where they don't make sense, resulting in an error if you try to use them.
- just take a const lvalue reference, and let compiler do its magic (99% of the time better than what you intend to do)
- do perfect forwarding if it's just forwarding to other code, delegating to problem to the callee.
Only in the second case, if for whatever reason a const T& would violate const correctness and you'd need to take a T& or T&& explicitly, would a manual std::move make sense.
I have seen it only once in app (as in, not library) code. -
retoor252033d@CoreFusionX I really needed it because it didn't work some other way iirc. It wasn't to be fancy or optimaztion. Really needed.
-
lorentz1539833d@12bitfloat That's really interesting, I assumed that if it's really that expensive they would just check the max value before entering the loop.
-
lorentz1539833dEspecially with iterators being such well-defined distinct values with lifetimes and immutability guarantees, such an optimization doesn't sound very difficult. But maybe I'm oversimplifying.
-
12bitfloat977533d@CoreFusionX The compiler can't always prevent stuff like that since sometimes it's in the semantics of the program
E.g. if you return a string as const, the compiler HAS to copy it, it can't move from it -
12bitfloat977533d@lorentz LLVM apparently sucks at optimizing it and Rust hasn't put any effort in optimizing it at the IR stage
But yeah, it really shouldn't be too difficult -
CoreFusionX358833d@12bitfloat
It has to copy if you create a const string inside the function body and then you return it.
Having const as return type and returning an auto non const object won't invalidate RVO.
Problem is, again, people not understanding the mechanism and just sprinkling const everywhere because they read it in some trend blog, just like sprinkling std::move around. -
12bitfloat977533d@CoreFusionX Sure, but that's what I'm saying. Both Rust's and C++'s zero cost abstractions aren't always zero cost if you don't know how to use them properly
-
CoreFusionX358833d@12bitfloat
Thing is, RVO and move semantics are zero cost abstractions in that sense.
The whole point of a zero cost abstraction is don't pay for it if you ain't using it.
That's why forced bounds checking, and similar runtime stuff is not a zero cost abstraction (you pay for it even if you don't need it).
move semantics, if you use them explicitly, and wrongly, will cost you performance, but they don't otherwise impose a runtime cost if not used, or if you let the compiler do its magic. -
12bitfloat977533d@CoreFusionX Depends on the definition
I know zero cost abstractions as "you couldn't write it any better by hand"
In that sense bounds checking are zero cost abstractions if that's what you wanted, and it's pretty much always what you want. Seriously, branch predictors are really good so bounds checks cost like 1% of performance even in the worst case which is very array heavy code
Do note that Rust doesn't force bounds checks, you are free to use the unsafe methods if you know what you're doing.... probably not a good idea most of the time though -
Lensflare1795432dOk, I‘m triggered 😂
Wtf is that supposed to mean? That zero cost abstractions don’t exist?
Is this a word that is too scary for JS devs? 😄 -
CoreFusionX358832d@12bitfloat
Well, that's not really the definition, at least the way the c++ committee enforces them.
By their own admission, it means that anything that gets added to the language (and everything at this point is abstractions really) must not impose runtime penalties on compatible code from previous versions if you are not *using* said abstractions, without need to configure or change anything in the code. -
Demolishun3562232d@CoreFusionX okay, I need to find out what they said then. I was under the impression it wasn't a cost in memory footprint. So a class with the same variables as a struct would not incur additional memory cost. That is why "this" is just a pointer. I have my c++ book I should look at it I guess.
-
CoreFusionX358832d@Demolishun
"struct" in C++ is just syntactic sugar for "public class" with default public accessibility. There's no functional difference, and of course, no runtime penalty either from
struct A { int i; };
To
public class A {
public:
int i;
};
They are the same and compile to the same.
Zero cost abstractions are what they are.
For example, smart pointers. An abstraction for reference counted pointers, which could be used for say, garbage collection.
In C#, java, or JS, you pay for this always. Every reference is reference counted and thus you pay the price, even if seemingly negligible.
C++ doesn't impose this penalty. You have smart pointers. You don't want to use them? Fine. They will cost you no runtime performance.
Yes, you will be on your own and might have memory leaks, but believe me, when you have to deal with very hot loops with allocations, those negligible penalties, will amount to non negligible penalties. -
CoreFusionX358832dAnd that is why, despite other languages doing a good job so far, everything performance critical will still be done in C/C++.
-
Lensflare1795432d@CoreFusionX well, runtime garbage collection is not the only automatic memory management system.
Swift has automatic reference counting that is performed at compile time. It has zero cost because it‘s literally what you manually would do, but done by the compiler.
I think Rust does the same. -
CoreFusionX358830d@Lensflare
To be fair I don't really know swift, but it's still an example of what I said. It doesn't matter what it is used for. Reference counting has overhead that you have to pay for.
C++ does not impose that on you, at your own risk.
And even then, I'm not at all sold at "compile time reference counting". A compiler has no idea when or why a piece of code with explicit malloc can be called.
RAII is the closest you can get to that, and it still relies on developer discipline to properly implement destructors. -
Lensflare1795430d@CoreFusionX before the time when automatic reference counting was introduced in objective-c, people were thinking that compilers can‘t do that. But they can. It worked well in objective c and it works well in swift.
Don‘t underestimate what the compiler can do.
Before ARC, objective c had manual reference counting as the default memory management model.
So the dev had to write init/alloc, retain and release calls. Those were internally counting the references.
With ARC, the compiler inserted those calls at the correct places automatically.
So, technically it‘s not free when comparing to C/C++, but it‘s free when you were doing manual reference counting in c++ anyway.
You need to help the compiler in very rare cases to resolve reference cycles though.
So it’s not 100% automatic either.
But imo it‘s the best system because it‘s nearly free (or completely free, it depends) and nearly automatic. -
CoreFusionX358830d@Lensflare
Oh, I do not underestimate compilers at all. I say here all the time that the compiler does better than any of us.
My gripe is that what you described isn't really automatic, in the sense that having the compiler insert the calls to init and release is just like GCC will add a call to your constructor/destructor. You don't call them manually. You can then do ARC in them (like std::shared_ptr) or not, and while not free, it's nearly free, but doesn't dismiss you from actually having to properly destruct objects (release resources, etc).
My other gripe about compile time ARC is that the compiler can't possibly know when an object will be constructed or copied if there's no topologically unique code path through the program.
It just takes shit like reacting to a key press to invalidate that. If you create an object on each key press, the compiler can't know how many times the key will get pressed in runtime. -
Lensflare1795430d@CoreFusionX it‘s not just the constructor/destructor calls. It‘s also the retain and release calls which are done when the reference is is copied or goes out of scope.
Depending on the current ref count, the memory is then released.
You don‘t get this by simply using the constructor/destructor because the destructor must not be called if there are still references for this memory.
You seem to still not believe that the compiler can do this, but it can, even when you create memory on a button press.
It doesn‘t matter how dynamic the code is.
And it is as automatic as I claim.
… -
Lensflare1795430d@CoreFusionX
I can‘t tell you how it works internally exactly but I have a good understanding what it does in terms of code insertion at compile time and what this code insertion means.
Essentially the compiler just looks for places where a reference is copied and inserts a retain, which increments the ref count, and in places where the ref goes out of scope it inserts a release, which decreases the ref count.
The destructor is called on ref count 0 and the memory is released. -
CoreFusionX358830d
-
retoor252030dDamn, what a nerds here. Only talking about software and shit. I go to Insta, have a new picture with my bestii ❤️🔥❤️🔥🚀
(Never expected to say this, but happy that emojipedia exists. Strange that we can't insert some emoji with right mouse click or so... Or is that linux related and working on windows or smth?) -
retoor252029d@cprn finally indeed. Good discussion. It's almost as good as cprn. I just realize that your awesome name also could be a reference child porn 😂 Don't worry, according to community policies only politics is forbidden. You can be yourself. You wouldn't be the first one that likes kids that way on this platform 😂 I miss him @chaosesqueteam. He had an amazing botnet promoting little girls. Technically amazing ofc the little girls were ugly.
-
Lensflare1795429d@CoreFusionX yes, but objective c had the equivalent of shared_ptr as the default memory model. You couldn‘t go less managed than that. And making that automatic is free compared to the previous system.
So it depends what the abstraction is based on.
I made it
joke/meme
rust sucks