September 24, 2020
On 9/24/20 11:59 AM, Stefan Koch wrote:
> On Thursday, 24 September 2020 at 15:57:03 UTC, Stefan Koch wrote:
>> On Thursday, 24 September 2020 at 15:54:55 UTC, Adam D. Ruppe wrote:
>>> On Thursday, 24 September 2020 at 14:36:45 UTC, Stefan Koch wrote:
>>>> Let me show you the code that does only typeid.name
>>>
>>> What if TypeInfo was templated instead of magically generated? So the compiler doesn't need to do all this stuff.
>>
>> You still have to instantiate all those templates and do it correctly.
>> Which means the compiler needs some way of exposing all the information via the templates system.
>>
>> Which essentially requires the same code.
> 
> Oh and typeinfo has to be generated eagerly!
> Whereas the current way it works with ctfe is lazy.
> Which means as long as nothing else requires typeinfo, using it at CTFE does not require you to generate it.
> So code that only uses type info at ctfe does compile with -betterC.

Actually it works to generate typeinfo objects lazily, on demand. I was quite surprised about how nicely that works as I was working on https://github.com/dlang/druntime/pull/3174/files.

I sketched something here:

https://run.dlang.io/is/PjRo9w

The code compiles and evaluates correctly during compilation. The URL shortener seems to have problems so I'll also paste the code below:

// Base class for CT and RT type information.
immutable abstract class NewTypeInfo {
    size_t tsize();
}

// Implementation for given type T.
immutable class NewTypeInfoImpl(T) : NewTypeInfo {
    override size_t tsize() {
        return T.sizeof;
    }
}

// Use __typeid!T to get a singleton object associated with type T.
@property immutable(NewTypeInfo) __typeid(T)() {
    static immutable singleton = new NewTypeInfoImpl!T;
    return singleton;
}

auto static_map_tf(alias F)(immutable NewTypeInfo[] types...)
{
    typeof(F(types[0]))[] result;
    result.length = types.length;
    foreach(i, t; types)
    {
        result[i] = F(t);
    }
    return result;
}

static assert(static_map_tf!(t => t.tsize)(__typeid!int, __typeid!ushort) == [4, 2]);

void main() {}

September 24, 2020
On Thursday, 24 September 2020 at 16:33:37 UTC, Andrei Alexandrescu wrote:
> On 9/24/20 11:59 AM, Stefan Koch wrote:
>> On Thursday, 24 September 2020 at 15:57:03 UTC, Stefan Koch wrote:
>>> On Thursday, 24 September 2020 at 15:54:55 UTC, Adam D. Ruppe wrote:
>>>> On Thursday, 24 September 2020 at 14:36:45 UTC, Stefan Koch wrote:
>>>>> Let me show you the code that does only typeid.name
>>>>
>>>> What if TypeInfo was templated instead of magically generated? So the compiler doesn't need to do all this stuff.
>>>
>>> You still have to instantiate all those templates and do it correctly.
>>> Which means the compiler needs some way of exposing all the information via the templates system.
>>>
>>> Which essentially requires the same code.
>> 
>> Oh and typeinfo has to be generated eagerly!
>> Whereas the current way it works with ctfe is lazy.
>> Which means as long as nothing else requires typeinfo, using it at CTFE does not require you to generate it.
>> So code that only uses type info at ctfe does compile with -betterC.


You still have the problem of spamming the executable with those type-info objects.
And you have the problem of having to eagerly generate the entire object.
Rather than just having the partial information appear which is actually required for the evaluation.

September 24, 2020
Actually I just realized no need to rewrite the map algorithm. Given that we're dealing with bona fide objects, all algorithms in std work out of the box. This compiles and runs:

https://run.dlang.io/is/TprA9u

==========================

import std;

// Base class for CT and RT type information.
immutable abstract class NewTypeInfo {
    size_t tsize();
}

// Implementation for given type T.
immutable class NewTypeInfoImpl(T) : NewTypeInfo {
    override size_t tsize() {
        return T.sizeof;
    }
}

// Use __typeid!T to get a singleton object associated with type T.
@property immutable(NewTypeInfo) __typeid(T)() {
    static immutable singleton = new NewTypeInfoImpl!T;
    return singleton;
}

static assert([__typeid!int, __typeid!ushort].map!(t => t.tsize).equal([4, 2]));

void main() {}

September 24, 2020
On Thursday, 24 September 2020 at 16:41:26 UTC, Andrei Alexandrescu wrote:
> Actually I just realized no need to rewrite the map algorithm. Given that we're dealing with bona fide objects, all algorithms in std work out of the box. This compiles and runs:
>
> https://run.dlang.io/is/TprA9u
>
> ==========================
>
> import std;
>
> // Base class for CT and RT type information.
> immutable abstract class NewTypeInfo {
>     size_t tsize();
> }
>
> // Implementation for given type T.
> immutable class NewTypeInfoImpl(T) : NewTypeInfo {
>     override size_t tsize() {
>         return T.sizeof;
>     }
> }
>
> // Use __typeid!T to get a singleton object associated with type T.
> @property immutable(NewTypeInfo) __typeid(T)() {
>     static immutable singleton = new NewTypeInfoImpl!T;
>     return singleton;
> }
>
> static assert([__typeid!int, __typeid!ushort].map!(t => t.tsize).equal([4, 2]));
>
> void main() {}

Now all you have to do is to be able to use the type member of the typeid template upon returning from the function.
And you're at feature parity with type functions.

That however requires a TOP-type container, which is alias[] :)
September 24, 2020
On Thursday, 24 September 2020 at 16:19:34 UTC, Adam D. Ruppe wrote:
> On Thursday, 24 September 2020 at 15:59:51 UTC, Stefan Koch wrote:
>> Oh and typeinfo has to be generated eagerly!
>> Whereas the current way it works with ctfe is lazy.
>
> Eh, if it is unreferenced except at CTFE the linker can strip it from the binary (the ctfe functions of course would have to be marked as discardable/ctfe-only)
>
> I'll try to make a test in library later when I'm free. I'm barely able to type these emails and chat messages while holding the baby, lol two-handed typing is more important to programming than I like to admit.

Congratulations to your new family member Adam.

Also here holding little child while writing :)

Kind regards
Andre
September 24, 2020
Andrei beat me to the test implementation, it is good it kinda works.

On Thursday, 24 September 2020 at 16:40:21 UTC, Stefan Koch wrote:
> You still have the problem of spamming the executable with those type-info objects.

linker can strip that.

> And you have the problem of having to eagerly generate the entire object.

Yeah, this is a potential major limitation: you can only use the data available there. But you could define your own classes that provide new data (can we have CTFE only classes as well as functions?!) as well as limit data you don't need.

Would be a new templated class instance per type which MIGHT runaway but not too bad.

But like you said in the other message the other issue is getting the original type T back out of the polymorphic typeinfo interface... if you need it. But maybe you could still have one template returning that and just using typeinfo for its internal intermediate calculations. (TypeInfo -> T can be done for a limited set by linear search. You cant pass a class instance as a template argument (alas... that restriction could *perhaps* be lifted in general tho), but one of the virtual methods could return a numeric id or string that is an index into a limited list of options.

```
class MyTypeInfo { immutable this(string name) { this.name = name; } string name;}

template mytypeid(T) {
        static immutable MyTypeInfo store = new immutable MyTypeInfo(T.stringof);
        immutable(MyTypeInfo) mytypeid() { return store; }
}

template Tof(string name) {
        alias Tof = mixin(name);
}

immutable(MyTypeInfo) getTheString(immutable MyTypeInfo a, immutable MyTypeInfo b) {
        if(a is mytypeid!string)
                return a;
        return b;
}

void main() {
        Tof!(mytypeid!(int).name) i;
        static assert(is(typeof(i) == int));
        i = 4;

        Tof!(getTheString(mytypeid!int, mytypeid!string).name) s;
        static assert(is(typeof(s) == string));
}
```


Obviously the stringof and mixin stuff does NOT work in general, as I talk about every chance I get (DON'T USE STRINGOF!!!!!), but the general approach here is plausible... at least given a limited set of options going into it.
September 25, 2020
On Thursday, 24 September 2020 at 10:08:30 UTC, Timon Gehr wrote:
> 
> It means your programming language lacks features to write the code in a better way. Note that D templates form a very ugly programming language with a semantics that is hard to implement efficiently.

Hello Timon,

I didn't notice your reply, when you gave it.
Thanks for expressing the concern so clearly.

Last time we talked about type functions on here,
you said they'd have to be able to replace templates in all circumstances,
(i.e. be able to actually create new types)
do you think so still?

Greetings,

Stefan
September 25, 2020
On 9/24/20 3:00 PM, Adam D. Ruppe wrote:
> But maybe you could still have one template returning that and just using typeinfo for its internal intermediate calculations.

Yah, looking at the ilk of std.meta and std.traits it seems that the more complicated items in there would be done like this:

1. Convert the type(s) into TypeInfo(s)
2. Use everyday algorithms (including std) to carry computation
3. If needed, convert the result(s) back into TypeInfo(s)

BTW, this process is akin to reification: https://en.wikipedia.org/wiki/Reification_(computer_science).

For TypeInfo objects, by far the most frequent operations will be to copy them around and to compare them for equality. Then there are a few more things necessary:

*    add a qualifier to a type
*    strip a qualifier from a type
*    strip all qualifiers from a type
*    are two types equal?
*    is type1 implicitly convertible to type2?
*    if function, give me the return type and the parameter types

So we'd need to add these primitives to TypeInfo. They all must be computable during compilation:

class TypeInfo {
    ... existing stuff ...
    TypeInfo addQualifier(string qual);
    TypeInfo stripQualifier(string qualifier);
    TypeInfo stripAllQualifiers();
    bool implicitlyConvertsTo(Typeinfo another);
    TypeInfo functionReturn(); // null if not a function
    Typeinfo[] functionParameters(); // null if not a function
}

This and a solution to https://issues.dlang.org/show_bug.cgi?id=9945 would impart tremendous power.
September 26, 2020
On Friday, 25 September 2020 at 13:33:29 UTC, Andrei Alexandrescu wrote:

> class TypeInfo {
>     ... existing stuff ...
>     TypeInfo addQualifier(string qual);
>     TypeInfo stripQualifier(string qualifier);
>     TypeInfo stripAllQualifiers();
>     bool implicitlyConvertsTo(Typeinfo another);
>     TypeInfo functionReturn(); // null if not a function
>     Typeinfo[] functionParameters(); // null if not a function
> }

having a string for the qualifier isn't great.
I'd much prefer an enum since the qualifier is a rightly bounded set of possible values.

Similarly I'd like to avoid polymorphic behavior as much as possible.
(It might still have to be polymorphic to work at all, but polyorphism should be as you would say 'curtailed' )


> This and a solution to https://issues.dlang.org/show_bug.cgi?id=9945 would impart tremendous power.

The solution in there is polymorphic.
It comes with all the problems of understandably and unpredictability that polymorphic "solutions" come with.

One of the reasons why type functions can be fast and easily be reasoned about is their non concrete monomorphic interface.

By removing the notion of a concrete interface the interaction with the compiler can be more efficient and direct.

And it also allows us to reuse existing language concepts such as ".sizeof", ".tupleof", ".stringof" on the surface.

By adding the notion of monomorphsim (alias can't convert to any other type) we achieve type safety and static checking.

type functions (a misnomer really, because they can work with more than just types) are designed to occupy a functional and syntactic middle-ground between templates and functions.

perhaps I should rename them to "compiletime entity introspection functions" CTEIF, but that acronym is unpronounceable

or I could call them "static template emulating function and namespace" STEFAN? :D
September 28, 2020
On Saturday, 26 September 2020 at 09:56:15 UTC, Stefan Koch wrote:
> or I could call them "static template emulating function and namespace" STEFAN? :D

Yay! That's so cute...
1 2 3 4 5 6 7
Next ›   Last »