On Wednesday, September 26, 2018 10:20:58 PM MDT Chad Joan via Digitalmars- d-learn wrote: > On Wednesday, 26 September 2018 at 23:32:36 UTC, Jonathan M Davis > > wrote: > > On Wednesday, September 26, 2018 3:24:07 PM MDT Adam D. Ruppe > > > > via Digitalmars-d-learn wrote: > >> Object.factory kinda sux and I'd actually like to remove it > >> (among other people). There's no plan to actually do that, but > >> still, just on principle I want to turn people away. > > > > While there may not currently be plans to be remove it, as > > there _are_ plans to add ProtoObject as the new root class > > underneath Object, at some point here, it's likely that a large > > percentage of classes won't have anything to do with Object, so > > relying on Object.factory to be able to construct class Objects > > in general isn't likely to be a viable path in the long term - > > though presumably it would work for a code base that's written > > specifically with it in mind. > > > > Personally, I'm hoping that we eventually get to the point > > where Walter and Andrei are willing to outright deprecate > > Object itself, but I expect that ProtoObject will have to have > > been in use for a while before we have any chance of that > > happening. Either way, I think that it's clear that most code > > bases should go with a solution other than Object.factory if at > > all reasonably possible. > > > > - Jonathan M Davis > > That's interesting! Thanks for mentioning. > > If you don't mind, what are the complaints regarding Object? Or > can you link me to discussions/issues/documents that point out > the shortcomings/pitfalls? > > I've probably run into a bunch of them, but I realize D has come > a long way since that original design and I wouldn't be surprised > if there's a lot more for me to learn here.
I can point you to the related DIP, though it's a WIP in progress https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIPxxxx.md There are also these enhancement requests for removing the various member functions from Object (though they're likely to be superceded by the DIP): https://issues.dlang.org/show_bug.cgi?id=9769 https://issues.dlang.org/show_bug.cgi?id=9770 https://issues.dlang.org/show_bug.cgi?id=9771 https://issues.dlang.org/show_bug.cgi?id=9772 Basically, the problems tend to come in two areas: 1. Because of how inheritance works, once you have a function on a class, you're forcing a certain set of attributes on that function - be it type qualifiers like const or shared or scope classes like pure or @safe. In some cases, derived classes can be more restricted when they override the function (e.g. an overide can be @safe when the original is @system), but that only goes so far, and when you use the base class API, you're stuck with whatever attributes it has. Regardless, derived classes can't be _less_ restrictive. In fact, the only reason that it's currently possible to use == with const class references in D right now is because of a hack. The free function opEquals that gets called when you use == on two class references actually casts away const so that it can then call the member function opEquals (which doesn't work with const). So, if the member function opEquals mutates the object, you actuall get undefined behavior. And because Object.opEquals defines both the parameter and invisible this parameter as mutable, derived classes have to do the same when they override it; otherwise, they'd be overloading it rather than overriding it. Object and its member functions really come from D1 and predate all of the various attributes in D2 - including const. But even if we could just add all of the attributes that we thought should be there without worrying about breaking existing code, there would be no right answer. For instance, while in the vast majority of cases, opEquals really should be const, having it be const does not work with types that lazily initialize some members (since unlike in C++, D does not have backdoors for const - when something is const, it really means const, and it's undefined behavior to cast away const and mutate the object). So, having Object.opEquals be const might work in 99% of cases, but it wouldn't work in all. The same could be said for other attributes such as pure or nothrow. Forcing a particular set of attributes on these functions on everyone is detrimental. And honestly, it really isn't necessary. Having them on Object comes from a Java-esque design where you don't have templates. With proper templates like D2 has, there normally isn't a reason to operate on an Object. You templatize the code rather than relying on a common base class. So, there's no need to have Object.toString in order have toString for all classes or Object.opEquals to have opEquals for all classes. Each class can define it however it sees fit. Now, once a particular class in a hierarchy has defined a function like opEquals or toString, that affects any classes derived from it, but then only the classes derived from it are restricted by those choices, not every single class in the entire language as has been the case with Object. 2. The other big issue has been that built-in monitor. It allows us to have synchronized classes, but in most cases, it's unnecessary overhead. _Most_ classes don't do anything with synchronized, so why have the monitor? It really should just be in those classes that need it. With Object as the base class for all D class, every class gets it whether it needs it or not. With the ProtoObject DIP, only those classes which specifically ask for it (or which don't bother to specify a base class and thus continue to use Object as their base class) will continue to have a monitor object. A related issue that Andrei likes to bring up occasionally (though I don't think that much of anyone else has complained about) is that synchronized is one of those things that the language can do that we can't duplicate without the languages help. With synchronized, you can have a const or immutable object with a mutex inside it which works perfectly fine, but without synchronized, that's not possible because of the transitivity of const and immutable. synchronized and the monitor object give us a backdoor that we can't emulate, and Andrei doesn't like language features where the language has a superpower that you can't emulate (another, unrelated example that he likes to bring up sometimes would be how when you pass a dynamic array to a templated function, it's instantiated with the tail-const version of the type, which doesn't work with user-defined types and actually would pose some interesting problems to implement for user-defined types). So, in any case, because of D's powerful template system, there's no need to have any member functions on Object. There arguably isn't even any need to have any root class type. But having a root class type with member functions has proven to be a _big_ problem when attributes come into play and a minor one with regards to unnecessary overhead because of synchronized classes. - Jonathan M Davis