www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - typeid() broken for interfaces?

reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
interface I { }
class C: I { }

I object = new C;
assert(typeid(object) == typeid(C)); // fails

Is this normal or is it a bug?
Note, that the same works fine in case of a base class, rather then an
interface.

-- 
Bye,
Gor Gyolchanyan.
Nov 30 2012
next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 30 November 2012 at 10:05:21 UTC, Gor Gyolchanyan 
wrote:
 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
 Note, that the same works fine in case of a base class, rather 
 then an
 interface.
It works according to spec. Object is expression of type interface I, so no dynamic type search is performed.
Nov 30 2012
parent reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
So the interfaces aren't supposed to hold a TypeInfo? That doesn't sound
right. That makes interfaces useless in a very large set of use cases.


On Fri, Nov 30, 2012 at 2:55 PM, Maxim Fomin <maxim maxim-fomin.ru> wrote:

 On Friday, 30 November 2012 at 10:05:21 UTC, Gor Gyolchanyan wrote:

 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
 Note, that the same works fine in case of a base class, rather then an
 interface.
It works according to spec. Object is expression of type interface I, so no dynamic type search is performed.
-- Bye, Gor Gyolchanyan.
Nov 30 2012
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 30 November 2012 at 11:04:10 UTC, Gor Gyolchanyan 
wrote:
 So the interfaces aren't supposed to hold a TypeInfo? That 
 doesn't sound
 right. That makes interfaces useless in a very large set of use 
 cases.
You can find information about interfaces and classes at http://dlang.org/abi.html (interfaces have a pointer to vtbl[] which entries have pointers to TypeInfo). You can also write enhancement request if you consider your proposal worth implementing (but I don't understand what exactly you want).
Nov 30 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 11/30/2012 9:04 PM, Gor Gyolchanyan wrote:
 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
Normal, since the typeids of interfaces are not the same as for classes.
 Note, that the same works fine in case of a base class, rather then an
 interface.
That works, because classes are classes. Classes are not interfaces.
Dec 01 2012
next sibling parent reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
What's the logic in this behavior?


On Sun, Dec 2, 2012 at 1:28 AM, Walter Bright <newshound2 digitalmars.com>wrote:

 On 11/30/2012 9:04 PM, Gor Gyolchanyan wrote:

 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
Normal, since the typeids of interfaces are not the same as for classes. Note, that the same works fine in case of a base class, rather then an
 interface.
That works, because classes are classes. Classes are not interfaces.
-- Bye, Gor Gyolchanyan.
Dec 02 2012
next sibling parent "pjmlp" <pjmlp progtools.org> writes:
On Sunday, 2 December 2012 at 19:26:47 UTC, Gor Gyolchanyan wrote:
 What's the logic in this behavior?


 On Sun, Dec 2, 2012 at 1:28 AM, Walter Bright 
 <newshound2 digitalmars.com>wrote:

 On 11/30/2012 9:04 PM, Gor Gyolchanyan wrote:

 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
Normal, since the typeids of interfaces are not the same as for classes. Note, that the same works fine in case of a base class, rather then an
 interface.
That works, because classes are classes. Classes are not interfaces.
Because interfaces don't extend object?
Dec 02 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/3/2012 6:26 AM, Gor Gyolchanyan wrote:
 What's the logic in this behavior?
Think of it this way. An int can be implicitly converted to a long, but they have different typeid's because they are different bits.
Dec 02 2012
parent reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
Wouldn't it be better to return the class's typeinfo if it is a class and
the interface's typeinfo if it isn't? The interface would then return the
most derived typeinfo that it knows of. I think, just because the interface
can be something other then a class object, doesn't mean it should be
treated as though it will never be a class object.


On Mon, Dec 3, 2012 at 5:10 AM, Walter Bright <newshound2 digitalmars.com>wrote:

 On 12/3/2012 6:26 AM, Gor Gyolchanyan wrote:

 What's the logic in this behavior?
Think of it this way. An int can be implicitly converted to a long, but they have different typeid's because they are different bits.
-- Bye, Gor Gyolchanyan.
Dec 02 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/3/2012 4:43 PM, Gor Gyolchanyan wrote:
 Wouldn't it be better to return the class's typeinfo if it is a class
 and the interface's typeinfo if it isn't? The interface would then
 return the most derived typeinfo that it knows of. I think, just because
 the interface can be something other then a class object, doesn't mean
 it should be treated as though it will never be a class object.
A particular interface can be implemented by many different class types, or by something that isn't even a class, so returning a typeid that's a class typeid would make it impossible to compare one with another.
Dec 02 2012
parent reply Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
Currently typeid(typeid(Interface)) == typeid(ClassInfo). So the interfaces
are using a class's type info, which doesn't make much sense considering
the aforementioned interface logic. If interfaces get their own type info
(like one without a "base" member), it might have an a member called
"objectType", which would be of type ClassInfo and would be null if the
interface is not a class object. then the interface would be perfectly
comparable with other interface types and in case it happens to be a class
object, that could be tested too. And with some more info, the offset of
the interface could be retrieved to compute the object's this reference
(all in case it is indeed a class object).


On Mon, Dec 3, 2012 at 9:58 AM, Walter Bright <newshound2 digitalmars.com>wrote:

 On 12/3/2012 4:43 PM, Gor Gyolchanyan wrote:

 Wouldn't it be better to return the class's typeinfo if it is a class
 and the interface's typeinfo if it isn't? The interface would then
 return the most derived typeinfo that it knows of. I think, just because
 the interface can be something other then a class object, doesn't mean
 it should be treated as though it will never be a class object.
A particular interface can be implemented by many different class types, or by something that isn't even a class, so returning a typeid that's a class typeid would make it impossible to compare one with another.
-- Bye, Gor Gyolchanyan.
Dec 03 2012
next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 3 December 2012 at 10:49:54 UTC, Gor Gyolchanyan wrote:
 Currently typeid(typeid(Interface)) == typeid(ClassInfo). So
Are you sure? //dpaste seems to be down import std.stdio; interface I { } class C: I { } void main() { I object = new C; writeln( typeid(object) == typeid(C) ); writeln( typeid(Interface) == typeid(ClassInfo) ); writeln( typeid(typeid(Interface)) == typeid(ClassInfo) ); } Using latest dmd from git head I get three falses.
Dec 03 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/3/2012 9:47 PM, Gor Gyolchanyan wrote:
 Currently typeid(typeid(Interface)) == typeid(ClassInfo).
I'm curious what you expect typeid(typeid(something)) to do. I would expect it to return the typeid of whatever object typeid returns. That has nothing to do with what 'something' is.
Dec 03 2012
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 1 December 2012 at 21:28:05 UTC, Walter Bright wrote:
 On 11/30/2012 9:04 PM, Gor Gyolchanyan wrote:
 interface I { }
 class C: I { }

 I object = new C;
 assert(typeid(object) == typeid(C)); // fails

 Is this normal or is it a bug?
Normal, since the typeids of interfaces are not the same as for classes.
 Note, that the same works fine in case of a base class, rather 
 then an
 interface.
That works, because classes are classes. Classes are not interfaces.
I'm still waiting to see an object that implement an interface but that isn't a class instance.
Dec 02 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 02, 2012 23:17:33 deadalnix wrote:
 I'm still waiting to see an object that implement an interface
 but that isn't a class instance.
Isn't that the case with the COM stuff? I remember there being something weird about them being interfaces but not classes, which is part of what has screwed over some of the interface-related stuff like opEquals. - Jonathan M Davis
Dec 02 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/3/2012 9:17 AM, deadalnix wrote:
 I'm still waiting to see an object that implement an interface but that
 isn't a class instance.
COM objects that come from code not written in D.
Dec 02 2012
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 3 December 2012 at 01:12:41 UTC, Walter Bright wrote:
 On 12/3/2012 9:17 AM, deadalnix wrote:
 I'm still waiting to see an object that implement an
interface but that
 isn't a class instance.
COM objects that come from code not written in D.
OK that make sense. I have to think about it.
Dec 02 2012
parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Monday, 3 December 2012 at 06:45:42 UTC, deadalnix wrote:
 On Monday, 3 December 2012 at 01:12:41 UTC, Walter Bright wrote:
 On 12/3/2012 9:17 AM, deadalnix wrote:
 I'm still waiting to see an object that implement an
interface but that
 isn't a class instance.
COM objects that come from code not written in D.
OK that make sense. I have to think about it.
When coding against interfaces, it is always a good decision not to try to get back the object. The main idea about using interfaces in first place is to have behavior independent of whatever class might implement it. If someone is trying to get back the implementation of a given interface, it is because the design is not sound in first place. -- Paulo
Dec 03 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-03 11:20, Paulo Pinto wrote:

 When coding against interfaces, it is always a good decision not to try
 to get back the object.

 The main idea about using interfaces in first place is to have behavior
 independent of whatever class might implement it. If someone is trying
 to get back the implementation of a given interface, it is because the
 design is not sound in first place.
Well, one would might think that this would work: interface I {} class A : I {} void main () { I i = new A; Object o = i; } But it doesn't. -- /Jacob Carlborg
Dec 03 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 3 December 2012 at 13:50:45 UTC, Jacob Carlborg wrote:
 On 2012-12-03 11:20, Paulo Pinto wrote:

 When coding against interfaces, it is always a good decision 
 not to try
 to get back the object.

 The main idea about using interfaces in first place is to have 
 behavior
 independent of whatever class might implement it. If someone 
 is trying
 to get back the implementation of a given interface, it is 
 because the
 design is not sound in first place.
Well, one would might think that this would work: interface I {} class A : I {} void main () { I i = new A; Object o = i; } But it doesn't.
Object does not implement interface I, so why should interface instance be implicitly converted to it? It even should not be implicitly convertible to class if that class implements interface. However it is possible to use cast. TDPL and dlang.org say almost nothing about it, but current investigated dmd behavior (http://dpaste.dzfl.pl/84637416) makes sense: it allows convenient conversion when it should happen, protects from poor implicit conversion which should not happen, but still allows to do what you want if you assume you are right. If you not, dmd punish you with segfault.
Dec 03 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-03 15:41, Maxim Fomin wrote:

 Object does not implement interface I, so why should interface instance
 be implicitly converted to it? It even should not be implicitly
 convertible to class if that class implements interface. However it is
 possible to use cast.
Because Object is the root of the class hierarchy. That's how it works in Java, for example. It's just because of these COM interfaces, that are not D interfaces, that we have this behavior. -- /Jacob Carlborg
Dec 03 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-03 16:51, Jacob Carlborg wrote:

 Because Object is the root of the class hierarchy. That's how it works
 in Java, for example. It's just because of these COM interfaces, that
 are not D interfaces, that we have this behavior.
Note, I'm not saying that an interface should be implicitly converted to any class, only to Object. -- /Jacob Carlborg
Dec 03 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/4/2012 2:52 AM, Jacob Carlborg wrote:
 Note, I'm not saying that an interface should be implicitly converted to
 any class, only to Object.
But not all interfaces come from Objects.
Dec 03 2012
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 3 December 2012 at 20:59:24 UTC, Walter Bright wrote:
 On 12/4/2012 2:52 AM, Jacob Carlborg wrote:
 Note, I'm not saying that an interface should be implicitly 
 converted to
 any class, only to Object.
But not all interfaces come from Objects.
So I thought about all that. typeid is about runtime type detection. As all interfaces are not coming from object, it is definitively an issue to resolve them as object sometime. However, keeping tied to the static type when runtime typeid is asked for is a but sad. But interfaces that don't resolve as object are well know at compile time. So isn't it possible to resolve all interfaces that we know are objects into object's typeid ? After all, this is what typeid is about.
Dec 03 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/4/2012 8:07 AM, deadalnix wrote:
 On Monday, 3 December 2012 at 20:59:24 UTC, Walter Bright wrote:
 On 12/4/2012 2:52 AM, Jacob Carlborg wrote:
 Note, I'm not saying that an interface should be implicitly converted to
 any class, only to Object.
But not all interfaces come from Objects.
So I thought about all that. typeid is about runtime type detection. As all interfaces are not coming from object, it is definitively an issue to resolve them as object sometime. However, keeping tied to the static type when runtime typeid is asked for is a but sad. But interfaces that don't resolve as object are well know at compile time. So isn't it possible to resolve all interfaces that we know are objects into object's typeid ? After all, this is what typeid is about.
I really don't know what issue you're trying to solve here. The typeid's work fine - and interfaces are not objects. Having the typeid for an interface be an object means you cannot compare typeids of one interface to another interface. And, my feeling is that if your code needs to implicitly convert interfaces to objects, or even know that an interface instance is implemented by a particular object, your program design is broken and is missing the point of what interfaces are.
Dec 03 2012
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 3 December 2012 at 21:53:47 UTC, Walter Bright wrote:
 I really don't know what issue you're trying to solve here. The 
 typeid's work fine - and interfaces are not objects. Having the 
 typeid for an interface be an object means you cannot compare 
 typeids of one interface to another interface.
You can't instantiate interface. So an underlying type MUST exist. The whole point of typeid on expression is to discover what is the dynamic type of things, otherwize you'd be using typeid(type) not typeid(expression).
 And, my feeling is that if your code needs to implicitly 
 convert interfaces to objects, or even know that an interface 
 instance is implemented by a particular object, your program 
 design is broken and is missing the point of what interfaces 
 are.
The same apply to object in general, and still D does it and for good reason (you'll find that few cases where it is actually useful and not a design flaw).
Dec 03 2012
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 3 December 2012 at 23:53:26 UTC, deadalnix wrote:
 On Monday, 3 December 2012 at 21:53:47 UTC, Walter Bright wrote:
 I really don't know what issue you're trying to solve here. 
 The typeid's work fine - and interfaces are not objects. 
 Having the typeid for an interface be an object means you 
 cannot compare typeids of one interface to another interface.
You can't instantiate interface. So an underlying type MUST exist. The whole point of typeid on expression is to discover what is the dynamic type of things, otherwize you'd be using typeid(type) not typeid(expression).
You cannot create interface instance with new operator because interface object is not valid until it is actually some class instance. But this does not mean neither that typeid operator for interfaces should return dynamic type nor that interface can be implicitly converted to Object - because interface instance may be invalid: import std.stdio; interface I { } void main() { I i; // should be implicitly converted Object o = cast(Object)i; writeln(typeid(o)); } and because presence of interface does not necessarily mean that some class has implemented it. This makes casting interfaces to object unsafe operation that better should require explicit cast.
Dec 03 2012
next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Tuesday, 4 December 2012 at 07:38:31 UTC, Maxim Fomin wrote:
 On Monday, 3 December 2012 at 23:53:26 UTC, deadalnix wrote:
 On Monday, 3 December 2012 at 21:53:47 UTC, Walter Bright 
 wrote:
 I really don't know what issue you're trying to solve here. 
 The typeid's work fine - and interfaces are not objects. 
 Having the typeid for an interface be an object means you 
 cannot compare typeids of one interface to another interface.
You can't instantiate interface. So an underlying type MUST exist. The whole point of typeid on expression is to discover what is the dynamic type of things, otherwize you'd be using typeid(type) not typeid(expression).
You cannot create interface instance with new operator because interface object is not valid until it is actually some class instance. But this does not mean neither that typeid operator for interfaces should return dynamic type nor that interface can be implicitly converted to Object - because interface instance may be invalid: import std.stdio; interface I { } void main() { I i; // should be implicitly converted Object o = cast(Object)i; writeln(typeid(o)); } and because presence of interface does not necessarily mean that some class has implemented it. This makes casting interfaces to object unsafe operation that better should require explicit cast.
Given my experience with the interface concept in several OO languages that implement it, I would say that you never want to know what object was given to you. The whole point of interfaces is to have some form of multiple inheritance in single inheritance languages. So you *really* don't want to cast interfaces to objects. I can't think of a single reason this makes sense, other than work around bad designs. -- Paulo
Dec 04 2012
prev sibling parent "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 07:38:31 UTC, Maxim Fomin wrote:
 On Monday, 3 December 2012 at 23:53:26 UTC, deadalnix wrote:
 On Monday, 3 December 2012 at 21:53:47 UTC, Walter Bright 
 wrote:
 I really don't know what issue you're trying to solve here. 
 The typeid's work fine - and interfaces are not objects. 
 Having the typeid for an interface be an object means you 
 cannot compare typeids of one interface to another interface.
You can't instantiate interface. So an underlying type MUST exist. The whole point of typeid on expression is to discover what is the dynamic type of things, otherwize you'd be using typeid(type) not typeid(expression).
You cannot create interface instance with new operator because interface object is not valid until it is actually some class instance. But this does not mean neither that typeid operator for interfaces should return dynamic type nor that interface can be implicitly converted to Object - because interface instance may be invalid: import std.stdio; interface I { } void main() { I i; // should be implicitly converted Object o = cast(Object)i; writeln(typeid(o)); } and because presence of interface does not necessarily mean that some class has implemented it. This makes casting interfaces to object unsafe operation that better should require explicit cast.
The above is a perfectly safe conversion. The variable i is _a reference_ to instance of I. since it was not assigned any class instance that implements I, it is initialized as _null_. In the example above: (o is null && typeid(o) == typeid(Object))
Dec 04 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-03 21:59, Walter Bright wrote:

 But not all interfaces come from Objects.
No, but those are statically known. -- /Jacob Carlborg
Dec 03 2012
prev sibling parent reply "foobar" <foo bar.com> writes:
On Monday, 3 December 2012 at 20:59:24 UTC, Walter Bright wrote:
 On 12/4/2012 2:52 AM, Jacob Carlborg wrote:
 Note, I'm not saying that an interface should be implicitly 
 converted to
 any class, only to Object.
But not all interfaces come from Objects.
IMO this is a design mistake - the special case is preferred over the common case which goes against the D philosophy of making the common case easy and the special case possible. All COM instances are known at _compile_time_ as they're all required to inherit from a special IUnknown interface so the compiler _knows_ if indeed an interface represents a COM instance or not. This can be used to handle this special case differently. Interface i = new Class(); Object o = i; // should work for regular interfaces The compiler can issue a compile-time error if i is COM since this is known at compile type.
Dec 04 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-12-04 13:15, foobar wrote:

 IMO this is a design mistake - the special case is preferred over the
 common case which goes against the D philosophy of making the common
 case easy and the special case possible.

 All COM instances are known at _compile_time_ as they're all required to
 inherit from a special IUnknown interface so the compiler _knows_ if
 indeed an interface represents a COM instance or not. This can be used
 to handle this special case differently.

 Interface i = new Class();
 Object o = i; // should work for regular interfaces

 The compiler can issue a compile-time error if i is COM since this is
 known at compile type.
Exactly, I couldn't agree more. -- /Jacob Carlborg
Dec 04 2012
prev sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 3 December 2012 at 15:52:24 UTC, Jacob Carlborg wrote:
 On 2012-12-03 16:51, Jacob Carlborg wrote:

 Because Object is the root of the class hierarchy. That's how 
 it works
 in Java, for example. It's just because of these COM 
 interfaces, that
 are not D interfaces, that we have this behavior.
Note, I'm not saying that an interface should be implicitly converted to any class, only to Object.
And what happens if nobody implements an interface? import std.stdio; interface I { } class A { } void main() { I i; // assume this is implicit Object o = cast(Object)i; writeln(typeid(o)); } Safe conversion class to interface requires two conditions: 1a) that class implements interface 1b) if you try to use interface variable, it must be an allocated class instance Safe conversion to Object requires: 2a) somebody in class hierarchy implements interface 2b) interface instance is actually allocated class instance It is possible to check 1a) but impossible in general case to check 2a). Also the first is design feature while the second is design abuse. And if there is need for getting runtime type of interface through typeid() it is always possible to use cast: import std.stdio; interface I { } class A : I { } void main() { A a = new A; I i = a; Object o = cast(Object)i; writeln(typeid(o)); // A }
Dec 04 2012
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 4 December 2012 at 08:22:36 UTC, Maxim Fomin wrote:
 On Monday, 3 December 2012 at 15:52:24 UTC, Jacob Carlborg 
 wrote:
 On 2012-12-03 16:51, Jacob Carlborg wrote:

 Because Object is the root of the class hierarchy. That's how 
 it works
 in Java, for example. It's just because of these COM 
 interfaces, that
 are not D interfaces, that we have this behavior.
Note, I'm not saying that an interface should be implicitly converted to any class, only to Object.
And what happens if nobody implements an interface?
The same as abstract classes : you can get the typeid by looking at it throw child's typeid or typeid(type). typeid(expression) will never return them because they can't be instantiated.
Dec 04 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-12-04 09:22, Maxim Fomin wrote:

 And what happens if nobody implements an interface?

 import std.stdio;

 interface I { }

 class A { }

 void main()
 {
      I i;
      // assume this is implicit
      Object o = cast(Object)i;
      writeln(typeid(o));
 }
You get a segmentation fault since both "i" and "o" are null.
 Safe conversion class to interface requires two conditions:
 1a) that class implements interface
 1b) if you try to use interface variable, it must be an allocated class
 instance

 Safe conversion to Object requires:
 2a) somebody in class hierarchy implements interface
 2b) interface instance is actually allocated class instance
You cannot really get an instance of an interface without having a class implementing it. That is, without inserting any explicit casts, which works: interface I { } class A { } void main() { A a = new A; I i = cast(I) a; Object o = cast(Object)i; writeln(typeid(a)); // A }
 It is possible to check 1a) but impossible in general case to check 2a).
 Also the first is design feature while the second is design abuse.
I don't understand why it wouldn't be safe to allow implicit casts of interfaces to Object. If I want to call toString, why should I need to insert an explicit cast to Object just because I have an interface? -- /Jacob Carlborg
Dec 04 2012
parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Tuesday, 4 December 2012 at 12:26:53 UTC, Jacob Carlborg wrote:
 On 2012-12-04 09:22, Maxim Fomin wrote:

 And what happens if nobody implements an interface?

 import std.stdio;

 interface I { }

 class A { }

 void main()
 {
     I i;
     // assume this is implicit
     Object o = cast(Object)i;
     writeln(typeid(o));
 }
You get a segmentation fault since both "i" and "o" are null.
 Safe conversion class to interface requires two conditions:
 1a) that class implements interface
 1b) if you try to use interface variable, it must be an 
 allocated class
 instance

 Safe conversion to Object requires:
 2a) somebody in class hierarchy implements interface
 2b) interface instance is actually allocated class instance
You cannot really get an instance of an interface without having a class implementing it. That is, without inserting any explicit casts, which works: interface I { } class A { } void main() { A a = new A; I i = cast(I) a; Object o = cast(Object)i; writeln(typeid(a)); // A }
 It is possible to check 1a) but impossible in general case to 
 check 2a).
 Also the first is design feature while the second is design 
 abuse.
I don't understand why it wouldn't be safe to allow implicit casts of interfaces to Object. If I want to call toString, why should I need to insert an explicit cast to Object just because I have an interface?
If you want to call toSring, it should be part of the interface specification, as simple as that. Interfaces are like contracts which state what is to be expected of a certain type. -- Paulo
Dec 04 2012
parent reply "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 12:30:29 UTC, Paulo Pinto wrote:
 On Tuesday, 4 December 2012 at 12:26:53 UTC, Jacob Carlborg 
 wrote:
 On 2012-12-04 09:22, Maxim Fomin wrote:

 And what happens if nobody implements an interface?

 import std.stdio;

 interface I { }

 class A { }

 void main()
 {
    I i;
    // assume this is implicit
    Object o = cast(Object)i;
    writeln(typeid(o));
 }
You get a segmentation fault since both "i" and "o" are null.
 Safe conversion class to interface requires two conditions:
 1a) that class implements interface
 1b) if you try to use interface variable, it must be an 
 allocated class
 instance

 Safe conversion to Object requires:
 2a) somebody in class hierarchy implements interface
 2b) interface instance is actually allocated class instance
You cannot really get an instance of an interface without having a class implementing it. That is, without inserting any explicit casts, which works: interface I { } class A { } void main() { A a = new A; I i = cast(I) a; Object o = cast(Object)i; writeln(typeid(a)); // A }
 It is possible to check 1a) but impossible in general case to 
 check 2a).
 Also the first is design feature while the second is design 
 abuse.
I don't understand why it wouldn't be safe to allow implicit casts of interfaces to Object. If I want to call toString, why should I need to insert an explicit cast to Object just because I have an interface?
If you want to call toSring, it should be part of the interface specification, as simple as that. Interfaces are like contracts which state what is to be expected of a certain type. -- Paulo
Generally speaking you are right. But specifically regarding toString, what would you suggest? Should each and every Interface have a toString method? Should we have an IObject Interface that all classes are required to explicitly inherit? The purpose of having a root Object class is to define the _common interface of all objects_. Why else have such a class in the first place? Requiring an explicit cast to Object makes sense only in a no-single-root design such as the one in c++ which D sensibly chose not to copy. We can have a separate debate what should the root Object define, but there should not be a requirement to explicitly cast any object to it.
Dec 04 2012
parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Tuesday, 4 December 2012 at 13:07:59 UTC, foobar wrote:
 On Tuesday, 4 December 2012 at 12:30:29 UTC, Paulo Pinto wrote:
 On Tuesday, 4 December 2012 at 12:26:53 UTC, Jacob Carlborg 
 wrote:
 On 2012-12-04 09:22, Maxim Fomin wrote:

 And what happens if nobody implements an interface?

 import std.stdio;

 interface I { }

 class A { }

 void main()
 {
   I i;
   // assume this is implicit
   Object o = cast(Object)i;
   writeln(typeid(o));
 }
You get a segmentation fault since both "i" and "o" are null.
 Safe conversion class to interface requires two conditions:
 1a) that class implements interface
 1b) if you try to use interface variable, it must be an 
 allocated class
 instance

 Safe conversion to Object requires:
 2a) somebody in class hierarchy implements interface
 2b) interface instance is actually allocated class instance
You cannot really get an instance of an interface without having a class implementing it. That is, without inserting any explicit casts, which works: interface I { } class A { } void main() { A a = new A; I i = cast(I) a; Object o = cast(Object)i; writeln(typeid(a)); // A }
 It is possible to check 1a) but impossible in general case 
 to check 2a).
 Also the first is design feature while the second is design 
 abuse.
I don't understand why it wouldn't be safe to allow implicit casts of interfaces to Object. If I want to call toString, why should I need to insert an explicit cast to Object just because I have an interface?
If you want to call toSring, it should be part of the interface specification, as simple as that. Interfaces are like contracts which state what is to be expected of a certain type. -- Paulo
Generally speaking you are right. But specifically regarding toString, what would you suggest? Should each and every Interface have a toString method?
Yes for each interface where you intend to call toString().
 Should we have an IObject Interface that all classes are 
 required to explicitly inherit?
 The purpose of having a root Object class is to define the 
 _common interface of all objects_. Why else have such a class 
 in the first place?
For languages without generics where you need a common base class to place in containers.
 Requiring an explicit cast to Object makes sense only in a 
 no-single-root design such as the one in c++ which D sensibly 
 chose not to copy.

 We can have a separate debate what should the root Object 
 define, but there should not be a requirement to explicitly 
 cast any object to it.
The whole point of interfaces is to have explicit dependencies of methods, properties, variables across the inheritance tree. Actually there was a discussion some months ago about what methods still made sense to expose via object, given D's templates. -- Paulo
Dec 04 2012
parent reply "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 13:47:39 UTC, Paulo Pinto wrote:

 Generally speaking you are right. But specifically regarding 
 toString, what would you suggest?
 Should each and every Interface have a toString method?
Yes for each interface where you intend to call toString().
That's a lot of duplication considering D already provides this in Object.
 Should we have an IObject Interface that all classes are 
 required to explicitly inherit?
 The purpose of having a root Object class is to define the 
 _common interface of all objects_. Why else have such a class 
 in the first place?
For languages without generics where you need a common base class to place in containers.
That's only one reason. Other reasons are to provide a common interface for all objects. Anyway, we are discussing the current D design and not other possible designs such as the one in C++.
 Requiring an explicit cast to Object makes sense only in a 
 no-single-root design such as the one in c++ which D sensibly 
 chose not to copy.

 We can have a separate debate what should the root Object 
 define, but there should not be a requirement to explicitly 
 cast any object to it.
The whole point of interfaces is to have explicit dependencies of methods, properties, variables across the inheritance tree. Actually there was a discussion some months ago about what methods still made sense to expose via object, given D's templates. -- Paulo
Given D's _current_ design, all objects should implicitly cast to Object. It's plain common sense - If we have a root class that all other classes inherit from than it logically follows that all class instances can be implicitly & safely converted back to that root class (Object). What you are arguing is whether the current design of D of defining Object makes sense in the first place. I'm arguing that _given the current design_ the language is inconsistent and has a design flaw.
Dec 04 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
Dec 04 2012
next sibling parent reply "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Dec 05 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, December 05, 2012 15:11:55 foobar wrote:
 On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis
 
 wrote:
 On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
No. The plan is not to deprecate Object. The reality is that those functions don't need to be on Object in D, because all of the runtime stuff that relies have to put them on Object and operate through Object. What we have currently (and templates weren't as good in D1, possibly making those functions necessary there). And having those functions on Object has created a lot of problems with regards to stuff like const. If they're there, they have to be const so that you can compare const objects, but given how D's const works, that then make certain idioms impossible in classes (e.g. lazy loading member variables and caching). const needs to work, but we can't force it on people, and putting it on Object forces it on people. Rather, it's perfectly possible for only derived classes to have those functions. They can then use the function attributes that match what they need, and stuff like druntime's opEquals or AAs will just be appropriately tempatized and work with the derived classes without needing to have any of that on Object. There's really no need to have any of that on Object. I'd have to go digging through the archives to find the last discussion on const-correctness where this was discussed in some detail, but that's the gist of it. Putting those functions on Object causes a lot of problems with regards to function attributes, and templates make actually putting those functions on Object unnecessary. - Jonathan M Davis
Dec 05 2012
parent reply "foobar" <foo bar.com> writes:
On Wednesday, 5 December 2012 at 16:21:55 UTC, Jonathan M Davis 
wrote:
 On Wednesday, December 05, 2012 15:11:55 foobar wrote:
 On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis
 
 wrote:
 On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides 
 this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
No. The plan is not to deprecate Object. The reality is that those functions don't need to be on Object in D, because all of the runtime stuff that relies on them can (and really should) be templatized, whereas in Java have to put them on Object and operate through Object. What we have currently have with Object in D is a case of having copied too much from (and templates weren't as good in D1, possibly making those functions necessary there). And having those functions on Object has created a lot of problems with regards to stuff like const. If they're there, they have to be const so that you can compare const objects, but given how D's const works, that then make certain idioms impossible in classes (e.g. lazy loading member variables and caching). const needs to work, but we can't force it on people, and putting it on Object forces it on people. Rather, it's perfectly possible for only derived classes to have those functions. They can then use the function attributes that match what they need, and stuff like druntime's opEquals or AAs will just be appropriately tempatized and work with the derived classes without needing to have any of that on Object. There's really no need to have any of that on Object. I'd have to go digging through the archives to find the last discussion on const-correctness where this was discussed in some detail, but that's the gist of it. Putting those functions on Object causes a lot of problems with regards to function attributes, and templates make actually putting those functions on Object unnecessary. - Jonathan M Davis
But these are the methods of Object. So even if Object itself remains it looses its meaning. So are we going to keep Object just for backwards compatibility? Is there any point left keeping the single root design?
Dec 06 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, December 06, 2012 12:03:14 foobar wrote:
 But these are the methods of Object. So even if Object itself
 remains it looses its meaning. So are we going to keep Object
 just for backwards compatibility? Is there any point left keeping
 the single root design?
It's would still be perfectly possible to pass around Object if you wanted to. You just couldn't call much on it without casting it to something else first. Perhaps there's less reason to have it, but no one ever suggested that we get rid of it. Having those functions on Object has harmed us. Having a common base type hasn't. But much as it was decided on, nothing has happened yet, so who knows how the transition will be done. - Jonathan M Davis
Dec 06 2012
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 6 December 2012 at 11:03:15 UTC, foobar wrote:
 But these are the methods of Object. So even if Object itself 
 remains it looses its meaning. So are we going to keep Object 
 just for backwards compatibility? Is there any point left 
 keeping the single root design?
I don't see any major drawback in keeping Object. What are the drawbacks ?
Dec 06 2012
prev sibling next sibling parent "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interface such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Dec 05 2012
prev sibling parent "foobar" <foo bar.com> writes:
On Tuesday, 4 December 2012 at 18:41:14 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 04, 2012 17:35:23 foobar wrote:
 That's a lot of duplication considering D already provides this
 in Object.
Though per the last major discussion on const-correctness and Object, it's likely that toString, toHash, opCmp, and opEquals will be removed from Object, in which case you'd need a derived class which implemented them to use any of them. - Jonathan m Davis
In other words, the plan is to pretty much deprecate Object? I hope there would be appropriate replacement before this happens. Users should be able to have a standardized API and a default implementation for these methods. Is phobos going to introduce interfaces such as Printable, Comparable, etc.. ? (names tentative, I'm more worried about the semantics).
Dec 05 2012