www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - One step out of the TypeInfo stalemate

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I think this has been attempted before. The TypeInfo* classes in 
object.d are one gnarly thing after another:

https://github.com/dlang/druntime/blob/master/src/object.d

Very poor usefulness to real estate ratio, ugly and inefficient 
implementation, etc. etc.

One simple step out of this would be to replace TypeInfo_Struct with a 
template TypeInfo(T) if (is(T == struct)). Then expressions such as 
`typeid(MyStruct)` would be lowered to 
`.object.__getTypeInfo!MyStruct()`. That function uses a singleton with 
lazy allocation.

That means for all structs the compiler does not need to generate 
TypeInfo_Struct objects, and the implementation of the primitives is 
simpler and more efficient.

We can't do exactly this for classes because typeid(obj) is dynamic, so 
it requires a virtual call. But there are other ideas we can use there 
as well.
Jul 25 2020
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 25 July 2020 at 16:34:07 UTC, Andrei Alexandrescu 
wrote:
 I think this has been attempted before. The TypeInfo* classes 
 in object.d are one gnarly thing after another:

 [...]
We should just complete the type info and increase the usefulness. Removing it makes very little sense to me.
Jul 25 2020
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/25/20 1:11 PM, Stefan Koch wrote:
 On Saturday, 25 July 2020 at 16:34:07 UTC, Andrei Alexandrescu wrote:
 I think this has been attempted before. The TypeInfo* classes in 
 object.d are one gnarly thing after another:

 [...]
We should just complete the type info and increase the usefulness. Removing it makes very little sense to me.
This is not proposing removal.
Jul 25 2020
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 25.07.20 18:34, Andrei Alexandrescu wrote:
 `.object.__getTypeInfo!MyStruct()`. That function uses a singleton with 
 lazy allocation.
What prevents putting it into the static data segment?
Jul 25 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/25/20 1:31 PM, Timon Gehr wrote:
 On 25.07.20 18:34, Andrei Alexandrescu wrote:
 `.object.__getTypeInfo!MyStruct()`. That function uses a singleton 
 with lazy allocation.
What prevents putting it into the static data segment?
Great idea. That can be done in the function, like here: https://github.com/dlang/phobos/blob/master/std/experimental/allocator/package.d#L996 The overriding principle is take out trickery and magic out of the compiler and imbue the language itself with the power to express such things. Ideally the compiler would be a consistent lowering machine to a small core language with carefully defined semantics. Haskell does that: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/compiler/core-syn-type It seems our community is favorable of the notion but the attitude has not quite dyed in our wool yet. Walter himself is not yet 100% there. If we value that, typeid(Type) and typeid(expression) would lower to one of the simpler known expressions - a function call that requires no special compiler support.
Jul 25 2020
parent drathier <forum.dlang.org fi.fo> writes:
On Saturday, 25 July 2020 at 18:28:46 UTC, Andrei Alexandrescu 
wrote:
 The overriding principle is take out trickery and magic out of 
 the compiler and imbue the language itself with the power to 
 express such things. Ideally the compiler would be a consistent 
 lowering machine to a small core language with carefully 
 defined semantics. Haskell does that:
As a developer currently writing a compiler in Haskell that outputs D code, this is something I wish D had years ago. A small well-defined core, with the restriction that any and all new features must be able to compile to the same core, means that it's much much harder to add new edge-cases and gotchas to the language.
Jul 25 2020
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/25/20 12:34 PM, Andrei Alexandrescu wrote:
 I think this has been attempted before. The TypeInfo* classes in 
 object.d are one gnarly thing after another:
 
 https://github.com/dlang/druntime/blob/master/src/object.d
 
 Very poor usefulness to real estate ratio, ugly and inefficient 
 implementation, etc. etc.
 
 One simple step out of this would be to replace TypeInfo_Struct with a 
 template TypeInfo(T) if (is(T == struct)). Then expressions such as 
 `typeid(MyStruct)` would be lowered to 
 `.object.__getTypeInfo!MyStruct()`. That function uses a singleton with 
 lazy allocation.
 
 That means for all structs the compiler does not need to generate 
 TypeInfo_Struct objects, and the implementation of the primitives is 
 simpler and more efficient.
 
 We can't do exactly this for classes because typeid(obj) is dynamic, so 
 it requires a virtual call. But there are other ideas we can use there 
 as well.
Progress on this: https://github.com/dlang/dmd/pull/11459/ https://github.com/dlang/druntime/pull/3172 Next step is to templatize the associative array primitives, which resort to horrendous tricks exactly because they lack static type information.
Jul 26 2020
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 27 July 2020 at 03:31:26 UTC, Andrei Alexandrescu 
wrote:
 Progress on this:

 https://github.com/dlang/dmd/pull/11459/
 https://github.com/dlang/druntime/pull/3172

 Next step is to templatize the associative array primitives, 
 which resort to horrendous tricks exactly because they lack 
 static type information.
This might be of help in the process https://github.com/dlang/dmd/pull/11463 It is however designed to make it easier to pin down source of unnecessary template instances triggered by `-unittest` when building import std; .
Jul 27 2020
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/26/20 11:31 PM, Andrei Alexandrescu wrote:
 On 7/25/20 12:34 PM, Andrei Alexandrescu wrote:
 I think this has been attempted before. The TypeInfo* classes in 
 object.d are one gnarly thing after another:

 https://github.com/dlang/druntime/blob/master/src/object.d

 Very poor usefulness to real estate ratio, ugly and inefficient 
 implementation, etc. etc.

 One simple step out of this would be to replace TypeInfo_Struct with a 
 template TypeInfo(T) if (is(T == struct)). Then expressions such as 
 `typeid(MyStruct)` would be lowered to 
 `.object.__getTypeInfo!MyStruct()`. That function uses a singleton 
 with lazy allocation.

 That means for all structs the compiler does not need to generate 
 TypeInfo_Struct objects, and the implementation of the primitives is 
 simpler and more efficient.

 We can't do exactly this for classes because typeid(obj) is dynamic, 
 so it requires a virtual call. But there are other ideas we can use 
 there as well.
Progress on this: https://github.com/dlang/dmd/pull/11459/ https://github.com/dlang/druntime/pull/3172 Next step is to templatize the associative array primitives, which resort to horrendous tricks exactly because they lack static type information.
Walter and I figured starting with Typeinfo_Struct is difficult, so we scaled down to the simplest: typeid(int). Take a look at: https://github.com/dlang/druntime/pull/3174 The idea is to lower typeid(int) to __typeid!(int) and it all works nicely. We can then start generalizing from there. The code generation, putting the object in storage with static duration, all is done with standard language mechanisms. One unexpected perk is that some functions now work during compilation. For example, with the old implementation this doesn't work: static assert(typeid(int).toString == "int"); However, this does work: static assert(__typeid!int.toString == "int"); which is pretty awesome. Others do, too - take a look at the unittest.
Jul 27 2020
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
More progress - now __typeid comes with statically-typed overloads, so 
whenever T is statically known, typeid(T).whatever() will pick an 
efficient inlined implementation instead of a virtual call. So TypeInfo 
becomes useful for static manipulation as well.

https://github.com/dlang/druntime/pull/3174/files
Jul 28 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 28 July 2020 at 14:28:09 UTC, Andrei Alexandrescu 
wrote:
 More progress - now __typeid comes with statically-typed 
 overloads, so whenever T is statically known, 
 typeid(T).whatever() will pick an efficient inlined 
 implementation instead of a virtual call.
What's potentially interesting here is you *might* be able to add an alias StaticType = T in there and then do some pseudo-type manipulation in CTFE then get the original type back out. Probably not there yet and might never get there but I think it would be cool if it did somehow work at some point.
Jul 28 2020
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/28/20 10:33 AM, Adam D. Ruppe wrote:
 On Tuesday, 28 July 2020 at 14:28:09 UTC, Andrei Alexandrescu wrote:
 More progress - now __typeid comes with statically-typed overloads, so 
 whenever T is statically known, typeid(T).whatever() will pick an 
 efficient inlined implementation instead of a virtual call.
What's potentially interesting here is you *might* be able to add an alias StaticType = T in there and then do some pseudo-type manipulation in CTFE then get the original type back out.
At least in some cases you can use someTypeid.toString inside a mixin. Also, this: static if (typeid(T1) == typeid(T2)) becomes a viable alternative to: static if (is(T1 == T2)) Sadly it's actually longer :o).
 Probably not there yet and might never get there but I think it would be 
 cool if it did somehow work at some point.
Yes, great idea to keep an eye out for. Thanks.
Jul 28 2020
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/28/20 10:33 AM, Adam D. Ruppe wrote:
 On Tuesday, 28 July 2020 at 14:28:09 UTC, Andrei Alexandrescu wrote:
 More progress - now __typeid comes with statically-typed overloads, so 
 whenever T is statically known, typeid(T).whatever() will pick an 
 efficient inlined implementation instead of a virtual call.
What's potentially interesting here is you *might* be able to add an alias StaticType = T in there and then do some pseudo-type manipulation in CTFE then get the original type back out.
Added: https://github.com/dlang/druntime/pull/3174/files#diff-a68e58fcf0de5aa198fcaceafe4e8cf9R441
Jul 28 2020
prev sibling parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Saturday, 25 July 2020 at 16:34:07 UTC, Andrei Alexandrescu 
wrote:
 I think this has been attempted before. The TypeInfo* classes 
 in object.d are one gnarly thing after another:

 https://github.com/dlang/druntime/blob/master/src/object.d

 Very poor usefulness to real estate ratio, ugly and inefficient 
 implementation, etc. etc.

 One simple step out of this would be to replace TypeInfo_Struct 
 with a template TypeInfo(T) if (is(T == struct)).
That would make typeinfo hierarchy a lot cleaner. Having type known in typeinfo object would also allow implementation of reflection methods as members which in turn would make reflection based code much much cleaner from developer perspective. For example currently to check if member is present on type T we have to do smth like: __traits(hasMember, T, "member") When it can be more readable through typeid statement like: typeid(T).hasMember!"member" It would also be nice for typeinfo to provide both templates and non-templated alternatives for reflection operations. For example for hasMember it could also offer: typeid(T).hasMember("member") While templated methods could be used to inspect types when they are known at compile time, non-templated ones may be used to inspect entities with erased type. But this of course is not for the first step but rather one of the future ones. I hope this message provided some insight on what can be improved regarding type info, In the future. Best regards, Alexandru.
Jul 28 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 28 July 2020 at 20:37:19 UTC, Alexandru Ermicioi 
wrote:
 That would make typeinfo hierarchy a lot cleaner.
 Having type known in typeinfo object would also allow 
 implementation of reflection methods as members which in turn 
 would make reflection based code much much cleaner from 
 developer perspective.

 For example currently to check if member is present on type T 
 we have to do smth like:

 __traits(hasMember, T, "member")

 When it can be more readable through typeid statement like:

 typeid(T).hasMember!"member"
Well, just about anything is better than the current __traits syntax. IMO an easy improvement would be to provide some syntax sugar so you could write T.__hasMember("member") and the compiler would lower it to __traits(hasMember, T, "member")
Jul 29 2020
parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 29 July 2020 at 13:27:02 UTC, Paul Backus wrote:
 On Tuesday, 28 July 2020 at 20:37:19 UTC, Alexandru Ermicioi 
 wrote:
 That would make typeinfo hierarchy a lot cleaner.
 Having type known in typeinfo object would also allow 
 implementation of reflection methods as members which in turn 
 would make reflection based code much much cleaner from 
 developer perspective.

 For example currently to check if member is present on type T 
 we have to do smth like:

 __traits(hasMember, T, "member")

 When it can be more readable through typeid statement like:

 typeid(T).hasMember!"member"
Well, just about anything is better than the current __traits syntax. IMO an easy improvement would be to provide some syntax sugar so you could write T.__hasMember("member") and the compiler would lower it to __traits(hasMember, T, "member")
Yep, true. Though, there is already a proper place for such reflection logic which are type info classes, hence I think lots of methods found in std.traits could just be moved under right type info classes.
Jul 29 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 29 July 2020 at 16:46:55 UTC, Alexandru Ermicioi 
wrote:
 On Wednesday, 29 July 2020 at 13:27:02 UTC, Paul Backus wrote:
 Well, just about anything is better than the current __traits 
 syntax. IMO an easy improvement would be to provide some 
 syntax sugar so you could write

     T.__hasMember("member")

 and the compiler would lower it to

     __traits(hasMember, T, "member")
Yep, true. Though, there is already a proper place for such reflection logic which are type info classes, hence I think lots of methods found in std.traits could just be moved under right type info classes.
The main disadvantage of using TypeInfo for this is that it doesn't work without the D runtime (i.e., in BetterC). It's also a bit less efficient. A __traits expression is essentially a single function call inside the compiler. Using TypeInfo requires CTFE and/or template instantiation, so switching std.traits to it would make compile times (slightly) longer.
Jul 29 2020
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 30/07/2020 5:36 AM, Paul Backus wrote:
 The main disadvantage of using TypeInfo for this is that it doesn't work 
 without the D runtime (i.e., in BetterC).
If it is templated with the type which then generates the member fields of the TypeInfo, this doesn't matter. It is no longer the responsibility of the compiler to emit the TypeInfo members, and it can be on demand even if druntime is not linked in.
Jul 29 2020
prev sibling parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 29 July 2020 at 17:36:56 UTC, Paul Backus wrote:
 It's also a bit less efficient. A __traits expression is 
 essentially a single function call inside the compiler. Using 
 TypeInfo requires CTFE and/or template instantiation, so 
 switching std.traits to it would make compile times (slightly) 
 longer.
Not switching, but moving. There are some methods that would really make sense for them to be part of type info.
Jul 29 2020