digitalmars.D.learn - Traits
- Agustin (9/9) Oct 10 2013 I have a function that needs to check if the template provided
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (17/26) Oct 10 2013 One of the uses of the is expression determines "whether implicitly
- Jonathan M Davis (8/15) Oct 10 2013 Actually, checking for implicit conversion will work directly in the te=
- Agustin (4/53) Oct 11 2013 On Friday, 11 October 2013 at 05:45:00 UTC, Jonathan M Davis
- luminousone (10/20) Oct 10 2013 import std.traits;
- Jacob Carlborg (4/12) Oct 11 2013 That will perform a runtime check and not a compile time check.
- luminousone (5/17) Oct 11 2013 Is is just the typeid call that makes it unable to be ran at
- Jacob Carlborg (6/10) Oct 11 2013 Hmm, it may actually be possible to run this at compile time. I don't
- Jonathan M Davis (5/15) Oct 11 2013 If typeid works at compile time, it's only because you're using CTFE. It...
- Gary Willoughby (11/34) Oct 11 2013 A simpler way:
- luminousone (3/39) Oct 11 2013 Using casts that way won't always be correct, it would be better
- Jonathan M Davis (8/10) Oct 11 2013 The only reason that the casts wouldn't be correct would be if the class...
- luminousone (30/46) Oct 11 2013 import std.stdio;
- Jonathan M Davis (23/86) Oct 11 2013 Two things:
- luminousone (17/119) Oct 11 2013 The inability to handle null is pretty big, specially considering
- Jonathan M Davis (11/15) Oct 11 2013 No. It's expected. When you are casting to a particular object to test w...
- Jonathan M Davis (17/35) Oct 11 2013 I'd also point out that if you have
- luminousone (21/68) Oct 12 2013 I was using the terminology used in prior posts, my point was to
- Jonathan M Davis (16/20) Oct 12 2013 Of course, it requires an instance of the object. The point is to test w...
- luminousone (17/51) Oct 12 2013 1.
- Jonathan M Davis (19/38) Oct 12 2013 And as I pointed out, that's perfectly acceptable in most cases, because...
- luminousone (26/75) Oct 12 2013 1.
- Jonathan M Davis (48/140) Oct 12 2013 No. I'm saying that where there are corner cases, they are intentional a...
- Agustin (4/48) Oct 11 2013 This is wrong for me because i don't have a value, i just wanted
- Artur Skawina (17/27) Oct 12 2013 As others have said, a "T:L" template arg specialization will often
- Artur Skawina (12/23) Oct 12 2013 That was too verbose.
- luminousone (3/26) Oct 12 2013 I like that! Avoids importing std.traits, And will correctly
- Artur Skawina (15/27) Oct 12 2013 It's also buggy. A more useful version would be:
- luminousone (7/38) Oct 12 2013 yea "is" can be a lil confusing, especially that "is( C S ==
- Artur Skawina (6/23) Oct 13 2013 Yes, D supports only single inheritance, so there can never be more than
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
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
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
On Friday, 11 October 2013 at 04:35:38 UTC, Ali Çehreli wrote:On 10/10/2013 09:13 PM, Agustin wrote:On Friday, 11 October 2013 at 05:45:00 UTC, Jonathan M Davis wrote:I have a function that needs to check if the templateprovided inherit aclass. 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 thatstd::is_base_of<L,T>::value using C++. Any clean way to do it, without a dirtyhack. 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"); } AliOn Thursday, October 10, 2013 21:35:37 Ali Çehreli wrote:Those work great, thanks a lot!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
Oct 11 2013
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
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
On Friday, 11 October 2013 at 09:37:33 UTC, Jacob Carlborg wrote:On 2013-10-11 07: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?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.
Oct 11 2013
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
On Friday, October 11, 2013 15:34:28 Jacob Carlborg wrote:On 2013-10-11 11:49, luminousone wrote: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 DavisIs 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.
Oct 11 2013
On Friday, 11 October 2013 at 05:49:38 UTC, luminousone wrote:On Friday, 11 October 2013 at 04:13:55 UTC, Agustin wrote:A simpler way: import std.stdio; bool instanceOf(A, B)(B value) { return !!cast(A)value; } void main() { assert(1.instanceOf!(int)); }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 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:Using casts that way won't always be correct, it would be better to use reflection in some way if possible.On Friday, 11 October 2013 at 04:13:55 UTC, Agustin wrote:A simpler way: import std.stdio; bool instanceOf(A, B)(B value) { return !!cast(A)value; } void main() { assert(1.instanceOf!(int)); }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 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
Oct 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: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.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
On Friday, October 11, 2013 23:06:53 luminousone wrote:On Friday, 11 October 2013 at 19:54:39 UTC, Jonathan M Davis wrote: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 DavisOn Friday, October 11, 2013 21:19:29 luminousone wrote: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.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
On Friday, 11 October 2013 at 21:49:50 UTC, Jonathan M Davis wrote:On Friday, October 11, 2013 23:06:53 luminousone wrote: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; }On Friday, 11 October 2013 at 19:54:39 UTC, Jonathan M Davis wrote: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 DavisOn Friday, October 11, 2013 21:19:29 luminousone wrote: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.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
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
On Friday, October 11, 2013 22:31:25 Jonathan M Davis wrote:On Saturday, October 12, 2013 00:54:48 luminousone wrote: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 DavisThe 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.
Oct 11 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: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; }On Saturday, October 12, 2013 00:54:48 luminousone wrote: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 DavisThe 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.
Oct 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 objectOf 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
On Saturday, 12 October 2013 at 07:47:18 UTC, Jonathan M Davis wrote:On Saturday, October 12, 2013 09:32:09 luminousone wrote: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.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 objectOf 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
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
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. 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.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
On Saturday, October 12, 2013 11:50:27 luminousone wrote:On Saturday, 12 October 2013 at 08:40:42 UTC, Jonathan M Davis wrote: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).On Saturday, October 12, 2013 10:24:13 luminousone wrote:1. Your hand waving corner cases.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 Davis2. 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
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: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)();On Friday, 11 October 2013 at 05:49:38 UTC, luminousone wrote:Using casts that way won't always be correct, it would be better to use reflection in some way if possible.On Friday, 11 October 2013 at 04:13:55 UTC, Agustin wrote:A simpler way: import std.stdio; bool instanceOf(A, B)(B value) { return !!cast(A)value; } void main() { assert(1.instanceOf!(int)); }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 11 2013
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
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
On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina wrote:On 10/12/13 13:42, Artur Skawina wrote:I like that! Avoids importing std.traits, And will correctly handle interfaces as well.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
On 10/12/13 21:42, luminousone wrote:On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina wrote: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... arturtemplate 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.
Oct 12 2013
On Saturday, 12 October 2013 at 23:48:56 UTC, Artur Skawina wrote:On 10/12/13 21:42, luminousone wrote: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.On Saturday, 12 October 2013 at 11:50:05 UTC, Artur Skawina wrote: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... arturtemplate 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.
Oct 12 2013
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