www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is it safe to use 'is' to compare types?

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
Will typeid(a) is typeid(b) yield different results than 
typeid(a) == typeid(b)?
Mar 03 2016
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than 
 typeid(a) == typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
Mar 03 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 3 March 2016 at 23:51:16 UTC, Adam D. Ruppe wrote:
 On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than 
 typeid(a) == typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
But opEquals also has extra comparison: auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); This makes me feel they are not the same.
Mar 03 2016
next sibling parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 3 March 2016 at 23:58:39 UTC, Yuxuan Shui wrote:
 On Thursday, 3 March 2016 at 23:51:16 UTC, Adam D. Ruppe wrote:
 On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than 
 typeid(a) == typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
But opEquals also has extra comparison: auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); This makes me feel they are not the same.
Oh, I get it. 'a is b' works for the results of typeid(). But not for duplicates of TypeInfo. For example: import std.stdio; A a, b; auto x = typeid(a), y = typeid(b); writeln(x is y); auto xz = ((cast(ubyte *)x)[0..typeof(x).classinfo.init.length]).dup; //Evil auto z = cast(typeof(x))(cast(void *)xz); writeln(x is z); //false writeln(x == z); //true
Mar 03 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/3/16 6:58 PM, Yuxuan Shui wrote:
 On Thursday, 3 March 2016 at 23:51:16 UTC, Adam D. Ruppe wrote:
 On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than typeid(a) ==
 typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
But opEquals also has extra comparison: auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); This makes me feel they are not the same.
In some cases, for instance using DLLs, the TypeInfo for an object allocated in one way may be identical, but be a different instance from the TypeInfo allocated in another way. This is why the string comparison occurs. Note that comparing ANY object will first check if they are the same instance before calling any functions (this is in object.opEquals) -Steve
Mar 04 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Friday, 4 March 2016 at 15:18:55 UTC, Steven Schveighoffer 
wrote:
 On 3/3/16 6:58 PM, Yuxuan Shui wrote:
 On Thursday, 3 March 2016 at 23:51:16 UTC, Adam D. Ruppe wrote:
 On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than 
 typeid(a) ==
 typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
But opEquals also has extra comparison: auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); This makes me feel they are not the same.
In some cases, for instance using DLLs, the TypeInfo for an object allocated in one way may be identical, but be a different instance from the TypeInfo allocated in another way. This is why the string comparison occurs. Note that comparing ANY object will first check if they are the same instance before calling any functions (this is in object.opEquals) -Steve
Thanks for answering. But I still don't understand why TypeInfo would need to be allocated. Aren't typeid() just returning references to the __DxxTypeInfo_xxxx__initZ symbol?
Mar 04 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/4/16 4:30 PM, Yuxuan Shui wrote:
 On Friday, 4 March 2016 at 15:18:55 UTC, Steven Schveighoffer wrote:
 On 3/3/16 6:58 PM, Yuxuan Shui wrote:
 On Thursday, 3 March 2016 at 23:51:16 UTC, Adam D. Ruppe wrote:
 On Thursday, 3 March 2016 at 23:46:50 UTC, Yuxuan Shui wrote:
 Will typeid(a) is typeid(b) yield different results than typeid(a) ==
 typeid(b)?
No. Indeed, opEquals on TypeInfo just calls is itself.
But opEquals also has extra comparison: auto ti = cast(const TypeInfo)o; return ti && this.toString() == ti.toString(); This makes me feel they are not the same.
In some cases, for instance using DLLs, the TypeInfo for an object allocated in one way may be identical, but be a different instance from the TypeInfo allocated in another way. This is why the string comparison occurs. Note that comparing ANY object will first check if they are the same instance before calling any functions (this is in object.opEquals)
Thanks for answering. But I still don't understand why TypeInfo would need to be allocated. Aren't typeid() just returning references to the __DxxTypeInfo_xxxx__initZ symbol?
You misunderstood, I meant the typeinfo *for* an allocated object, not that the typeinfo was allocated. In some cases, 2 different objects allocated from different libraries (usually DLL-land) may reference TypeInfo from different segments, even though the TypeInfo is identical. -Steve
Mar 07 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Monday, 7 March 2016 at 16:13:45 UTC, Steven Schveighoffer 
wrote:
 On 3/4/16 4:30 PM, Yuxuan Shui wrote:
 On Friday, 4 March 2016 at 15:18:55 UTC, Steven Schveighoffer 
 wrote:
[...]
Thanks for answering. But I still don't understand why TypeInfo would need to be allocated. Aren't typeid() just returning references to the __DxxTypeInfo_xxxx__initZ symbol?
You misunderstood, I meant the typeinfo *for* an allocated object, not that the typeinfo was allocated. In some cases, 2 different objects allocated from different libraries (usually DLL-land) may reference TypeInfo from different segments, even though the TypeInfo is identical. -Steve
Hmm... Does that mean each DLL will have their own TypeInfo symbols for the same type?
Mar 08 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/16 3:26 PM, Yuxuan Shui wrote:
 On Monday, 7 March 2016 at 16:13:45 UTC, Steven Schveighoffer wrote:
 On 3/4/16 4:30 PM, Yuxuan Shui wrote:
 On Friday, 4 March 2016 at 15:18:55 UTC, Steven Schveighoffer wrote:
 [...]
Thanks for answering. But I still don't understand why TypeInfo would need to be allocated. Aren't typeid() just returning references to the __DxxTypeInfo_xxxx__initZ symbol?
You misunderstood, I meant the typeinfo *for* an allocated object, not that the typeinfo was allocated. In some cases, 2 different objects allocated from different libraries (usually DLL-land) may reference TypeInfo from different segments, even though the TypeInfo is identical.
Hmm... Does that mean each DLL will have their own TypeInfo symbols for the same type?
I don't know the exact circumstances. I think the answer is both yes and no, depending on the situation :) But I know this is the reason for the string comparison. -Steve
Mar 08 2016
prev sibling parent reply Anon <anon anon.anon> writes:
On Tuesday, 8 March 2016 at 20:26:04 UTC, Yuxuan Shui wrote:
 On Monday, 7 March 2016 at 16:13:45 UTC, Steven Schveighoffer 
 wrote:
 On 3/4/16 4:30 PM, Yuxuan Shui wrote:
 On Friday, 4 March 2016 at 15:18:55 UTC, Steven Schveighoffer 
 wrote:
[...]
Thanks for answering. But I still don't understand why TypeInfo would need to be allocated. Aren't typeid() just returning references to the __DxxTypeInfo_xxxx__initZ symbol?
You misunderstood, I meant the typeinfo *for* an allocated object, not that the typeinfo was allocated. In some cases, 2 different objects allocated from different libraries (usually DLL-land) may reference TypeInfo from different segments, even though the TypeInfo is identical. -Steve
Hmm... Does that mean each DLL will have their own TypeInfo symbols for the same type?
[Note: I phrase my answer in terms of Linux shared libraries (*.so) because D doesn't actually have proper Windows DLL support yet. The same would apply to DLLs, it just feels wrong describing functionality that doesn't exist.] They can, mostly due to templated types. Consider modules `common`, `foo`, and `bar` (all built as shared libraries), and `main` (built as an executable). module common; // => common.so struct List(T) { // ... } module foo; // => foo.so, links to common.so import common; List!int getList() { // ... } module bar; // => bar.so, links to common.so import common void processList(List!int a) { // ... } module main; // => main, links to foo.so, bar.so, and common.so import foo, bar; void main() { processList(getList()); } No part of List!int is instantiated in common, so no part of it is actually present in common.so. Instead, it is instantiated in foo and bar, and thus separate copies of List!int are present in foo.so and bar.so, along with TypeInfo for List!int. If you were to statically link instead (using .a or .lib files), the linker would keep only one copy of List!int and its TypeInfo, but the linker can't eliminate either of them when dealing with shared libraries. So, yes, I think the string comparison is needed, as awkward as it may seem in many circumstances.
Mar 08 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Tuesday, 8 March 2016 at 23:13:32 UTC, Anon wrote:
 On Tuesday, 8 March 2016 at 20:26:04 UTC, Yuxuan Shui wrote:
 [...]
[Note: I phrase my answer in terms of Linux shared libraries (*.so) because D doesn't actually have proper Windows DLL support yet. The same would apply to DLLs, it just feels wrong describing functionality that doesn't exist.] [...]
Can we left TypeInfo symbol undefined in the shared libraries? i.e. D compiler will strip out TypeInfo definition when creating .so. (Alternatively, we can have TypeInfo always undefined in .o, and generate them in linking stage only when creating executables)
Mar 09 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 03/09/2016 07:05 AM, Yuxuan Shui wrote:

 Can we left TypeInfo symbol undefined in the shared libraries? i.e. D
 compiler will strip out TypeInfo definition when creating .so.
 (Alternatively, we can have TypeInfo always undefined in .o, and
 generate them in linking stage only when creating executables)
That would require a linker that's aware of D but as far as I know, all system languages use the system linker. Ali
Mar 09 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Wednesday, 9 March 2016 at 22:26:38 UTC, Ali Çehreli wrote:
 On 03/09/2016 07:05 AM, Yuxuan Shui wrote:

 Can we left TypeInfo symbol undefined in the shared
libraries? i.e. D
 compiler will strip out TypeInfo definition when creating .so.
 (Alternatively, we can have TypeInfo always undefined in .o,
and
 generate them in linking stage only when creating executables)
That would require a linker that's aware of D but as far as I know, all system languages use the system linker. Ali
Hmm, how about this: During compilation, D generate undefined TypeInfo symbols, but it also embed type information in the object file (like what Rust does). And then, when dmd/ldc/gdc/whatever is called for linking executables, it will scan object files and generate another object file containing the TypeInfos, and link them together with the system linker. If the compiler is called for linking shared libraries, it doesn't.
Mar 09 2016
parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Thu, Mar 10, 2016 at 01:33:41AM +0000, Yuxuan Shui via Digitalmars-d-learn
wrote:
 On Wednesday, 9 March 2016 at 22:26:38 UTC, Ali Çehreli wrote:
On 03/09/2016 07:05 AM, Yuxuan Shui wrote:

 Can we left TypeInfo symbol undefined in the shared libraries? i.e.
 D compiler will strip out TypeInfo definition when creating .so.
 (Alternatively, we can have TypeInfo always undefined in .o, and
 generate them in linking stage only when creating executables)
That would require a linker that's aware of D but as far as I know, all system languages use the system linker. Ali
Hmm, how about this: During compilation, D generate undefined TypeInfo symbols, but it also embed type information in the object file (like what Rust does). And then, when dmd/ldc/gdc/whatever is called for linking executables, it will scan object files and generate another object file containing the TypeInfos, and link them together with the system linker. If the compiler is called for linking shared libraries, it doesn't.
You can't rely on invoking the compiler to link these objects, because if you're using shared libraries, it will be the OS's dynamic linker that will get invoked to resolve the references, and different versions of shared libraries may have a different set of TypeInfo's, and the compiler may not be able to generate the required TypeInfo's. A better way is to use the OS linker's "weak symbol" feature, where a symbol is allowed to be defined multiple times (with identical content), and the linker (both dynamic and static) will choose the first definition that it finds. T -- Маленькие детки - маленькие бедки.
Mar 09 2016
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 10 March 2016 at 02:14:19 UTC, H. S. Teoh wrote:
 On Thu, Mar 10, 2016 at 01:33:41AM +0000, Yuxuan Shui via 
 Digitalmars-d-learn wrote:
 [...]
You can't rely on invoking the compiler to link these objects, because if you're using shared libraries, it will be the OS's dynamic linker that will get invoked to resolve the references, and different versions of shared libraries may have a different set of TypeInfo's, and the compiler may not be able to generate the required TypeInfo's. A better way is to use the OS linker's "weak symbol" feature, where a symbol is allowed to be defined multiple times (with identical content), and the linker (both dynamic and static) will choose the first definition that it finds.
However weak symbol overriding is deprecated on Linux (see ld.so(8)). If we want to go all out to solve this problem, there are clearly solutions. But for now there doesn't seem to be enough benefit to justify the amount of work needed.
 T
Mar 10 2016