Jump to page: 1 2
Thread overview
typeof(func!0) != typeof(func!0())
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Ali Çehreli
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
JG
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Paul Backus
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Paul Backus
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Paul Backus
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Paul Backus
Aug 22, 2022
Andrey Zherikov
Aug 22, 2022
Paul Backus
August 22, 2022

I have this simple code:

struct U
{
    auto ref func(int i)() { return this; }
}

void main()
{
    {
        alias type = typeof(U().func!0);
        pragma(msg, type);  		// pure nothrow @nogc ref @safe U() return
        pragma(msg, is(type : U));  // false

        auto u = U().func!0;
        pragma(msg, typeof(u));		// U
    }
    {
        alias type = typeof(U().func!0());
        pragma(msg, type);  		// U
        pragma(msg, is(type : U));  // true

        auto u = U().func!0();
        pragma(msg, typeof(u));		// U
    }
}

Why does typeof(U().func!0) != U? How can I check that the returned value has type U in this case?

August 21, 2022
On 8/21/22 21:39, Andrey Zherikov wrote:

>          alias type = typeof(U().func!0);
>          pragma(msg, type);          // pure nothrow @nogc ref @safe U()
> return

This is where the @property keyword makes a difference:

    @property auto ref func(int i)() { return this; }

Now U().func!0 will be a call in your expression. But @property is not recommended (deprecated?).

But I think std.traits.ReturnType is more explicit and does work in this case:

        import std.traits;
        alias type = ReturnType!(U().func!0);

Ali

August 22, 2022

On Monday, 22 August 2022 at 04:39:18 UTC, Andrey Zherikov wrote:

>

I have this simple code:

struct U
{
    auto ref func(int i)() { return this; }
}

void main()
{
    {
        alias type = typeof(U().func!0);
        pragma(msg, type);  		// pure nothrow @nogc ref @safe U() return
        pragma(msg, is(type : U));  // false

        auto u = U().func!0;
        pragma(msg, typeof(u));		// U
    }
    {
        alias type = typeof(U().func!0());
        pragma(msg, type);  		// U
        pragma(msg, is(type : U));  // true

        auto u = U().func!0();
        pragma(msg, typeof(u));		// U
    }
}

Why does typeof(U().func!0) != U? How can I check that the returned value has type U in this case?

Why not just change to:
alias type = typeof(U().func!0());

August 22, 2022

On Monday, 22 August 2022 at 05:25:50 UTC, Ali Çehreli wrote:

>

This is where the @property keyword makes a difference:

@property auto ref func(int i)() { return this; }

Now U().func!0 will be a call in your expression.

Is original U().func!0 not a call?

>

But I think std.traits.ReturnType is more explicit and does work in this case:

    import std.traits;
    alias type = ReturnType!(U().func!0);

This works but looks strange - I'm checking the type of UDA expression:

@(U().func!0) int b;

pragma(msg, __traits(getAttributes, b));             		// tuple(U().func)
pragma(msg, typeof(__traits(getAttributes, b)[0]));  		// pure nothrow @nogc ref @safe U() return
pragma(msg, ReturnType!(__traits(getAttributes, b)[0]));  	// U
pragma(msg, is(typeof(__traits(getAttributes, b)[0]) : U)); // false
pragma(msg, hasUDA!(b, U));                          		// false
August 22, 2022

On Monday, 22 August 2022 at 06:01:11 UTC, JG wrote:

>

Why not just change to:
alias type = typeof(U().func!0());

This is user's code and U().func!0 is legit syntax.

August 22, 2022

On Monday, 22 August 2022 at 11:24:59 UTC, Andrey Zherikov wrote:

>

On Monday, 22 August 2022 at 06:01:11 UTC, JG wrote:

>

Why not just change to:
alias type = typeof(U().func!0());

This is user's code and U().func!0 is legit syntax.

Workaround: wrap it in a lambda.

import std.traits;

alias type = ReturnType!(() => U().func!0);
August 22, 2022

On 8/22/22 8:04 AM, Paul Backus wrote:

>

On Monday, 22 August 2022 at 11:24:59 UTC, Andrey Zherikov wrote:

>

On Monday, 22 August 2022 at 06:01:11 UTC, JG wrote:

>

Why not just change to:
alias type = typeof(U().func!0());

This is user's code and U().func!0 is legit syntax.

Workaround: wrap it in a lambda.

import std.traits;

alias type = ReturnType!(() => U().func!0);

Or without having to import phobos:

alias type = typeof((() => U().func!0)());

I actually created a small utility for this in my code:

auto ref eval(T)(auto ref T expr) { return expr; }

so now I can just do:

alias type = typeof(eval(U().func!0)));

-Steve

August 22, 2022

On Monday, 22 August 2022 at 12:04:09 UTC, Paul Backus wrote:

>

On Monday, 22 August 2022 at 11:24:59 UTC, Andrey Zherikov wrote:

>

On Monday, 22 August 2022 at 06:01:11 UTC, JG wrote:

>

Why not just change to:
alias type = typeof(U().func!0());

This is user's code and U().func!0 is legit syntax.

Workaround: wrap it in a lambda.

import std.traits;

alias type = ReturnType!(() => U().func!0);

My situation is that user can write some UDA expression and I'm checking whether it's of a type U using hasUDA!(sym, U) and getUDAs!(sym, U). Is the users uses U() or U().func!0(), everything works. But U().func!0 does not because its type is not U. So to handle this use case it seems I need to implement my own hasUDA and getUDAs based on
ReturnType.

August 22, 2022

But the question is still opened: why is typeof(U().func!0) not the same as typeof(U().func!0())?

There is also inconsistency within UFCS - type depends on whether function is a member or standalone (even if I replace auto ref with ref U):

struct U
{
    ref U func(int i)() { return this; }
}
ref U func2(int i)(ref U u) { return u; }

void main()
{
    U u;
    pragma(msg, typeof(u.func!0));	// pure nothrow @nogc ref @safe U() return
    pragma(msg, typeof(u.func2!0));	// U
}
August 22, 2022

On Monday, 22 August 2022 at 14:42:10 UTC, Andrey Zherikov wrote:

>

My situation is that user can write some UDA expression and I'm checking whether it's of a type U using hasUDA!(sym, U) and getUDAs!(sym, U). Is the users uses U() or U().func!0(), everything works. But U().func!0 does not because its type is not U. So to handle this use case it seems I need to implement my own hasUDA and getUDAs based on
ReturnType.

My first instinct is to say that this is the user's mistake. UDAs are not evaluated like normal expressions, and anyone using UDAs is going to have to learn that sooner or later.

That said, if you want to try and present a nicer API, my recommendation would be to accept either (a) an instance of U, or (b) a callable that returns a U, which you can do with code like the following:

import std.traits, std.meta;

enum isOrReturnsU(alias attr) = is(typeof(attr) == U) || is(typeof(attr()) == U);
alias getMyUDAs(alias sym) = Filter!(isOrReturnsU, getUDAs!sym);

Or if you want to generalize to arbitrary predicates:

alias filterUDAs(alias sym, alias pred) = Filter!(pred, getUDAs!sym);
« First   ‹ Prev
1 2