October 11, 2013
On Friday, 11 October 2013 at 14:09:09 UTC, Gary Willoughby wrote:
> On Friday, 11 October 2013 at 05:49:38 UTC, luminousone wrote:
>> On Friday, 11 October 2013 at 04:13:55 UTC, Agustin wrote:
>>> I have a function that needs to check if the template provided inherit a class.
>>>
>>> For example:
>>>
>>> public void function(T, A...)(auto ref A values)
>>> {
>>> // static assert(IsBaseOf(L, T));
>>> }
>>>
>>> Check if T inherit class "L". Same result that std::is_base_of<L, T>::value using C++. Any clean way to do it, without a dirty hack.
>>
>> import std.traits;
>>
>> bool ChildInheritsFromParent( parent, child )( ) {
>> 	
>> 	foreach ( k, t; BaseClassesTuple!child ) {
>> 		if( typeid(t) == typeid(parent) )
>> 			return true;
>> 	}
>> 	return false;
>> }
>
> A simpler way:
>
> 	import std.stdio;
>
> 	bool instanceOf(A, B)(B value)
> 	{
> 		return !!cast(A)value;
> 	}
>
> 	void main()
> 	{
> 		assert(1.instanceOf!(int));
> 	}

Using casts that way won't always be correct, it would be better to use reflection in some way if possible.
October 11, 2013
On Friday, October 11, 2013 21:19:29 luminousone wrote:
> Using casts that way won't always be correct, it would be better to use reflection in some way if possible.

The only reason that the casts wouldn't be correct would be if the class overrode opCast for the type that you're casting to or had an alias this declaration for it. Using casting for "instanceOf" is considered the standard and correct way to do it. But if you're being paranoid about the possibility of a conversion being defined with opCast or alias this, then yes, you need to use typeid.

- Jonathan M Davis
October 11, 2013
On Friday, 11 October 2013 at 19:54:39 UTC, Jonathan M Davis wrote:
> On Friday, October 11, 2013 21:19:29 luminousone wrote:
>> Using casts that way won't always be correct, it would be better
>> to use reflection in some way if possible.
>
> The only reason that the casts wouldn't be correct would be if the class
> overrode opCast for the type that you're casting to or had an alias this
> declaration for it. Using casting for "instanceOf" is considered the standard
> and correct way to do it. But if you're being paranoid about the possibility
> of a conversion being defined with opCast or alias this, then yes, you need to
> use typeid.
>
> - Jonathan M Davis

import std.stdio;

bool instanceOf(A, B)(B value) {
        return !!cast(A)value;
}

class e {
}

class f : e {

}

class g {

}


void main() {
        int a;
        float b;
        char c;

        e E;
        f F;
        g G;

        assert( 1.instanceOf!int, "1");
        assert( a.instanceOf!int, "a"); // fails here ?!?
        assert( b.instanceOf!int, "b");
        assert( c.instanceOf!int, "c");

        assert( E.instanceOf!e  , "e"); // fails here !??
        assert( F.instanceOf!e  , "f");
        assert( G.instanceOf!e  , "g"); // fails as expected
}


Seems to be problems, at least with quick testing using rdmd. Using casts seems terribly hackish, I would think that some sort of reflection should be much safer/correct way todo this.

October 11, 2013
On Friday, 11 October 2013 at 19:19:31 UTC, luminousone wrote:
> On Friday, 11 October 2013 at 14:09:09 UTC, Gary Willoughby wrote:
>> On Friday, 11 October 2013 at 05:49:38 UTC, luminousone wrote:
>>> On Friday, 11 October 2013 at 04:13:55 UTC, Agustin wrote:
>>>> I have a function that needs to check if the template provided inherit a class.
>>>>
>>>> For example:
>>>>
>>>> public void function(T, A...)(auto ref A values)
>>>> {
>>>> // static assert(IsBaseOf(L, T));
>>>> }
>>>>
>>>> Check if T inherit class "L". Same result that std::is_base_of<L, T>::value using C++. Any clean way to do it, without a dirty hack.
>>>
>>> import std.traits;
>>>
>>> bool ChildInheritsFromParent( parent, child )( ) {
>>> 	
>>> 	foreach ( k, t; BaseClassesTuple!child ) {
>>> 		if( typeid(t) == typeid(parent) )
>>> 			return true;
>>> 	}
>>> 	return false;
>>> }
>>
>> A simpler way:
>>
>> 	import std.stdio;
>>
>> 	bool instanceOf(A, B)(B value)
>> 	{
>> 		return !!cast(A)value;
>> 	}
>>
>> 	void main()
>> 	{
>> 		assert(1.instanceOf!(int));
>> 	}
>
> Using casts that way won't always be correct, it would be better to use reflection in some way if possible.

This is wrong for me because i don't have a value, i just wanted to check if a template parameter inherit a class at compile time.

bool instanceOf(A, B)();
October 11, 2013
On Friday, October 11, 2013 23:06:53 luminousone wrote:
> On Friday, 11 October 2013 at 19:54:39 UTC, Jonathan M Davis
> 
> wrote:
> > On Friday, October 11, 2013 21:19:29 luminousone wrote:
> >> Using casts that way won't always be correct, it would be
> >> better
> >> to use reflection in some way if possible.
> > 
> > The only reason that the casts wouldn't be correct would be if
> > the class
> > overrode opCast for the type that you're casting to or had an
> > alias this
> > declaration for it. Using casting for "instanceOf" is
> > considered the standard
> > and correct way to do it. But if you're being paranoid about
> > the possibility
> > of a conversion being defined with opCast or alias this, then
> > yes, you need to
> > use typeid.
> > 
> > - Jonathan M Davis
> 
> import std.stdio;
> 
> bool instanceOf(A, B)(B value) {
> return !!cast(A)value;
> }
> 
> class e {
> }
> 
> class f : e {
> 
> }
> 
> class g {
> 
> }
> 
> 
> void main() {
> int a;
> float b;
> char c;
> 
> e E;
> f F;
> g G;
> 
> assert( 1.instanceOf!int, "1");
> assert( a.instanceOf!int, "a"); // fails here ?!?
> assert( b.instanceOf!int, "b");
> assert( c.instanceOf!int, "c");
> 
> assert( E.instanceOf!e , "e"); // fails here !??
> assert( F.instanceOf!e , "f");
> assert( G.instanceOf!e , "g"); // fails as expected
> }
> 
> 
> Seems to be problems, at least with quick testing using rdmd. Using casts seems terribly hackish, I would think that some sort of reflection should be much safer/correct way todo this.

Two things:

1. Casting to determine the type of a variable only makes sense with classes. The idea is that casting a reference to a particular class will result in null if the cast fails. That doesn't work at all with types that aren't classes.

2. All of your objects are null. Of course the cast is going to fail. You need to be operating on actual instances. The whole point of casting is to check the actual type of an object at runtime. It's a completely different use case from using compile-time reflection on two types to see whether one is a base class of the other. And usually all that's done for that is to see whether one implicitly converts to the other, which is(DerivedClass : BaseClass) will do for you. The only reason to use compile-time reflection is if you're want to make sure that DerivedClass doesn't implicitly convert to BaseClass via alias this instead of by actually being a class derived from BaseClass.

I'd also change the implementation of instanceOf to something like

bool instanceOf(A, B)(B value)
 if(is(A == class) && is(B == class))
{
 return cast(A)value !is null;
}

since it doesn't rely on the conversion to bool that ! does and is more explicit that way, but the other version will work.

- Jonathan M Davis
October 11, 2013
On Friday, 11 October 2013 at 21:49:50 UTC, Jonathan M Davis wrote:
> On Friday, October 11, 2013 23:06:53 luminousone wrote:
>> On Friday, 11 October 2013 at 19:54:39 UTC, Jonathan M Davis
>> 
>> wrote:
>> > On Friday, October 11, 2013 21:19:29 luminousone wrote:
>> >> Using casts that way won't always be correct, it would be
>> >> better
>> >> to use reflection in some way if possible.
>> > 
>> > The only reason that the casts wouldn't be correct would be if
>> > the class
>> > overrode opCast for the type that you're casting to or had an
>> > alias this
>> > declaration for it. Using casting for "instanceOf" is
>> > considered the standard
>> > and correct way to do it. But if you're being paranoid about
>> > the possibility
>> > of a conversion being defined with opCast or alias this, then
>> > yes, you need to
>> > use typeid.
>> > 
>> > - Jonathan M Davis
>> 
>> import std.stdio;
>> 
>> bool instanceOf(A, B)(B value) {
>> return !!cast(A)value;
>> }
>> 
>> class e {
>> }
>> 
>> class f : e {
>> 
>> }
>> 
>> class g {
>> 
>> }
>> 
>> 
>> void main() {
>> int a;
>> float b;
>> char c;
>> 
>> e E;
>> f F;
>> g G;
>> 
>> assert( 1.instanceOf!int, "1");
>> assert( a.instanceOf!int, "a"); // fails here ?!?
>> assert( b.instanceOf!int, "b");
>> assert( c.instanceOf!int, "c");
>> 
>> assert( E.instanceOf!e , "e"); // fails here !??
>> assert( F.instanceOf!e , "f");
>> assert( G.instanceOf!e , "g"); // fails as expected
>> }
>> 
>> 
>> Seems to be problems, at least with quick testing using rdmd.
>> Using casts seems terribly hackish, I would think that some sort
>> of reflection should be much safer/correct way todo this.
>
> Two things:
>
> 1. Casting to determine the type of a variable only makes sense with classes.
> The idea is that casting a reference to a particular class will result in null
> if the cast fails. That doesn't work at all with types that aren't classes.
>
> 2. All of your objects are null. Of course the cast is going to fail. You need
> to be operating on actual instances. The whole point of casting is to check
> the actual type of an object at runtime. It's a completely different use case
> from using compile-time reflection on two types to see whether one is a base
> class of the other. And usually all that's done for that is to see whether one
> implicitly converts to the other, which is(DerivedClass : BaseClass) will do
> for you. The only reason to use compile-time reflection is if you're want to
> make sure that DerivedClass doesn't implicitly convert to BaseClass via alias
> this instead of by actually being a class derived from BaseClass.
>
> I'd also change the implementation of instanceOf to something like
>
> bool instanceOf(A, B)(B value)
>  if(is(A == class) && is(B == class))
> {
>  return cast(A)value !is null;
> }
>
> since it doesn't rely on the conversion to bool that ! does and is more
> explicit that way, but the other version will work.
>
> - Jonathan M Davis

The inability to handle null is pretty big, specially considering that at not point is the class instance itself cared about!, Again this should be done via reflection, this method above is hackish at best.

perhaps,

bool instanceOf(A, B)( )
   if( is( A == class ) && is( B == class ) ) {
   if( __traits( isSame, A, B ) )
      return true;
   foreach( k, v ; BaseClassesTuple!A ) {
      if( __traits(isSame, B, v ) )
         return true;
   }
   return false;
}
October 12, 2013
On Saturday, October 12, 2013 00:54:48 luminousone wrote:
> The inability to handle null is pretty big, specially considering that at not point is the class instance itself cared about!,

No. It's expected. When you are casting to a particular object to test whether the object is of that type, you are testing the type that the object is, and if the object is null, then it is _not_ of the type that you're casting to.

> Again this should be done via reflection, this method above is hackish at best.

Testing via compile-time reflection is testing for something fundamentally different than what casting is testing for. With casting, you're testing whether the object is the type that you're casting to or a type derived from the type that you're casting to. With compile-time reflection, you're testing whether a particular type is derived from another type. One is testing an instance. The other is testing a type. The two are completely different.

- Jonathan M Davis
October 12, 2013
On Friday, October 11, 2013 22:31:25 Jonathan M Davis wrote:
> On Saturday, October 12, 2013 00:54:48 luminousone wrote:
> > The inability to handle null is pretty big, specially considering that at not point is the class instance itself cared about!,
> 
> No. It's expected. When you are casting to a particular object to test whether the object is of that type, you are testing the type that the object is, and if the object is null, then it is _not_ of the type that you're casting to.
> > Again this should be done via reflection, this method above is hackish at best.
> 
> Testing via compile-time reflection is testing for something fundamentally different than what casting is testing for. With casting, you're testing whether the object is the type that you're casting to or a type derived from the type that you're casting to. With compile-time reflection, you're testing whether a particular type is derived from another type. One is testing an instance. The other is testing a type. The two are completely different.

I'd also point out that if you have

class A
{
}

class B : A
{
}

B is _not_ an instance of A. It's a subclass of A. An instance is an object in memory, not the type of the object.

auto a = new A; //instance of A
auto b = new B; //instance of B
A c = new B; //instance of B
A d; //There is no instance here. The reference is null.
B e; //There's no instance here either for the same reason.

So, you're using the term "instance of" incorrectly.

- Jonathan M Davis
October 12, 2013
On Saturday, 12 October 2013 at 05:38:16 UTC, Jonathan M Davis wrote:
> On Friday, October 11, 2013 22:31:25 Jonathan M Davis wrote:
>> On Saturday, October 12, 2013 00:54:48 luminousone wrote:
>> > The inability to handle null is pretty big, specially considering
>> > that at not point is the class instance itself cared about!,
>> 
>> No. It's expected. When you are casting to a particular object to test
>> whether the object is of that type, you are testing the type that the
>> object is, and if the object is null, then it is _not_ of the type that
>> you're casting to.
>> > Again this should be done via reflection, this method above is
>> > hackish at best.
>> 
>> Testing via compile-time reflection is testing for something fundamentally
>> different than what casting is testing for. With casting, you're testing
>> whether the object is the type that you're casting to or a type derived from
>> the type that you're casting to. With compile-time reflection, you're
>> testing whether a particular type is derived from another type. One is
>> testing an instance. The other is testing a type. The two are completely
>> different.
>
> I'd also point out that if you have
>
> class A
> {
> }
>
> class B : A
> {
> }
>
> B is _not_ an instance of A. It's a subclass of A. An instance is an object in
> memory, not the type of the object.
>
> auto a = new A; //instance of A
> auto b = new B; //instance of B
> A c = new B; //instance of B
> A d; //There is no instance here. The reference is null.
> B e; //There's no instance here either for the same reason.
>
> So, you're using the term "instance of" incorrectly.
>
> - Jonathan M Davis

I was using the terminology used in prior posts, my point was to the original intent of the poster.

And again, the casting solution is a bloody hack, it is loaded with corner cases that will break things if you are not aware of them. It also requires an allocated instance of that object, What the poster wishes to test for doesn't require that, so why have a function that needs it unnecessarily.

It is bad practice.

And I suppose in good faith of correcting bad practices,

bool inheritsFrom(A, B)( )
   if( is( A == class ) && is( B == class ) ) {
   if( __traits( isSame, A, B ) )
      return true;
   foreach( k, v ; BaseClassesTuple!A ) {
      if( __traits(isSame, B, v ) )
         return true;
   }
   return false;
}
October 12, 2013
On Saturday, October 12, 2013 09:32:09 luminousone wrote:
> And again, the casting solution is a bloody hack, it is loaded with corner cases that will break things if you are not aware of them. It also requires an allocated instance of that object

Of course, it requires an instance of the object. The point is to test whether an instance is of a type derived from a particular type, not whether a particular type is derived from a particular type. If the OP wants to test whether a particular type is derived from another type, then casting is not the right solution. The way to do that is to use an is expression, e.g. is(Derived : Base). If you really care that the type is a derived type and want to avoid any other type of implicit conversions, then you need to use some compile time reflection to do that, but that's often overkill and completely kills the ability to create class which "inherits" via alias this, which is the main purpose for alias this existing in the first place.

> It is bad practice.

It's standard practice. Both the online docs and TDPL will tell you to use a cast to determine whether a particular object's type is derived from a particular type. And I completely disagree that it's bad practice, but clearly we're not going to agree on that.

- Jonathan M Davis