digitalmars.D - One step out of the TypeInfo stalemate
- Andrei Alexandrescu (16/16) Jul 25 2020 I think this has been attempted before. The TypeInfo* classes in
- Stefan Koch (4/7) Jul 25 2020 We should just complete the type info and increase the usefulness.
- Andrei Alexandrescu (2/10) Jul 25 2020 This is not proposing removal.
- Timon Gehr (2/4) Jul 25 2020 What prevents putting it into the static data segment?
- Andrei Alexandrescu (13/18) Jul 25 2020 Great idea. That can be done in the function, like here:
- drathier (8/13) Jul 25 2020 As a developer currently writing a compiler in Haskell that
- Andrei Alexandrescu (7/28) Jul 26 2020 Progress on this:
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (9/15) Jul 27 2020 This might be of help in the process
- Andrei Alexandrescu (14/45) Jul 27 2020 Walter and I figured starting with Typeinfo_Struct is difficult, so we
- Andrei Alexandrescu (5/5) Jul 28 2020 More progress - now __typeid comes with statically-typed overloads, so
- Adam D. Ruppe (7/11) Jul 28 2020 What's potentially interesting here is you *might* be able to add
- Andrei Alexandrescu (8/18) Jul 28 2020 At least in some cases you can use someTypeid.toString inside a mixin.
- Andrei Alexandrescu (3/11) Jul 28 2020 Added:
- Alexandru Ermicioi (24/31) Jul 28 2020 That would make typeinfo hierarchy a lot cleaner.
- Paul Backus (8/18) Jul 29 2020 Well, just about anything is better than the current __traits
- Alexandru Ermicioi (5/27) Jul 29 2020 Yep, true. Though, there is already a proper place for such
- Paul Backus (9/24) Jul 29 2020 The main disadvantage of using TypeInfo for this is that it
- rikki cattermole (5/7) Jul 29 2020 If it is templated with the type which then generates the member fields
- Alexandru Ermicioi (3/8) Jul 29 2020 Not switching, but moving. There are some methods that would
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
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
On 7/25/20 1:11 PM, Stefan Koch wrote:On Saturday, 25 July 2020 at 16:34:07 UTC, Andrei Alexandrescu wrote:This is not proposing removal.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
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
On 7/25/20 1:31 PM, Timon Gehr wrote:On 25.07.20 18:34, Andrei Alexandrescu wrote: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.`.object.__getTypeInfo!MyStruct()`. That function uses a singleton with lazy allocation.What prevents putting it into the static data segment?
Jul 25 2020
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
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
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
On 7/26/20 11:31 PM, Andrei Alexandrescu wrote:On 7/25/20 12:34 PM, Andrei Alexandrescu wrote: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.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 27 2020
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
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
On 7/28/20 10:33 AM, Adam D. Ruppe wrote:On Tuesday, 28 July 2020 at 14:28:09 UTC, Andrei Alexandrescu wrote: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).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.Yes, great idea to keep an eye out for. Thanks.
Jul 28 2020
On 7/28/20 10:33 AM, Adam D. Ruppe wrote:On Tuesday, 28 July 2020 at 14:28:09 UTC, Andrei Alexandrescu wrote:Added: https://github.com/dlang/druntime/pull/3174/files#diff-a68e58fcf0de5aa198fcaceafe4e8cf9R441More 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.
Jul 28 2020
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
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
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: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.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
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: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.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
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
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