digitalmars.D - Rethinking the default class hierarchy: Milestone 1, Week 1
- Robert Aron (51/51) Sep 23 2021 [Project
- =?UTF-8?Q?Ali_=c3=87ehreli?= (3/5) Sep 24 2021 Can ProtoObject get rid of monitor as well?
- Robert Aron (2/7) Sep 29 2021 Yes, it can. `ProtoObject` will be empty.
- Petar Kirov [ZombineDev] (55/60) Sep 29 2021 Since there's no default base class in C++ (like
- Sebastiaan Koppe (8/14) Sep 29 2021 I tend to use the shared annotation a lot in our concurrency
- Bruce Carneal (4/18) Sep 29 2021 Like Sebastiaan, I also use shared quite a bit. It helps keep
- rikki cattermole (7/7) Sep 29 2021 I've stopped using shared entirely, it has only one meaning now for me
- Sebastiaan Koppe (6/13) Sep 30 2021 I remember fighting with `shared` too initially, trying to force
- rikki cattermole (3/18) Sep 30 2021 9 months ago, my conclusion was the same as yours.
[Project description](https://gist.github.com/edi33416/0e592f4afbeb2fb81d3abf235b9732ce) [SAOC projects](https://dlang.org/blog/2021/08/30/saoc-2021-projects/) Hello! The project that I have selected is “Rethinking the default class hierarchy”. Every class defined in the D language has `Object` as the root ancestor. `Object` defines four methods: `toString`, `toHash`, `opCmp` and `opEquals`, that, at a first glance, might not strike you with much but they are doing much more harm than good. Their signatures predate the introduction of the ` nogc`, `nothrow`, `pure` and ` safe` function attributes and `const`, `immutable` and `shared` type qualifiers. As a consequence, these methods make it difficult to use `Object` with qualifiers or in code with properties such as ` nogc` or ` safe`.\ The goal of the project is to implement the solution proposed by Eduard Staniloiu in his talk. We will introduce a new class, `ProtoObject`, as the root class and ancestor of `Object`. `ProtoObject` defines no methods and requires the user to implement the desired behaviour through interfaces: this approach enables the user to opt-in for the behaviour that makes sense for his class and the design is flexible enough to allow future attributes and language improvements to be used without breaking code. Last week I managed to do the following tasks for #SAOC2021: - read the [gist](https://gist.github.com/edi33416/0e592f4afbeb2fb81d3abf235b9732ce) that Edi provided and also watch [his talk](https://www.youtube.com/watch?v=EcG5mnOzZ0s) from Dconf to familiarize myself with the problem and the way we are going to handle it. To summarize this, we are going to introduce a new class `ProtoObject` as the root of all classes. The recommended way of going forward with types that inherit from `ProtoObject` is write and implement interfaces that expose the desired behaviour(order, equality, hash, etc.) that the type supports. - read about how the default class hierarchy is designed in Java, - Java has quite a few similarites with Dlang, both defining operations like `opEquals` or `getHash`, having similar operations (for example `getClass` is simillar to `typeid(obj)`) and an `object monitor` - Kotlin is similar to Java, as it was designed to interoperate fully with Java. In Kotlin the root of all classes is represented by the `Any` class and it also the operations described above, as well as new ones, such as `apply` and `also` Kotlin and D, and it comes a lot closer to what we desire. There is no builtin monitor. The `Monitor` object is implemented as a separate class that inherits from `Object` in the imposed methods, but they are still imposed, and `toString` will continue to be GC dependent. - took a look at the [DIPs](https://github.com/dlang/DIPs) to familiarize myself with them and read the guidelines The plan for the next week: - read about how Rust handles this, since it has a totally different approach - start writing the DIP for the project
Sep 23 2021
On 9/23/21 3:15 AM, Robert Aron wrote:`ProtoObject` defines no methods`object monitor`Can ProtoObject get rid of monitor as well? Ali
Sep 24 2021
On Friday, 24 September 2021 at 20:17:51 UTC, Ali Çehreli wrote:On 9/23/21 3:15 AM, Robert Aron wrote:Yes, it can. `ProtoObject` will be empty.`ProtoObject` defines no methods`object monitor`Can ProtoObject get rid of monitor as well? Ali
Sep 29 2021
On Friday, 24 September 2021 at 20:17:51 UTC, Ali Çehreli wrote:On 9/23/21 3:15 AM, Robert Aron wrote:Since there's no default base class in C++ (like `object.Object`), `extern (C++) class`-es defined in D don't inherit one implicitly as well, which is obviously necessary for ABI compatibility. This means that D already supports truly empty non-abstract classes (like the proposed `ProtoObject`), but only if they're declared as `extern (C++)`. Essentially, this proposal is about removing this limitation, so that an `extern (D)` class can also be empty. Luckily, most of Druntime and Phobos are oblivious to the fact that D's classes have monitors, as monitors are only needed for thread synchronization. (That's because D made the right choice by making `shared` memory explicit in the type system.) When is the last time you saw a Druntime, Phobos, or in general, D function that took a `shared` class reference? (Not a completely rhetorical question - I'd be interested to know if people have such instances in their projects.) Outside of `core.sync.*`, `std.concurrency` and `std.parallelism` nothing deals with `shared` classes. AFAIU, inserting `ProtoObject` as the base class of `Object` should be backwards compatible change as far as most library / application code is concerned, outside of specific meta-programming related code, like [this][1]. I think the biggest challenge would be ironing all the type-system related details, e.g. basic things like this: ``` // Should print `ProtoObject`? pragma (msg, typeof(( new class { auto getParent() { return super; } }).getParent() ) ); ``` https://run.dlang.io/is/DvVcn9 ``` class A {} class B {} // Object[] pragma (msg, typeof([ new A, new B])); extern (C++) class C {} extern (C++) class D {} // Error: incompatible types for `(new C) : (new D)`: `onlineapp.C` and `onlineapp.D` // _error_ (ICE?) pragma (msg, typeof([ new C, new D])); class E : ProtoObject {} class F {} // should print: `ProtoObject[]` pragma (msg, typeof([ new E, new F])); ``` https://run.dlang.io/is/LpmnfR [1]: https://dlang.org/phobos/std_traits#.AllImplicitConversionTargets`ProtoObject` defines no methods`object monitor`Can ProtoObject get rid of monitor as well? Ali
Sep 29 2021
On Wednesday, 29 September 2021 at 16:11:24 UTC, Petar Kirov [ZombineDev] wrote:When is the last time you saw a Druntime, Phobos, or in general, D function that took a `shared` class reference? (Not a completely rhetorical question - I'd be interested to know if people have such instances in their projects.) Outside of `core.sync.*`, `std.concurrency` and `std.parallelism` nothing deals with `shared` classes.I tend to use the shared annotation a lot in our concurrency library. Structs and delegates mostly though, but it has some classes as well. Obviously it is the sane thing to do once you have multiple execution contexts with shared state. I guess not many people have that though.
Sep 29 2021
On Wednesday, 29 September 2021 at 21:40:11 UTC, Sebastiaan Koppe wrote:On Wednesday, 29 September 2021 at 16:11:24 UTC, Petar Kirov [ZombineDev] wrote:Like Sebastiaan, I also use shared quite a bit. It helps keep things sorted if you need/want to roll your own multi-core flows.When is the last time you saw a Druntime, Phobos, or in general, D function that took a `shared` class reference? (Not a completely rhetorical question - I'd be interested to know if people have such instances in their projects.) Outside of `core.sync.*`, `std.concurrency` and `std.parallelism` nothing deals with `shared` classes.I tend to use the shared annotation a lot in our concurrency library. Structs and delegates mostly though, but it has some classes as well. Obviously it is the sane thing to do once you have multiple execution contexts with shared state. I guess not many people have that though
Sep 29 2021
I've stopped using shared entirely, it has only one meaning now for me and that is: use atomics. Having it infiltrate everywhere isn't helpful, in fact half the time I spent is on fixing casting to and from shared. This is after trying to implement lock-free concurrent data structures in D for like 6 months, so my opinion is slightly tainted with shared and atomics in general.
Sep 29 2021
On Thursday, 30 September 2021 at 04:02:30 UTC, rikki cattermole wrote:I've stopped using shared entirely, it has only one meaning now for me and that is: use atomics. Having it infiltrate everywhere isn't helpful, in fact half the time I spent is on fixing casting to and from shared. This is after trying to implement lock-free concurrent data structures in D for like 6 months, so my opinion is slightly tainted with shared and atomics in general.I remember fighting with `shared` too initially, trying to force my ideas onto the keyword. It resulted in a lot of casts and me hating it. I did came around though.
Sep 30 2021
On 30/09/2021 8:23 PM, Sebastiaan Koppe wrote:On Thursday, 30 September 2021 at 04:02:30 UTC, rikki cattermole wrote:9 months ago, my conclusion was the same as yours. Unfortunately my experiences didn't stop there... lolI've stopped using shared entirely, it has only one meaning now for me and that is: use atomics. Having it infiltrate everywhere isn't helpful, in fact half the time I spent is on fixing casting to and from shared. This is after trying to implement lock-free concurrent data structures in D for like 6 months, so my opinion is slightly tainted with shared and atomics in general.I remember fighting with `shared` too initially, trying to force my ideas onto the keyword. It resulted in a lot of casts and me hating it. I did came around though.
Sep 30 2021