View mode: basic / threaded / horizontal-split · Log in · Help
December 04, 2012
Re: typeid() broken for interfaces?
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
December 04, 2012
Re: typeid() broken for interfaces?
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.
December 04, 2012
Re: typeid() broken for interfaces?
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))
December 04, 2012
Re: typeid() broken for interfaces?
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
December 04, 2012
Re: typeid() broken for interfaces?
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
December 04, 2012
Re: typeid() broken for interfaces?
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
December 04, 2012
Re: typeid() broken for interfaces?
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.
December 04, 2012
Re: typeid() broken for interfaces?
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
December 04, 2012
Re: typeid() broken for interfaces?
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.
December 04, 2012
Re: typeid() broken for interfaces?
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
1 2 3 4 5
Top | Discussion index | About this forum | D home