www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Traits

reply "Agustin" <agustin.l.alvarez hotmail.com> writes:
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.
Oct 10 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 10/10/2013 09:13 PM, 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)
function happens to be a keyword. :)
 {
    // 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.
One of the uses of the is expression determines "whether implicitly convertible to". It may work for you: public void foo(T, A...)(auto ref A values) { static assert(is (T : L)); } class L {} class LL : L {} void main() { foo!LL(1, 2.3, "4"); } Ali
Oct 10 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 10, 2013 21:35:37 Ali =C3=87ehreli wrote:
 One of the uses of the is expression determines "whether implicitly
 convertible to". It may work for you:
=20
 public void foo(T, A...)(auto ref A values)
 {
      static assert(is (T : L));
 }
Actually, checking for implicit conversion will work directly in the te= mplate=20 signature without a template constraint or static assertion. e.g. public void foo(T : L, A...)auto ref A values) { } - Jonathan M Davis
Oct 10 2013
prev sibling parent "Agustin" <agustin.l.alvarez hotmail.com> writes:
On Friday, 11 October 2013 at 04:35:38 UTC, Ali Çehreli wrote:
 On 10/10/2013 09:13 PM, 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)
function happens to be a keyword. :)
 {
    // 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. One of the uses of the is expression determines "whether implicitly convertible to". It may work for you: public void foo(T, A...)(auto ref A values) { static assert(is (T : L)); } class L {} class LL : L {} void main() { foo!LL(1, 2.3, "4"); } Ali
On Friday, 11 October 2013 at 05:45:00 UTC, Jonathan M Davis wrote:
 On Thursday, October 10, 2013 21:35:37 Ali Çehreli wrote:
 One of the uses of the is expression determines "whether 
 implicitly
 convertible to". It may work for you:
 
 public void foo(T, A...)(auto ref A values)
 {
      static assert(is (T : L));
 }
Actually, checking for implicit conversion will work directly in the template signature without a template constraint or static assertion. e.g. public void foo(T : L, A...)auto ref A values) { } - Jonathan M Davis
Those work great, thanks a lot!
Oct 11 2013
prev sibling next sibling parent reply "luminousone" <rd.hunt gmail.com> writes:
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; }
Oct 10 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-10-11 07:49, luminousone wrote:

 import std.traits;

 bool ChildInheritsFromParent( parent, child )( ) {

      foreach ( k, t; BaseClassesTuple!child ) {
          if( typeid(t) == typeid(parent) )
              return true;
      }
      return false;
 }
That will perform a runtime check and not a compile time check. -- /Jacob Carlborg
Oct 11 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
On Friday, 11 October 2013 at 09:37:33 UTC, Jacob Carlborg wrote:
 On 2013-10-11 07:49, luminousone wrote:

 import std.traits;

 bool ChildInheritsFromParent( parent, child )( ) {

     foreach ( k, t; BaseClassesTuple!child ) {
         if( typeid(t) == typeid(parent) )
             return true;
     }
     return false;
 }
That will perform a runtime check and not a compile time check.
Is is just the typeid call that makes it unable to be ran at compile time or is their something else wrong in their?, Would a string compare with type.classInfo.name fix that, or is their not a tool yet in place for that?
Oct 11 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-10-11 11:49, luminousone wrote:

 Is is just the typeid call that makes it unable to be ran at compile
 time or is their something else wrong in their?,

 Would a string compare with type.classInfo.name fix that, or is their
 not a tool yet in place for that?
Hmm, it may actually be possible to run this at compile time. I don't remember. I was thinking that "typeid" doesn't work at compile time, but I might be wrong. -- /Jacob Carlborg
Oct 11 2013
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, October 11, 2013 15:34:28 Jacob Carlborg wrote:
 On 2013-10-11 11:49, luminousone wrote:
 Is is just the typeid call that makes it unable to be ran at compile
 time or is their something else wrong in their?,
 
 Would a string compare with type.classInfo.name fix that, or is their
 not a tool yet in place for that?
Hmm, it may actually be possible to run this at compile time. I don't remember. I was thinking that "typeid" doesn't work at compile time, but I might be wrong.
If typeid works at compile time, it's only because you're using CTFE. It returns the type of the instance when the code runs, not statically. So, it's intended as a runtime check, not a compile time check. - Jonathan M Davis
Oct 11 2013
prev sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
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)); }
Oct 11 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
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.
Oct 11 2013
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Oct 11 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
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.
Oct 11 2013
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Oct 11 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
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; }
Oct 11 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Oct 11 2013
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Oct 11 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
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; }
Oct 12 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Oct 12 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
On Saturday, 12 October 2013 at 07:47:18 UTC, Jonathan M Davis 
wrote:
 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
1. opCast, and alias can break the cast approach. You pointed this out yourself. 2. The requested function is testing types not instance state. bool instanceOf(A,B)( B value ) { assert( value !is null ); return inheritsFrom(A,typeof(value)); } 3. Cast breaks on null, so this must be checked on every call, and leads to a 3 state outcome, true, false, and null, null then returns false, which is potentially incorrect and could cause odd bugs hard to trace. Again it is bad practice regardless of what any document says.
Oct 12 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 12, 2013 10:24:13 luminousone wrote:
 1.
 
 opCast, and alias can break the cast approach. You pointed this
 out yourself.
And as I pointed out, that's perfectly acceptable in most cases, because what you care about is the conversion. alias this is specifically designed with the idea that you can subtype a struct or class with it. Checking with typeid to get the exact type would be circumventing that design. So, casting is almost always the correct option.
 2.
 
 The requested function is testing types not instance state.
 
 bool instanceOf(A,B)( B value ) {
          assert( value !is null );
          return inheritsFrom(A,typeof(value));
 }
Fine. That doesn't invalidate casting to check an instance. They're two different things.
 3.
 
 Cast breaks on null, so this must be checked on every call, and
 leads to a 3 state outcome, true, false, and null, null then
 returns false, which is potentially incorrect and could cause odd
 bugs hard to trace.
null is _supposed_ to be false. The whole point is to check whether the object in question can be used as the type that you're casting to. If it's null, it isn't the type that you're casting to - it's null. So, false is exactly what it should be doing. It's specifically designed so that you can do if(auto c = cast(MyClass)obj) { ... }
 Again it is bad practice regardless of what any document says.
And I completely disagree. Casting is doing precisely what it's designed to do, and I really don't see a problem with it. - Jonathan M Davis
Oct 12 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
On Saturday, 12 October 2013 at 08:40:42 UTC, Jonathan M Davis 
wrote:
 On Saturday, October 12, 2013 10:24:13 luminousone wrote:
 1.
 
 opCast, and alias can break the cast approach. You pointed this
 out yourself.
And as I pointed out, that's perfectly acceptable in most cases, because what you care about is the conversion. alias this is specifically designed with the idea that you can subtype a struct or class with it. Checking with typeid to get the exact type would be circumventing that design. So, casting is almost always the correct option.
 2.
 
 The requested function is testing types not instance state.
 
 bool instanceOf(A,B)( B value ) {
          assert( value !is null );
          return inheritsFrom(A,typeof(value));
 }
Fine. That doesn't invalidate casting to check an instance. They're two different things.
 3.
 
 Cast breaks on null, so this must be checked on every call, and
 leads to a 3 state outcome, true, false, and null, null then
 returns false, which is potentially incorrect and could cause 
 odd
 bugs hard to trace.
null is _supposed_ to be false. The whole point is to check whether the object in question can be used as the type that you're casting to. If it's null, it isn't the type that you're casting to - it's null. So, false is exactly what it should be doing. It's specifically designed so that you can do if(auto c = cast(MyClass)obj) { ... }
 Again it is bad practice regardless of what any document says.
And I completely disagree. Casting is doing precisely what it's designed to do, and I really don't see a problem with it. - Jonathan M Davis
1. Your hand waving corner cases. 2. Your throwing away perfectly good opportunities for the compiler to use CTFE by depending on allocated instance state(or at least its address) to get your answers. To say nothing of the fact, that reflection won't have the list of corner case problems that casting does. Reflection is simply correct in more cases then casting for this activity, it is also more generic, and requires fewer function parameters. 3. Hardly, casting null works perfectly fine in c and c++, D strives towards more correct code, its one of the things I love about the language. It is precisely because D checks null on cast, that creates the potential ternary return. A corner case I grant you, but still. Further D being a statically typed language, it could very well be argued, that a nulled reference, still has a type. meaning... bool instanceOf(A,B)( B value ) { return inheritsFrom(A,B); } would be more correct then using typeOf(value) version above.
Oct 12 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 12, 2013 11:50:27 luminousone wrote:
 On Saturday, 12 October 2013 at 08:40:42 UTC, Jonathan M Davis
 
 wrote:
 On Saturday, October 12, 2013 10:24:13 luminousone wrote:
 1.
 
 opCast, and alias can break the cast approach. You pointed this
 out yourself.
And as I pointed out, that's perfectly acceptable in most cases, because what you care about is the conversion. alias this is specifically designed with the idea that you can subtype a struct or class with it. Checking with typeid to get the exact type would be circumventing that design. So, casting is almost always the correct option.
 2.
 
 The requested function is testing types not instance state.
 
 bool instanceOf(A,B)( B value ) {
 
          assert( value !is null );
          return inheritsFrom(A,typeof(value));
 
 }
Fine. That doesn't invalidate casting to check an instance. They're two different things.
 3.
 
 Cast breaks on null, so this must be checked on every call, and
 leads to a 3 state outcome, true, false, and null, null then
 returns false, which is potentially incorrect and could cause
 odd
 bugs hard to trace.
null is _supposed_ to be false. The whole point is to check whether the object in question can be used as the type that you're casting to. If it's null, it isn't the type that you're casting to - it's null. So, false is exactly what it should be doing. It's specifically designed so that you can do if(auto c = cast(MyClass)obj) { ... }
 Again it is bad practice regardless of what any document says.
And I completely disagree. Casting is doing precisely what it's designed to do, and I really don't see a problem with it. - Jonathan M Davis
1. Your hand waving corner cases.
No. I'm saying that where there are corner cases, they are intentional and expected. Casting takes conversions into account that are supposed to be there, and using any kind reflection would bypass that. And if you know that you're dealing with a reference to a base class, and you're testing whether that reference points to a particular derived class (as opposed to simply checking whether the conversion works), you know that the corner cases don't even exist unless the base class overrode opCast or alias this to that derived class (which would be a really broken design, since base classes shouldn't know about derived classes).
 2.
 
 Your throwing away perfectly good opportunities for the compiler
 to use CTFE by depending on allocated instance state(or at least
 its address) to get your answers.
It's _impossible_ to use CTFE for testing whether a particular instance is of a particular type. You can test its _reference_. You can test whether a particular type is derived from another. But you _can't_ test a particular instance, because it doesn't even exist at compile time.
 3.
 
 Hardly, casting null works perfectly fine in c and c++, D strives
 towards more correct code, its one of the things I love about the
 language.
 
 It is precisely because D checks null on cast, that creates the
 potential ternary return. A corner case I grant you, but still.
 
 Further D being a statically typed language, it could very well
 be argued, that a nulled reference, still has a type.
Sure, the reference has a type, but the object doesn't because there isn't one. It's typeof(null). And the whole point of casting to check the type is to check the obect's type, not the reference. If it's null, the reference does _not_ point to an object, so there's no object to test, and it is _not_ of the type that you're testing for.
 meaning...
 
 bool instanceOf(A,B)( B value ) {
           return inheritsFrom(A,B);
 }
 
 would be more correct then using typeOf(value) version above.
Again, this is completely wrong for the case where you're checking an object's type. That is a _runtime_ operation for determining what the type of the actual object being referred to is. All you're doing here is checking whether B is a derived class of A, which is for testing the types of the _references_, not the actual type of the object. B could inherit from A, but the object could in fact be of type C which is derived from B - or any other type which is derived from B. e.g. class A {} class B : A {} class C : B {} A a1 = new A; A a2 = new B; A a3 = new C; assert(cast(B)a1 is null); assert(cast(B)a2 !is null); assert(cast(B)a3 !is null); These are all testing the objects being referred to and _not_ anything about the types themselves. You use compile time reflection when you're testing _types_ (e.g. whether B is derived from A). You use casts to determine whether a reference of a base type is actually referring to an object of a particular derived class. The two use cases are completely different. If you're using compile time reflection to determine whether a particular instance is of a particular type, then you're doing it wrong, because all you're testing are the references, not the object. If you're using casts to determine whether a particular type is derived from another type, then that's wrong because of the extra conversions that could take place (not to mention, it's then a runtime check instead of a compile- time one). You have to use the right test for the right situation. - Jonathan M Davis
Oct 12 2013
prev sibling parent "Agustin" <agustin.l.alvarez hotmail.com> writes:
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)();
Oct 11 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 10/11/13 06:13, 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.
As others have said, a "T:L" template arg specialization will often be enough. When you really need to restrict the i/f (which can be a good idea), something like this will work: template isBaseOf(BASE, C) { static if (is(C S == super)) enum isBaseOf = { foreach (A; S) static if (is(A==BASE)) return true; return is(C==BASE); }(); else enum isBaseOf = is(C==BASE); } artur
Oct 12 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/12/13 13:42, Artur Skawina wrote:
    template isBaseOf(BASE, C) {
       static if (is(C S == super))
          enum isBaseOf = {
             foreach (A; S)
                static if (is(A==BASE))
                   return true;
             return is(C==BASE);
          }();
       else
          enum isBaseOf = is(C==BASE);
    }
That was too verbose. template isBaseOf(BASE, C) { enum isBaseOf = { static if (is(C S == super)) foreach (A; S) static if (is(A==BASE)) return true; return is(C==BASE); }(); } artur
Oct 12 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina wrote:
 On 10/12/13 13:42, Artur Skawina wrote:
    template isBaseOf(BASE, C) {
       static if (is(C S == super))
          enum isBaseOf = {
             foreach (A; S)
                static if (is(A==BASE))
                   return true;
             return is(C==BASE);
          }();
       else
          enum isBaseOf = is(C==BASE);
    }
That was too verbose. template isBaseOf(BASE, C) { enum isBaseOf = { static if (is(C S == super)) foreach (A; S) static if (is(A==BASE)) return true; return is(C==BASE); }(); } artur
I like that! Avoids importing std.traits, And will correctly handle interfaces as well.
Oct 12 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 10/12/13 21:42, luminousone wrote:
 On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina wrote:
    template isBaseOf(BASE, C) {
       enum isBaseOf = {
          static if (is(C S == super))
             foreach (A; S)
                static if (is(A==BASE))
                   return true;
          return is(C==BASE);
       }();
    }
I like that! Avoids importing std.traits, And will correctly handle interfaces as well.
It's also buggy. A more useful version would be: template isBaseOf(BASE, C) { enum isBaseOf = { static if (is(C S == super)) foreach (A; S) static if (isBaseOf!(BASE, A)) return true; return is(C==BASE); }(); } Sorry, didn't test this properly; going to blame the dlang is-expression docs. It's not like D has multiple inheritance, so using "base classes" (plural) is very misleading... artur
Oct 12 2013
parent reply "luminousone" <rd.hunt gmail.com> writes:
On Saturday, 12 October 2013 at 23:48:56 UTC, Artur Skawina wrote:
 On 10/12/13 21:42, luminousone wrote:
 On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina 
 wrote:
    template isBaseOf(BASE, C) {
       enum isBaseOf = {
          static if (is(C S == super))
             foreach (A; S)
                static if (is(A==BASE))
                   return true;
          return is(C==BASE);
       }();
    }
I like that! Avoids importing std.traits, And will correctly handle interfaces as well.
It's also buggy. A more useful version would be: template isBaseOf(BASE, C) { enum isBaseOf = { static if (is(C S == super)) foreach (A; S) static if (isBaseOf!(BASE, A)) return true; return is(C==BASE); }(); } Sorry, didn't test this properly; going to blame the dlang is-expression docs. It's not like D has multiple inheritance, so using "base classes" (plural) is very misleading... artur
yea "is" can be a lil confusing, especially that "is( C S == super)" expression. I take it that "is( C S == super)" is only the bases directly listed for inheritance by the class and not the bases bases as well? which is the reason for the change you made their? That expression is weird lol.
Oct 12 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 10/13/13 02:25, luminousone wrote:
 On Saturday, 12 October 2013 at 23:48:56 UTC, Artur Skawina wrote:
    template isBaseOf(BASE, C) {
       enum isBaseOf = {
          static if (is(C S == super))
             foreach (A; S)
                static if (isBaseOf!(BASE, A))
                   return true;
          return is(C==BASE);
       }();
    }

 Sorry, didn't test this properly; going to blame the dlang is-expression docs.
 It's not like D has multiple inheritance, so using "base classes" (plural)
 is very misleading...
 yea "is" can be a lil confusing, especially that "is( C S == super)"
expression.
 
 I take it that "is( C S == super)" is only the bases directly listed for
inheritance by the class and not the bases bases as well? which is the reason
for the change you made their?
Yes, D supports only single inheritance, so there can never be more than one "super" class (plus interfaces). I'm not using classes in D often and when I looked up that is-expr syntax, the wrong doc confused me. It should say "base class" (or "super class"), not "base classes". artur
Oct 13 2013