News for hackers. Stuff that matters.
Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @03:43AM (#24648437)
D and Rust are the only languages that have since adopted the destructor.
Re:C++ the Good Parts (2014) by bestouff on Thursday October 01, 2020 @04:14AM (#24648634)
I tend to see Rust as "only the good parts of modern C++, and then some".
Re:C++ the Good Parts (2014) by aldanor on Thursday October 01, 2020 @05:15AM (#24648984)
And also: "Minus all the OOP, and then some."
Re:C++ the Good Parts (2014) by saagarjha on Thursday October 01, 2020 @05:42AM (#24649120)
Modern C++ generally doesn’t use OOP all that much anyways. However, <algorithm> and <type_traits> in Rust’s standard library would be quite nice to have.
Re:C++ the Good Parts (2014) by est31 on Thursday October 01, 2020 @06:21AM (#24649329)
What would be a use case for using type_traits? It feels to me that most cases for it would be frowned upon in Rust, but that's just my gut feeling, not knowing what they are useful for in C++-
Re:C++ the Good Parts (2014) by secondcoming on Thursday October 01, 2020 @07:20AM (#24649626)
They provide the compiler metadata about a type. For example if you have a std::vector<int>, there is a value_type trait for this that deduces to int, i.e. 'this vector holds ints'.
Re:C++ the Good Parts (2014) by est31 on Thursday October 01, 2020 @07:37AM (#24649747)
Hmmm I see. Reading up on it it seems to enable generic code deduce info or assume info about stuff (as in assert). Rust uses proper traits for that instead, basically having lifted traits to a first-class language feature. But there is only a barebones set of traits available in the standard library, mostly the ones needed for language or std features. Any traits only needed for generic libraries are left to crates to implement.
Re:C++ the Good Parts (2014) by aldanor on Thursday October 01, 2020 @08:19AM (#24650027)
The difference here is that, C++ templates are closer to just "string replacement", as they're not validated (basic syntax aside) until you instantiate them. As such, in C++, your generic type T can be whatever the user decides to stick in there (you can't prevent them doing that), and so you typically have a chance of disabling/enabling certain bits of code by checking various type traits and using hacks like sfinae etc (e.g., "if T is an enum - please use this version of this method; otherwise - substitute this version of the same method", this would be quite typical and idiomatic in C++).

In Rust, generic code is fully validated as it should be, with all trait bounds being matched where need be. So you would rarely end up with needing to figure (at compile time) whether generic type T is an enum or not - because it wouldn't allow you to do anything extra with it out of the box. In Rust, an idiomatic way of adding different behaviours based on the kind of the generic type would be using traits still - e.g., you can have multiple impl blocks on your generic type, each one having different trait bounds on the generic parameter, like - if T: Copy, then implement these extra methods; standard library has tons of examples like this. The only exception that comes to mind is proc macros - when you deal with Rust code in AST form and generate new code at pre-compile-time phase, but that's a completely different story and not really related.

Re:C++ the Good Parts (2014) by est31 on Thursday October 01, 2020 @01:25PM (#24653671)
Oh yeah, C++ templates work more on the token level than Rust generics. Didn't know that type_traits was meant for that.

Indeed Rust proc macros, or Rust macros in general, are a better analog to C++ templates than Rust generics. They aren't quite the same, as during evaluation time C++ can do a bit more, and apparently type_traits is an example of what C++ can do statically. Rust's model is different, it wants macro expansion to be done by the time it starts even resolving any non-macro paths, let alone type checking or anything.

That being said, you'll be able to emulate something like that once specialization lands (hopefully also included by min_specialization).

Re:C++ the Good Parts (2014) by TinkersW on Thursday October 01, 2020 @08:52AM (#24650281)
C++ does have something along the lines of Rust traits now, it is called concepts and was added in C++ 20.

Mind you it probably has very little real world usage right now..

Concepts aren't as powerful as Rust traits in that they are static dispatch only, while Rust supports both static & dynamic-- but they should make for cleaner code than <type_traits>

Re:C++ the Good Parts (2014) by steveklabnik on Thursday October 01, 2020 @09:42AM (#24650706)
Another large difference (in my understanding) is that you're not actually forced to use concepts; they help if you do use them, but they're not required. Rust pretty much requires that you use a trait for these cases.
Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @06:01AM (#24649225)
Other than the classes used to implement all those STL concepts.
Re:C++ the Good Parts (2014) by johannes1234321 on Thursday October 01, 2020 @07:08AM (#24649566)
Types are being used to create those things. But it's not OOP as many people understand it. (Inheritance, everything via method calls etc.)
Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @07:10AM (#24649580)
People should spend more time learning what OOP actually is all about, hint it isn't just MFC and Qt.
Re:C++ the Good Parts (2014) by tom_mellior on Thursday October 01, 2020 @08:46AM (#24650229)
This is such a lazy form of "argument". If you have knowledge, share it, or at least share concrete references to concrete resources where one might learn what you think should be learned. If you put it in this nebulous way, people might look up the meaning of OOP in some source you don't approve of, which wouldn't help communicate what you think should be communicated.
Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @10:57AM (#24651580)
Start here,

"Object-oriented programming: Some history, and challenges for the next fifty years"

https://www.sciencedirect.com/science/article/pii/S089054011...

Than read on BETA design for example,

https://beta.cs.au.dk/

Follow up with "The Art of the Metaobject Protocol",

https://mitpress.mit.edu/books/art-metaobject-protocol

and "Xerox LOOPS"

http://www.softwarepreservation.org/projects/LISP/interlisp_...

Then "Component Software: Beyond Object-Oriented Programming" (the 1st edition with Component Pascal)

https://www.amazon.com/Component-Software-Beyond-Object-Orie...

"Applying Traits to the Smalltalk Collection Classes"

https://rmod.inria.fr/archives/papers/Blac03a-OOSPLA03-Trait...

"Self – The Power of Simplicity"

http://media.cichon.com/talks/Introduction_Self_Language_OOP...

https://blog.rfox.eu/en/Programming/Series_about_Self/index....

How about this for starters?

Re:C++ the Good Parts (2014) by discreteevent on Thursday October 01, 2020 @03:41PM (#24655355)
Re:C++ the Good Parts (2014) by tom_mellior on Thursday October 01, 2020 @03:48PM (#24655435)
This is pretty good for starters! It makes it clear that you're not interested in a real discussion. Requiring that people read The Art of the Metaobject Protocol before you'll engage with their arguments on whether C++ programmers write OOP code is clearly just evasion on your part.

This isn't knocking the book, I've read it and agree that it's edifying. This list is a good resource on OOP in general. It's just not helpful in the context of this thread.

Re:C++ the Good Parts (2014) by pjmlp on Friday October 02, 2020 @01:50AM (#24659333)
> If you have knowledge, share it, or at least share concrete references to concrete resources where one might learn what you think should be learned.

Your own words, documentation and knowledge was shared, apparently you are the one not interested.

Re:C++ the Good Parts (2014) by tom_mellior on Friday October 02, 2020 @06:58AM (#24661285)
You missed the "concrete" part. Which of these sources, concretely, should one read to evaluate the claim that "Modern C++ generally doesn’t use OOP all that much anyways.", which is what you seemed to criticise in this subthread?

Again: Does one really, concretely, have to read The Art of the Metaobject Protocol, a book about Lisp, to evaluate this claim about C++? Having read the book, I would say no. Which is why I say that you are evading a real discussion.

(And for that matter, it would be interesting if you fleshed out your counter-claim -- "Other than the classes used to implement all those STL concepts." -- in a bit more detail. Are you saying that all uses of C++ classes are OOP? Or that only certain uses are, but that the way classes are used to implement the STL fall into this category? Will I find the answer to these concrete questions in The Art of the Metaobject Protocol?)

Re:C++ the Good Parts (2014) by pjmlp on Friday October 02, 2020 @10:48AM (#24663169)
> Are you saying that all uses of C++ classes are OOP?

Definitely, any use of class constructs with data members and member functions is OOP.

Any use of data members inside class constructs represents aggregation and if any member function on a data member happens to be called, as means to help a member function to do their work, that is delegation.

Any template implemented as class that uses its type parameters to decide at compile time what gets called, makes use of dynamic dispatch decided at compile time.

If you prefer we can pick any random STL type and dissect all their uses of OOP features, lets start with something like std::set?

Re:C++ the Good Parts (2014) by ncmncm on Friday October 02, 2020 @05:13PM (#24667080)
> Definitely, any use of class constructs with data members and member functions is OOP.

Definitely not.

OOP requires, also, runtime binding and polymorphism. You can get the polymorphism by inheritance, delegation, or what-have-you. You can get runtime binding with a vtable or a name lookup.

The usual term for just-encapsulation is "object-based". The STL is definitively not object-oriented, according to its author, Stepanov, who has said that giving the STL classes member functions was a mistake.

OOP is a niche technique. It has uses, sometimes. More often, a function pointer suffices.

Re:C++ the Good Parts (2014) by pjmlp on Saturday October 03, 2020 @06:36AM (#24671063)
No it doesn't, hence why I mentioned that one should learn what OOP is all about.

Object based languages are part of the OOP universe from CS point of view, plenty of literature, that apparently is too much to ask to read about, some of which I have provided above.

So here we go about std::set and it being OOP.

1 - class set, a means for encapsulation, with most of its members de

2 - Uses delegation for memory allocation via the allocator_type

3 - Uses delegation for key lookups and value comparisasion

4 - Implements the concepts Container, AllocatorAwareContainer, AssociativeContainer, ReversibleContainer alongside their respective concept dependencies, which in OOP speak are protocols/traits/categories;

5 - The actual types used for comparisaion and allocation are instances of the respective protocols, with dispatch being decided at compilation time of std::set uses, given the respective implementations as type parameters, in a way similar to multi-method-dispatch.

As bonus here is a simplified UML diagram. It isn't more detailed, because my patience to draw ASCII art is limited.

    -------------------------------------------------------------------------------------------  
    |std|                                                                                     | 
    -----                                                                                     |
    |                                                           __________________            |
    |                                                           | <<protocol>>    |           |  
    |                                                           |   Container     |           | 
    |                                                           |-----------------|           |
    |                                                           |-----------------|           |
    |                                                           |-----------------|           | 
    |                                                           | constructor     |           |
    |                                                           | copy-constructor|           |
    |                                                           |   destructor    |           |
    |                                                           |     begin()     |           |
    |                                                           |      end()      |           |
    |                                                           |     cbegin()    |           |
    |                                                           |     cend()      |           |
    |                                                           |     swap()      |           |
    |                                                           |     size()      |           |
    |                                                           |    max_size()   |           |
    |                                                           |      empty()    |           |
    |                                                           -------------------           |
    |                                                                   /\                    |
    |                                                                   --                    |
    |                                                                    | extends            |
    |                                                                    |                    |
    |          ______________        _______________________    _______________________       |
    |         | <<protocol>>|        |     <<protocol>>     |  |     <<protocol>>     |       |
    |         |  Allocator  |        | ReversibleContainer  |  | AssociativeContainer |       |
    |         |-------------|        |----------------------|  |----------------------|       |
    |         |-------------|        |----------------------|  |----------------------|       |
    |         | constructor |        |       rbegin()       |  |     key_comp()       |       | 
    |         |  destructor |        |       rend()         |  |     value_comp()     |       |
    |         |  allocate   |        |      crbegin()       |  |----------------------|       |
    |         |  deallocate |        |      crend()         |             /\                  |
    |         |  max_size   |        |-----------------------             --                  |
    |         |  construct  |                  /\                          |                  |
    |         |  destroy    |                  --              implements  |                  |
    |         ---------------                   |                          |                  |
    |               /\                          |                          |                  |
    |               --                          |  implements             /                   |
    |                |                          \                        /                    |
    |                | implements                \                     /                      |
    |                |                            \                   /                       |
    |                |                             \------------------                        |
    |                |                                        |                               |
    |                |                                        |                               |
    |                |                                     ------------------                 | 
    |         ----------------                            | <<protocol>>     |                |
    |         |  allocator<T> |          uses             |     set          |                |
    |         |---------------|<------------------------/\|------------------|                | 
    |         |---------------|                         \/|  constructor     |                | 
    |                                                     |  destructor      |                | 
    |                                                     |  begin()         |                |
    |                                                     |  end()           |                |
    |                                                     |  cbegin()        |                |
    |                                                     |  cend()          |                |
    |                                                     |  rbegin()        |                | 
    |                                                     |  rend()          |                |
    |                                                     |  crbegin()       |                |
    |                                                     |  crend()         |                |
    |                                                     |  operator=       |                | 
    |                                                     |  get_allocator() |                |
    |                                                     |  empty()         |                |
    |                                                     |  size()          |                |
    |                                                     |  max_size()      |                |
    |                                                     |  clear()         |                |
    |                                                     |  insert()        |                |
    |                                                     |  emplace()       |                | 
    |                                                     |  emplace_hint()  |                |
    |                                                     |  erase()         |                |
    |                                                     |  swap()          |                |
    |                                                     |  extract()       |                |
    |                                                     |  merge()         |                |
    |                                                     |  count()         |                |
    |                                                     |  find()          |                |
    |                                                     |  contains()      |                |
    |                                                     |  equal_range()   |                |
    |                                                     |  lower_bound()   |                |
    |                                                     |  upper_bound()   |                |
    |                                                     |  key_comp()      |                |
    |                                                     |  value_comp()    |                |
    |                                                      ------------------                 |
    |-----------------------------------------------------------------------------------------|
Re:C++ the Good Parts (2014) by ncmncm on Saturday October 03, 2020 @07:37PM (#24675491)
It has and does all of these things, but it does not have runtime binding, therefore by definition is not object-oriented.

Concretely, you cannot take a Container pointer and point it at a std::set. You can take a T, and bind T to std::set at compile time; but that is Generic Programming: analogous, in some ways, but not the same.

In the '90s it was fightin' words to say "X is not Object Oriented", because Object-Oriented was taken as a high-status way to say Good, and "Not Object-Oriented" translated implicitly to "Not Good".

But in our brave new world, object-oriented is but one design discipline, and we have others, and enough language primitives to construct our own disciplines by mix-and-match as problems dictate.

And, I have myself simplified code that had used a virtual function to use, instead, a function pointer, and it was (still) Good. Better, even.

Re:C++ the Good Parts (2014) by pjmlp on Sunday October 04, 2020 @05:30AM (#24677543)
> It has and does all of these things, but it does not have runtime binding, therefore by definition is not object-oriented.

What renowned SIGPLAN or IEEE paper states that runtime binding is required for 100% of all OOP programming languages ever created and polymorphic dispatch at compile time doesn't count?

Re:C++ the Good Parts (2014) by ncmncm on Monday October 05, 2020 @12:46AM (#24684630)
Not interested in classifying programming languages, or in SIGPLAN- or IEEE-sanctioned opinions.

Changing the definition would be moving the goalposts. A new definition deserves a new word.

Re:C++ the Good Parts (2014) by gpderetta on Thursday October 01, 2020 @07:18AM (#24649618)
if STL is OO then everything is OO.
Re:C++ the Good Parts (2014) by jcelerier on Thursday October 01, 2020 @11:04AM (#24651712)
> if STL is OO then everything is OO.

I mean... in the sense in which most people use "OO language" (which is, "a language with constructs which associates a data specification with procedures"), yes. Only hardcore pure-functional algorithms written in Haskell / ML without typeclasses, or things like Prolog, Esterel (though thinking about it), and similar research languages aren't.

Once upon a time programming looked like this. https://github.com/chrislgarry/Apollo-11/blob/master/Luminar...

Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @07:43AM (#24649790)
Then remove the classes, static inheritance via template arguments, method dispatch via type parameters (very CLOS like), class member functions, iostreams, .....

Plenty of SIGPLAN papers to one educate themselves about what OOP is all about.

OOP is not MFC alone, apparently those that learn languages on the trenches without referring to them, never get to appreciate the wealth of information we have available.

Not surprising, given how many misunderstand "whatever my compiler does" for what ISO actually says.

Re:C++ the Good Parts (2014) by gpderetta on Thursday October 01, 2020 @08:03AM (#24649921)
OO is a very nebulously defined term and if you ask two people you'll get three different definitions. But I would say that most people will agree that at the very least late binding is a fundamental component.
Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @08:22AM (#24650054)
Hence why having a proper CS education is an very important pillar for any good engineering degree.

Back to STL, it makes heavy use at compile time method dispatch via template metaprogramming and lambdas (which are implemented as classes actually by the compiler.

Re:C++ the Good Parts (2014) by gpderetta on Thursday October 01, 2020 @11:56AM (#24652386)
Stepanov has forgotten more about CS than I'll ever learn in an hundreds lifetimes and he is pretty adamant that STL is no OO [1].

I know this is an argumentum ab auctoritate, but you didn't really provide an argument either :)

[1] http://www.stlport.org/resources/StepanovUSA.html

Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @12:23PM (#24652795)
He also thinks that Artificial Intelligence is an hoax, so take your pick.
Re:C++ the Good Parts (2014) by gpderetta on Thursday October 01, 2020 @12:30PM (#24652904)
FWIW, he is referring to the AI Winter, the interview was written well before the current AI renaissance.
Re:C++ the Good Parts (2014) by msla on Thursday October 01, 2020 @03:43PM (#24655375)
Did he say that about GOFAI or Deep Learning?
Re:C++ the Good Parts (2014) by Jtsummers on Thursday October 01, 2020 @03:46PM (#24655412)
In the context of the interview, it would've been GOFAI. Deep learning hadn't taken off yet.
Re:C++ the Good Parts (2014) by MiroF on Thursday October 01, 2020 @04:05PM (#24655602)
Well then it was a hoax?
Re:C++ the Good Parts (2014) by Jtsummers on Thursday October 01, 2020 @04:15PM (#24655710)
For context, the relevant answer:

> Yes. STL is not object oriented. I think that object orientedness is almost as much of a hoax as Artificial Intelligence. I have yet to see an interesting piece of code that comes from these OO people. In a sense, I am unfair to AI: I learned a lot of stuff from the MIT AI Lab crowd, they have done some really fundamental work: Bill Gosper's Hakmem is one of the best things for a programmer to read. AI might not have had a serious foundation, but it produced Gosper and Stallman (Emacs), Moses (Macsyma) and Sussman (Scheme, together with Guy Steele). I find OOP technically unsound. It attempts to decompose the world in terms of interfaces that vary on a single type. To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types. I find OOP philosophically unsound. It claims that everything is an object. Even if it is true it is not very interesting - saying that everything is an object is saying nothing at all. I find OOP methodologically wrong. It starts with classes. It is as if mathematicians would start with axioms. You do not start with axioms - you start with proofs. Only when you have found a bunch of related proofs, can you come up with axioms. You end with axioms. The same thing is true in programming: you have to start with interesting algorithms. Only when you understand them well, can you come up with an interface that will let them work.

I have seen this a few times and have felt that "hoax" is the wrong word each time. Later he talks about OOP being "philosophically unsound", which adds some clarity to the statement. It's not that OOP or AI are made up (true hoaxes), it's that they will not accomplish (in his view) what they set out to do because they are founded on unsound bases.

Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @12:13PM (#24652645)
Aldanor has an important point here, in the "and the some".

Rust is deliberately a weaker language for expressing library semantics. You can write libraries in C++ that cannot be written in Rust, that encapsulate semantics that cannot be captured in Rust. C++ library writers do, routinely. The C++ Standard Library has many components that could not be coded in Rust, that make the language more powerful for all users.

This makes Rust easier to learn, but it limits the libraries you can use, having learned it, and limits the libraries you can write.

This is a difficult tradeoff for any language design. Haskell is more powerful, too, and also harder to learn and to use well. (At the same time, its lack of destructors also limits it in ways that Rust and C++ do not suffer.)

The OOP -- inheritance, and virtual functions -- is a niche feature that is sometimes useful, but can often be emulated well enough with function pointers.

Re:C++ the Good Parts (2014) by Ar-Curunir on Thursday October 01, 2020 @01:08PM (#24653450)
What libraries do you have in mind?
Re:C++ the Good Parts (2014) by ncmncm on Friday October 02, 2020 @08:35PM (#24668450)
Re:C++ the Good Parts (2014) by int_19h on Thursday October 01, 2020 @06:21PM (#24656788)
Rust has virtual method dispatch. What else do you need to call it OO?

If it's implementation inheritance, then that was never a requirement for OO, seeing how prototype-based OO has been around for a very long time.

Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @06:00AM (#24649216)
Traits are OOP, check out on Objective-C and CLOS/Flavors protocols, Smalltalk categories, alongside a couple of SIGPLAN papers on component programming.
Re:C++ the Good Parts (2014) by vbarrielle on Thursday October 01, 2020 @07:47AM (#24649819)
Haskell typeclasses are quite close to Rust traits, does Haskell count as OOP then?
Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @07:55AM (#24649872)
Yes, Haskell has all the necessary features to implement some forms of OOP.

There are plenty of OOP flavours, just like there are plenty of FP flavours.

If one considers 100% Haskell's features as must have for a language to be considered FP, then OCaml and Standard ML are going to have a hard time to be considered FP.

Re:C++ the Good Parts (2014) by int_19h on Thursday October 01, 2020 @06:24PM (#24656808)
IIRC, Haskell doesn't have the notion of object identity. It wouldn't make sense in an immutable language, anyway, because identity only matters if object state can change - otherwise any two objects with identical state are substitutable. But anyway, I would argue that this is the crucial difference that sets apart "objects" and "values with syntactic sugar for function calls".
Re:C++ the Good Parts (2014) by ChrisMarshallNY on Thursday October 01, 2020 @04:50AM (#24648848)
Swift has it. It’s called `dealloc()`. Since the language is fairly tight, and doesn’t have real stack-unwinding exceptions, there’s not a whole lot of utility in it.

Apple seems to think that anything that you put in dealloc should end up in the system (like unsubscribing from notifications).

C++ is a dangerous, powerhouse systems language. I think it really needs things like destructors, and I’m glad to see its continuing development.

Re:C++ the Good Parts (2014) by saagarjha on Thursday October 01, 2020 @05:40AM (#24649102)
deinit, and if they’re from NotificationCenter you haven’t had to do that for a while and for KVO if you’re using the block syntax (you should!) you basically have an RAII “observation” that you control the lifetime of (often you assign it as a property of the object being observed, so it automatically gets cleaned up when the object goes out of scope).
Re:C++ the Good Parts (2014) by ChrisMarshallNY on Thursday October 01, 2020 @06:15AM (#24649286)
You're right (shows how often I use it, and I write Swift every day).

Apple is amping up KVO, in general, which I like.

Re:C++ the Good Parts (2014) by pjmlp on Thursday October 01, 2020 @04:16AM (#24648645)
Alongside Object Pascal back in the old MS-DOS and Apple days, Ada 95, Swift, Python, and a couple of others that I won't now bother to search for on my papers archive.
Re:C++ the Good Parts (2014) by tonyarkles on Thursday October 01, 2020 @07:29AM (#24649689)
Here’s the crucial difference between Python destructors and C++ destructors: C++ destructors run as soon as the object goes out of scope, deterministically. Python destructors run down the road, during the next GC cycle.

As an example of why this matters, I’ve got a class called TimeCapture in a project. If I want to instrument how long a block takes (full function, inside of an if, etc) I can add `TimeCapture tc(“my-metric-name”);` to the block and know that the destructor on that object will be called precisely at the end of that block (capturing the end time of the block)

I don’t know the rules for Swift or Ada or OP, but I’m guessing they’ll vary.

Re:C++ the Good Parts (2014) by masklinn on Thursday October 01, 2020 @07:54AM (#24649867)
> Here’s the crucial difference between Python destructors and C++ destructors: C++ destructors run as soon as the object goes out of scope, deterministically. Python destructors run down the road, during the next GC cycle.

Not true. They run when the object is deallocated. In CPython if the object is not involved in or referenced from a cycle, that’s as soon as it goes out of scope: the ref count goes to 0 and the object gets deallocated.

This is trivial to check: create a structure with a noisy __del__ and create an instance from a function, call the function, del will run. The GC has no reason to run at this point, there’s no allocation requiring any sort of reclamation, but if you don’t trust that you can just `gc.disable()` and observe… the exact same behaviour.

Re:C++ the Good Parts (2014) by Nullabillity on Thursday October 01, 2020 @08:52AM (#24650279)
> Not true. They run when the object is deallocated. In CPython if the object is not involved in or referenced from a cycle, that’s as soon as it goes out of scope: the ref count goes to 0 and the object gets deallocated.

That's a CPython implementation detail, not a guarantee that you can rely on.

For example, both PyPy[0] and Jython use tracing GCs where this is not true.

[0]: https://doc.pypy.org/en/latest/cpython_differences.html

Re:C++ the Good Parts (2014) by masklinn on Thursday October 01, 2020 @05:10PM (#24656171)
> That's a CPython implementation detail

Which would be why I specifically wrote « in CPython ».

And it still makes the original assertion completely incorrect. Python destructors do not run « down the road, during the next GC cycle ». They may, in certain cases or implementations.

Re:C++ the Good Parts (2014) by Nullabillity on Thursday October 01, 2020 @05:45PM (#24656460)
Once again,

> implementation detail

There is no guarantee that even CPython will keep the current behaviour. Ultimately, the promise you're given is that __del__ might be invoked by the system some point between "the object has no live references" and "never".

The original assertion gives a much closer intuition than your description of the current behaviour.

Re:C++ the Good Parts (2014) by bluGill on Thursday October 01, 2020 @09:31AM (#24650591)
Not all the world is CPython though. There are several other implemntions and the python docs make it quite clear that the cpython developers do not consider the a destructor running when an object goes out of scope anything more than an implementation detail, and they reserve the right to change it without warning should they discover a reason to. (They haven't changed it in 20 or 30 years, but that doesn't mean they won't tomorrow)
Re:C++ the Good Parts (2014) by masklinn on Thursday October 01, 2020 @05:12PM (#24656193)
> Not all the world is CPython though

The original commenter made a specific assertion. I demonstrated that their assertion is not true.

Re:C++ the Good Parts (2014) by bluGill on Thursday October 01, 2020 @08:53PM (#24657726)
But you didn't demonstrate anything because your assertion is false. In C++ destructor are guaranteed deterministic as to when they run. In Cpython they are not guaranteed, by chance it happens that way, but it should be considered chance.

It seems to me that there must be some other language that would have the c++ guarantee, but I don't know of it. (it isn't hard to implement, and c++ is well known enough that other languages designers can consider the pros and cons and surely someone else has decided it is worth it)

Re:C++ the Good Parts (2014) by Nullabillity on Friday October 02, 2020 @06:49AM (#24661219)
> It seems to me that there must be some other language that would have the c++ guarantee, but I don't know of it.

Rust's Drop[0] has basically the same guarantees as C++: the destructor will run right before the memory is freed (although it is possible in both cases to also leak both). Combine with Pin[1] if you need the exact memory location to be stable as well.

> it isn't hard to implement

Sadly, it's basically incompatible with tracing garbage collectors, since they make it completely unpredictable when the destructor will run.

So if you ever want to allow yourself to switch to tracing GC then you'll either have to disallow it completely, or bury it in a hidden corner of the docs with a load of caveats (like Python or Java). And in the latter case you'll still have people like the GP stumble upon it, say "oh, this looks neat", and set up a really painful trap for their future selves.

[0]: https://doc.rust-lang.org/stable/std/ops/trait.Drop.html

[1]: https://doc.rust-lang.org/stable/std/pin/index.html#drop-gua...

Re:C++ the Good Parts (2014) by kubav on Thursday October 01, 2020 @07:56AM (#24649877)
To implement scope guard you can use with statement and implement __enter__, __exit__ methods. It is not real RAII as object is not destroyed on exit but it is still quite useful.

http://effbot.org/zone/python-with-statement.htm

Re:C++ the Good Parts (2014) by achn on Thursday October 01, 2020 @07:49AM (#24649834)
How do multiple destructors get sequenced? Last in, first out? Thanks
Re:C++ the Good Parts (2014) by richardwhiuk on Thursday October 01, 2020 @03:46AM (#24648451)
Objective C also has destructors.
Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @12:24PM (#24652808)
Not the same, and overwhelmingly less useful.
Re:C++ the Good Parts (2014) by setpatchaddress on Thursday October 01, 2020 @01:23PM (#24653658)
dealloc is pretty much the same thing, and it can be used in the same way. It's not "useful" in the C++ RAII sense because:

- the standard library design -- every object is refcounted and any code that references the object can add it to an autorelease pool, so you can't safely predict when dealloc will be invoked

- Objective C doesn't support stack-based objects

Re:C++ the Good Parts (2014) by richardwhiuk on Thursday October 01, 2020 @03:23PM (#24655160)
You can do stuff:

  @autoreleasepool {
    RaiObj* obj = [RaiObj new];
    [obj autorelease];

    //... stuff
  }
will de-allocate at the end of the block if nothing else hold onto it, but it's obviously less neat.
Re:C++ the Good Parts (2014) by sacado2 on Thursday October 01, 2020 @04:24AM (#24648686)
Don't forget good old Ada.
Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @12:25PM (#24652829)
Ada does not have destructors or anything analogous.
Re:C++ the Good Parts (2014) by Jtsummers on Thursday October 01, 2020 @01:00PM (#24653352)
https://www.adaic.org/resources/add_content/docs/95style/htm...

"Finalize" on objects of type "Ada.Finalization.Controlled".

Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @02:44PM (#24654645)
Nope. Key words there are "should call".
Re:C++ the Good Parts (2014) by Jtsummers on Thursday October 01, 2020 @02:49PM (#24654708)
> Nope. Key words there are "should call".

I mean, yes, those words are in there, but I'm responding to your words:

> Ada does not have destructors or anything analogous.

Which are factually wrong. Finalize is called automatically (per the link). And they are exactly what you say Ada lacks, analogues of destructors.

Your complaint, now, is that Finalize and Initialize don't automatically call the same functions in the parent. That's a separate issue, and doesn't demonstrate that Ada doesn't have this thing (a variant of destructors) which it very clearly has.

Re:C++ the Good Parts (2014) by ncmncm on Friday October 02, 2020 @06:54PM (#24667860)
It fails to implement the aspect of destructors that makes them an architecturally important feature.
Re:C++ the Good Parts (2014) by johannes1234321 on Thursday October 01, 2020 @07:05AM (#24649546)
Also PHP.
Re:C++ the Good Parts (2014) by ncmncm on Thursday October 01, 2020 @02:45PM (#24654660)
Sorry, no.
Re:C++ the Good Parts (2014) by johannes1234321 on Thursday October 01, 2020 @09:03PM (#24657766)
"Sorry No" as in "PHP is a stupid language, stay away!" Which is a point I won't argue.

Or in the "PHP has no destructors"? - in that: PHP's object model is an "interesting" mixture of Java and C++. In regards to C++ it has detemrinsitric destructors, which enable RAII. The only complication is that all objects are reference counted (like shared_ptr in C++) and one can easily lose ownership from where one expects it to be. However if you keep an eye on ownership you can rely on reference count being decreased on function exit (be it regular exit or exception) and the destructor being called, in LIFO order as one expects. This isn't used much in PHP as you don't have to manage resources as often as with other languages/domains (in short lived request world one doesn't care whether a database connection is destroyed on function end or only on request shutdown, memory is handled automatically, etc.)

Re:C++ the Good Parts (2014) by threatripper on Thursday October 01, 2020 @05:53AM (#24649173)
Python also has destructors (def __del__(self):). They are called at whatever time and whichever order the GC gets around to it.
Re:C++ the Good Parts (2014) by saurik on Thursday October 01, 2020 @06:10AM (#24649264)
The Python people don't want you to rely on this--which I only learned many years later and it frankly ruined Python for me (are least in the abstract, as "practically" I can ignore this for my projects), as I consider "deterministic finalization" to be a critical language feature--but CPython uses reference counting and thereby has predictable deconstruction.
Re:C++ the Good Parts (2014) by ben509 on Thursday October 01, 2020 @07:20AM (#24649628)
CPython uses reference counting and gc. It's the worst of both worlds: the expense of refcounting, and faux determinism until some innocuous code change causes you to hang on to a reference.
Re:C++ the Good Parts (2014) by klyrs on Thursday October 01, 2020 @10:54AM (#24651521)
Refcounting needs a mechanism for cycle breaking, or it's necessarily leaky. This isn't the worst of both worlds; it's simply a consequence of refcounting.

The same issue occurs in c++ if you're sloppy with shared_ptr. If you know what you're doing, you can break cycles with weak references in either language. Where Python has diapers, c++ has footguns aplenty.

Re:C++ the Good Parts (2014) by int_19h on Thursday October 01, 2020 @06:30PM (#24656849)
The problem with Python isn't that it has reference cycles. It's that it has a tracing GC that tries to automagically fix those cycles for you. So in C++, if you get a cycle, the destructors do not run at all - which is pretty noticeable. In Python, they run "sometime later", so programmers are less inclined to fix the cycles (indeed, many aren't even aware that it's a problem).

But if you provide a non-deterministic mechanism on top of refcounting to break the cycles, and destructors aren't consistently deterministic already, why even bother with refcounting at all?

Re:C++ the Good Parts (2014) by ncmncm on Saturday October 03, 2020 @02:05AM (#24669934)
In practice, cycles just don't happen in real code.

It is possible to contrive a graph data structure with cycles, but it is a bad (i.e. slow) representation not useful in production.

Re:C++ the Good Parts (2014) by gpderetta on Thursday October 01, 2020 @06:25AM (#24649345)
Those are finalizes thought and are a bit different.