Bug 1835 – typeof(this) should return the type of object or some other typeof() is needed

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2008-02-14T05:25:00Z
Last change time
2015-06-09T01:31:22Z
Assigned to
nobody
Creator
onlystupidspamhere

Comments

Comment #0 by onlystupidspamhere — 2008-02-14T05:25:47Z
Consider the following code: class A { A foo() { return this; } } class B : A { B bar() { return this; } } void main() { auto b = new B; b.foo().bar(); // We would like to chain methods like this } Currently this is not possible without CRTP (fugly) / mixins (not a good idea) / casts (yucky). Also typeof(this) returns A in class A.. Why can't we allow this: class A { typeof(this) foo() { return this; } // here the return type would depend on the actual runtime type of the object } class B : A { B bar() { return this; } } void main() { auto b = new B; b.foo().bar(); // We would like to chain methods like this } Similar problems occur with common graph data structures. E.g. if we have nodes and edges and inherit from both of them. Now going from SubNode to SubNode won't be possible without the tricks mentioned above because of the type system. This is a very useful feature, see Scala language docs for more info.
Comment #1 by andrei — 2008-02-14T07:23:11Z
This proposal has a lot of merit. A better example than chaining is the clone function: class Root { abstract typeof(this) clone(); ... } If such a function were defined, then all derived classes would be required to implement it (which is a Good Thing) and would also be forced to return the same static type as themselves (which again is a Good Thing). Unfortunately, this does not port nicely to functions that accept an equivariant parameter, such as opCmp and opEquals: class Root { int opCmp(typeof(this) another); int opEquals(typeof(this) another); ... } The intent is to have the comparison operations accept the same type as the actual static type of the object. But such a signature cannot be checked statically - a runtime check would have to be inserted. Nonetheless, I'll bring it up with Walter.
Comment #2 by aarti — 2008-02-14T08:43:58Z
Well, I requested it already before... Unfortunately without much luck: 1. http://www.digitalmars.com/d/archives/digitalmars/D/Covariance_fix_was_Idea_Lazy_upcasting_51296.html 2. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=51201 It's also mentioned in previous bugzilla reports: 1. http://d.puremagic.com/issues/show_bug.cgi?id=323 2. http://d.puremagic.com/issues/show_bug.cgi?id=1120 The problem solution seems to have even its name: anchored types. ---------------- Additionally in current design you have to overwrite every, even simple setter/getter method in every derived class. e.g. class A { typeof(this) setX(int x) { this.x = x; } int x; } class B { void test() {} } When I don't want to redefine setX() in B, below also should work: B b = new B; b.setX(5).test;
Comment #3 by aarti — 2008-02-14T08:47:22Z
... B derives after A of course: class A { typeof(this) setX(int x) { this.x = x; } int x; } class B : A { void test() {} }
Comment #4 by andrei — 2008-02-14T12:07:19Z
I understand. Now the problem is that this is a feature of rather modest utility, while Walter has many much bigger rocks to move right now. I'll bring it un nonetheless. Andrei
Comment #5 by matti.niemenmaa+dbugzilla — 2008-08-20T08:15:09Z
*** Bug 2295 has been marked as a duplicate of this bug. ***
Comment #6 by simen.kjaras — 2010-07-24T08:00:24Z
With template this parameters[1], shouldn't this bug be closed? [1]: http://www.digitalmars.com/d/2.0/template.html#TemplateThisParameter
Comment #7 by kamm-removethis — 2010-07-24T09:15:23Z
Yes, it looks like template this parameters cover this use case. You can even express the contract of a clone function nicely: class B { T clone(this T)() { return (cast(T)this).cloneImpl(); } B cloneImpl() { return new B; } } class D { override D cloneImpl() { return new D; } } If the user forgets to provide cloneImpl or doesn't make it return the correct type, the compiler will complain. At least as long as clone!(D) gets instantiated somewhere.
Comment #8 by fawzi — 2010-07-24T16:18:40Z
Yes indeed and Christian showed this templates argument allows one workaround to achieve this (a wrapper object is another). {{{ class A { void a(...){ ... } T aChain(this T)() { a(); return cast(T)this; } } class B { void a(...){ ... } } }}} it might even be cleaner to have also a non chainable version, the return this is really a convenience, and not strictly part of the operation itself, even if it implies some duplication.