Jump to page: 1 2 3
Thread overview
I've just fixed UFCS for the experimental type function branch
Sep 11
jmh530
Sep 11
Meta
Sep 10
Meta
Sep 10
Meta
Sep 10
jmh530
September 10
Hi there,

just a quick update.
limited UFCS for type functions works again.
i.e.

this code:

---
struct S1 { double[2] x; }

static assert(S1.sizeOf == S1.sizeof);

size_t sizeOf(alias t)
{
    return t.sizeof;
}
---

will work.

There are a few caveats in the current POC implementation of type-function UFCS, which mean this will only apply to single type variables (`alias x;`)
and not to arrays of them, it also won't work for structures which have alias variable members.

If you want to play with it, the code is downloadable at:
https://github.com/UplinkCoder/dmd/tree/talias_master

which contains the type function changes applied on a current dmd ~master.

Happy Hacking,

Stefan
September 10
On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
> just a quick update.
> limited UFCS for type functions works again.

Very nice.

To gain momentum and motivation in adding more features how about starting to maintain a druntime and phobos branch where all the traits that can be expressed with current state of talias branch are converted to alias functions?
September 10
On Thursday, 10 September 2020 at 13:55:06 UTC, Per Nordlöw wrote:
> On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
>> just a quick update.
>> limited UFCS for type functions works again.
>
> Very nice.
>

Indeed.  Type functions look like a very promising lowering: a new base functionality that can be used to reduce complexity in both the compiler and, much more importantly, in all future meta programs.

September 10
On Thursday, 10 September 2020 at 14:14:30 UTC, Bruce Carneal wrote:
> On Thursday, 10 September 2020 at 13:55:06 UTC, Per Nordlöw wrote:
>> On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
>>> just a quick update.
>>> limited UFCS for type functions works again.
>>
>> Very nice.
>>
>
> Indeed.  Type functions look like a very promising lowering: a new base functionality that can be used to reduce complexity in both the compiler and, much more importantly, in all future meta programs.

More accurately, the *addition* of type functions to the compiler will, necessarily, increase the complexity of the compiler in trade for complexity reduction in many future meta programs.



September 10
On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
> limited UFCS for type functions works again.

Having type functions with UFCS is a significant improvement of the developer experience aswell compared to having to use templates.
September 10
On Thursday, 10 September 2020 at 15:14:00 UTC, Per Nordlöw wrote:
> On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
>> limited UFCS for type functions works again.
>
> Having type functions with UFCS is a significant improvement of the developer experience aswell compared to having to use templates.

Absolutely.  Functions are more readable, compose more readily, are easier to debug (better locality), and tickle fewer compiler problems than templates.  CTFE is a huge win overall, "it just works".

By contrast, when using D's pattern matching meta programming sub-language, things start out very nicely but rapidly progress to "it probably works, but you'll have a devil of a time debugging it if it actually doesn't, and you may not know that it doesn't for a few years, best of luck".

In a type function world we'll still need templates, we'll just need fewer of them.

September 10
On Thu, Sep 10, 2020 at 04:28:46PM +0000, Bruce Carneal via Digitalmars-d wrote:
> On Thursday, 10 September 2020 at 15:14:00 UTC, Per Nordlöw wrote:
> > On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
> > > limited UFCS for type functions works again.
> > 
> > Having type functions with UFCS is a significant improvement of the developer experience aswell compared to having to use templates.
> 
> Absolutely.  Functions are more readable, compose more readily, are easier to debug (better locality), and tickle fewer compiler problems than templates.  CTFE is a huge win overall, "it just works".

I wouldn't be so sure about that last part. The current CTFE implementation is, shall we say, hackish at best?  It "works" by operating on AST nodes as if they were values, and is slow, memory inefficient, and when there are problems, it's a nightmare to debug. For small bits of code, it works wonderfully, but it's not at all scalable: try some non-trivial CTFE and pretty soon your compile times will be skyrocketing, if the compiler manages to finish its job at all before being killed by the kernel OOM killer for gobbling too much memory. (Of course, templates, esp. the recursive kind, are mostly to blame for this, but CTFE isn't exactly an innocent bystander when it comes to memory hoggage.)


> By contrast, when using D's pattern matching meta programming sub-language, things start out very nicely but rapidly progress to "it probably works, but you'll have a devil of a time debugging it if it actually doesn't, and you may not know that it doesn't for a few years, best of luck".

To be fair, the problems really only arise with IFTI and a few other isolated places in D's template system.  In other respects, D templates are wonderfully nice to work with.  Definitely a refreshing change from the horror show that is C++ templates.


> In a type function world we'll still need templates, we'll just need fewer of them.

Generally, I'm in favor of this. Templates have their place, but in many type manipulation operations, type functions are definitely better than truckloads of recursive template instantiations with their associated memory hoggage and slowdown of compile times.


T

-- 
English has the lovely word "defenestrate", meaning "to execute by throwing someone out a window", or more recently "to remove Windows from a computer and replace it with something useful". :-) -- John Cowan
September 10
On Thursday, 10 September 2020 at 09:43:34 UTC, Stefan Koch wrote:
> Hi there,
>
> just a quick update.
> limited UFCS for type functions works again.
> i.e.
>
> this code:
>
> ---
> struct S1 { double[2] x; }
>
> static assert(S1.sizeOf == S1.sizeof);
>
> size_t sizeOf(alias t)
> {
>     return t.sizeof;
> }
> ---
>
> will work.

I'm curious, will this also work?

size_t sizeOf(alias t)
{
    size_t result;
    /* static? */ if (__traits(isScalar))
    {
        static if (is(t == int))
            result += 32;
        else static if (...)
        ...
    }
    else static if (is(t == A[n], A, size_t n))
        result += A.sizeOf * n
    else static if (...)
        ...
    else
        /* static? */ foreach (field; t.tupleof)
            result += field.sizeOf

    return result;
}

Basically, is the implementation at a level where sizeOf can be turtles all the way down, with minimal or no reliance on __traits?
September 10
On Thursday, 10 September 2020 at 17:05:02 UTC, Meta wrote:
>
> I'm curious, will this also work?
>
> size_t sizeOf(alias t)
> {
>     size_t result;
>     /* static? */ if (__traits(isScalar))
>     {
>         static if (is(t == int))
>             result += 32;
>         else static if (...)
>         ...
>     }
>     else static if (is(t == A[n], A, size_t n))
>         result += A.sizeOf * n
>     else static if (...)
>         ...
>     else
>         /* static? */ foreach (field; t.tupleof)
>             result += field.sizeOf
>
>     return result;
> }
>
> Basically, is the implementation at a level where sizeOf can be turtles all the way down, with minimal or no reliance on __traits?

One thing built-in .sizeof does that no user-code version can do is "freeze" the size of a type to prevent additional members from being added. For example, if you try to compile this code:

struct S
{
    int a;
    enum size = S.sizeof;
    mixin("int b;");
}

...you'll get an error:

onlineapp.d-mixin-5(5): Error: variable onlineapp.S.b cannot be further field because it will change the determined S size
September 10
On Thursday, 10 September 2020 at 18:05:23 UTC, Paul Backus wrote:
> On Thursday, 10 September 2020 at 17:05:02 UTC, Meta wrote:
>>
>> I'm curious, will this also work?
>>
>> size_t sizeOf(alias t)
>> {
>>     size_t result;
>>     /* static? */ if (__traits(isScalar))
>>     {
>>         static if (is(t == int))
>>             result += 32;
>>         else static if (...)
>>         ...
>>     }
>>     else static if (is(t == A[n], A, size_t n))
>>         result += A.sizeOf * n
>>     else static if (...)
>>         ...
>>     else
>>         /* static? */ foreach (field; t.tupleof)
>>             result += field.sizeOf
>>
>>     return result;
>> }
>>
>> Basically, is the implementation at a level where sizeOf can be turtles all the way down, with minimal or no reliance on __traits?
>
> One thing built-in .sizeof does that no user-code version can do is "freeze" the size of a type to prevent additional members from being added. For example, if you try to compile this code:
>
> struct S
> {
>     int a;
>     enum size = S.sizeof;
>     mixin("int b;");
> }
>
> ...you'll get an error:
>
> onlineapp.d-mixin-5(5): Error: variable onlineapp.S.b cannot be further field because it will change the determined S size

It looks like it depends on the order of fields:

struct S
{
    int a;
    mixin("int b;"); //No error
    enum size = S.sizeof;
}

Ideally `enum size = S.sizeof` could be delayed until after all mixins are "evaluated" (is that during one of the semantic phases? I don't know much about how DMD actually works), but I imagine that would take some major re-architecting. Really though, is it even necessary to be able to "freeze" a type like this when evaluating type functions?
« First   ‹ Prev
1 2 3