| ▲ | cherryteastain 4 hours ago | |||||||
OOP has nothing to do with it. In your C++ example, foo(bar const&); is basically the same as bar.foo();. At the end of the day, whether passing it in as an argument or accessing this via the method call syntax it's just a pointer to a struct. Not to mention, a C++ compiler can, and often does, choose to put even references to member variables in registers and access them that way within the method call. This is a Python specific problem caused by everything being boxed by default and the interpreter does not even know what's in the box until it dereferences it, which is a problem that extends to the "self" object. In contrast in C++ the compiler knows everything there's to know about the type of this which avoids the issue. | ||||||||
| ▲ | adrian17 3 hours ago | parent | next [-] | |||||||
That's not true. I mean: it's true that it has little to do with OOP, but most imperative languages (only exception I know is Rust) have the issue, it's not "Python specific". For example (https://godbolt.org/z/aobz9q7Y9): struct S { const int x; int f() const; }; int S::f() const { int a = x; printf("hello\n"); int b = x; return a-b; } The compiler can't reuse 'x' unless it's able to prove that it definitely couldn't have changed during the `printf()` call - and it's unable to prove it. The member is loaded twice. C++ compilers can usually only prove it for trivial code with completely inlined functions that doesn't mutate any external state, or mutates in a definitely-not-aliasing way (strict aliasing). (and the `const` don't do any difference here at all) In Python the difference is that it can basically never prove it at all. | ||||||||
| ▲ | josefx 3 hours ago | parent | prev | next [-] | |||||||
> This is a Python specific problem caused by everything being boxed I would say it is part python being highly dynamic and part C++ being full of undefined behavior. A c++ compiler will only optimize member access if it can prove that the member isn't overwritten in the same thread. Compatible pointers, opaque method calls, ... the list of reasons why that optimization can fail is near endless, C even added the restrict keyword because just having write access to two pointers of compatible types can force the compiler to reload values constantly. In python anything is a function call to some unknown code and any function could get access to any variable on the stack (manipulating python stack frames is fun). Then there is the fun thing the C++ compiler gets up to with varibles that are modified by different threads, while(!done) turning into while(true) because you didn't tell the compiler that done needs to be threadsafe is always fun. | ||||||||
| ||||||||
| ▲ | 1718627440 3 hours ago | parent | prev [-] | |||||||
> This is a Python specific problem caused by everything being boxed by default and the interpreter does not even know what's in the box until it dereferences it That's not the whole thing, what is going on. Every attribute access is a function call to __getattr__, that can return whatever object it wants. bar.foo (...) is actually bar.__getattr__ ('foo') (bar, ...) This dynamism is what makes Python Python and it allows you to wrap domain state in interface structure. | ||||||||