Thread overview
Question about alias and getOverloads
Jan 28, 2020
uranuz
Jan 28, 2020
Paul Backus
Jan 28, 2020
uranuz
Jan 28, 2020
Paul Backus
Jan 28, 2020
uranuz
Jan 30, 2020
uranuz
Jan 30, 2020
H. S. Teoh
Feb 01, 2020
uranuz
Jan 30, 2020
Paul Backus
January 28, 2020
Hello! I have a question about `alias` template parameter and getOverloads.
For instance I have some code like this:
// -----
import std;
import core.thread;

void foo(string param1) {}
void foo(string param1, int param2) {}

template Bar(alias Func)
{
    // Next line is not valid now. This is my understanding of how I wish it would work...
    pragma(msg, __traits(getOverloads, Func));
}

void main()
{
    Bar!foo;
}
//---
By the spec:
https://dlang.org/spec/traits.html#getOverloads
The signature of `getOverloads` trait requires me to pass a symbol where my function is contained (it could be class, struct or module). And a name of function that I want to get overloads for.

Let's imagine that `foo` overloads and Bar template are in different modules. And `Bar` template doesn't have no direct access to module where `foo` is contained. And `Bar` is instantiated outside module where `Bar` is declared.

I have two questions:
1. Whether `Bar` instantiation would get first, second or both overloads of function? Or maybe I would get two instantiations of template by the number of overloads? I don't understand well how this mechanic is working. Is it documented somewhere? Does actually one alias parameter represents only one symbol from overload set or all of them?

2. If alias parameter represents multiple symbols from overload set. Then I wish I could access to list of overloads having alias parameter. I wish to get count of overloads in my real case in order to issue an error that overloaded are not supported by my code.



January 28, 2020
On Tuesday, 28 January 2020 at 19:26:03 UTC, uranuz wrote:
> Hello! I have a question about `alias` template parameter and getOverloads.
> For instance I have some code like this:
> // -----
> import std;
> import core.thread;
>
> void foo(string param1) {}
> void foo(string param1, int param2) {}
>
> template Bar(alias Func)
> {
>     // Next line is not valid now. This is my understanding of how I wish it would work...
>     pragma(msg, __traits(getOverloads, Func));
> }

__traits(getOverloads, __traits(parent, Func), __traits(identifier, Func))
January 28, 2020
Thanks for advice ;) This looks like some `standard trick` that is yet not learnt or forgoten by me personally. The key was in using `parent` trait. This is what I failed to think of. This is working as expected:
//-----
import std;
import core.thread;
import std.meta: AliasSeq;

void foo(string param1) {}
void foo(string param1, int param2, bool param3) {}

template Bar(alias Func)
{
    alias Bar = __traits(getOverloads, __traits(parent, Func), __traits(identifier, Func));
}

void main()
{
	import std.traits: fullyQualifiedName, Parameters;
    import std.conv: text;
    static foreach( It; Bar!foo ) {
    	pragma(msg, fullyQualifiedName!It ~ "/" ~ (Parameters!It).length.text);
    }
}
//-----
Output:
onlineapp.foo/1
onlineapp.foo/3
//-----

So as far as I understand alias template parameter gives access to all of items of overload set as I was expecting. The only problem is that I didn't found something about it in specification about templates:
https://dlang.org/spec/template.html

January 28, 2020
On Tuesday, 28 January 2020 at 19:59:15 UTC, uranuz wrote:
> So as far as I understand alias template parameter gives access to all of items of overload set as I was expecting. The only problem is that I didn't found something about it in specification about templates:
> https://dlang.org/spec/template.html

It's documented under "Alias Declaration":

> Aliases can also import a set of overloaded functions, that can be overloaded with functions in the current scope:

https://dlang.org/spec/declaration.html#alias
January 28, 2020
I have read it two or three times just before writing my question:
https://dlang.org/spec/declaration.html#alias
And also a have read all the dlang docs several time few years ago... ;)
But I don't see what do you you mean by writing that it was menioned here. I don't se any words or any examples that describe how `alias` works with function overload sets. Is it a blind assumption that it was written here?

The only example that someone can mix up and consider as answer to my question if actually didn't read it with attention. It is example bellow:
```
alias myint = int;

void foo(int x) { ... }
void foo(myint m) { ... } // error, multiply defined function foo
```
But the only thing that this example illustrates is that `myint` and `int` is actualy the same  type. So this overload set is just incorrect. I don't ask you to consider the case where overload set is incorrect. So this didn't answered my question in any way.

Looks like this is some kind of nasty details that language developers don't "proud of" and don't like to discover details about how it's working. Or just lazy enough to do so ;)

Still I figured answer myself using your example. The answer is not full, but yet enough for me for practical usage. But the lack of description about it makes me think that I am not the last man who will have his curiosity not fully satisfied about this aspect of language.

And also __traits(parent, Func) seems like not universal for all cases with functions, because it fails on lambda-functions. For instance:
//----
import std;

template Bar(alias Func) {
    alias Bar = __traits(getOverloads, __traits(parent, Func), __traits(identifier, Func));
}

void main()
{
    alias Test = Bar!(() { return `test`; });
}
//----
Output:
onlineapp.d(4): Error: no property __lambda1 for type void
onlineapp.d(4): Error: main().__lambda1 cannot be resolved
onlineapp.d(9): Error: template instance onlineapp.Bar!(function () pure nothrow @nogc @safe => "test") error instantiating
//----
Seems that it fails to get parent for lambda. I don't know why? What parent should be for labmda?

Thanks for attention!
January 30, 2020
I apologise that I need to revive this discussion again. But still I got answer to only one of my questions. I know that it is a common practice in programmers society that when someone asks more than 1 question. Then people who answer them usually choose only one of these questions that is the most easiest to answer. But the rest of the questions are just ignored. But the topic is still considered resolved. Person who answered `increased his carma`. All are happy. Except for the man who asked the question, but only got answer that is trivial, easy-to-answer or easy-to-find by himself. And actually got the answer to only one of the questions. And it is the less important.

At my job in this case I usually ask questions only one by one. It gives to person that shall try to answer no options and to answer only to this question. So only when I got answer that satisfies me I start to ask the next question.
I didn't want to use this technique there, because I believe that D community is better...

Sorry for this disgression, but I still don't understand several main points:
1. Why API for __traits(getOverloads) is so strange. Why I need to find parent for symbol myself and pass actual symbol name as string, but not actually pass a symbol itself? It is very strange to me...
2. Where in the documentation is mentioned that when I create alias to name that is a function or method that has overloads then this alias is actually an alias not only for the first or second or randomly selected overload in overload set, but an alias for all of overloads in set at the same time?

Thanks. Have a good day!
January 30, 2020
On Thu, Jan 30, 2020 at 06:20:47PM +0000, uranuz via Digitalmars-d-learn wrote: [...]
> 1. Why API for __traits(getOverloads) is so strange. Why I need to find parent for symbol myself and pass actual symbol name as string, but not actually pass a symbol itself? It is very strange to me...

Actually, __traits was not intended to be used by end user code.  It's supposed to be a raw, low-level interface into compiler internals, that the standard library uses to implement a nicer user-facing API, i.e., std.traits.

Unfortunately, std.traits hasn't kept up with the proliferation of __traits, and now we have pretty widespread use of __traits in user code for doing things std.traits can't do, or can't do very well.

If you think __traits(getOverloads) is strange, wait till you see the weird function parameter tuples that behave like tuples but actually have extra information associated with them, but this information "disappears" when you index the tuple or otherwise manipulate it like a "normal" tuple.  Instead, to extract this information you must take 1-element slices of it.  Thankfully, this ugly mess is hidden behind nicely-clothed citizens of std.traits, so user code rarely has to deal with this craziness.

Arguably, any weird behaviours of __traits ought to be reason to file a bug to add a nicer-behaving API to std.traits.  In fact, any __traits that doesn't have a std.traits analogue arguably should be a bug.


> 2. Where in the documentation is mentioned that when I create alias to name that is a function or method that has overloads then this alias is actually an alias not only for the first or second or randomly selected overload in overload set, but an alias for all of overloads in set at the same time?
[...]

It's probably missing/incomplete documentation.  File a bug.


T

-- 
Change is inevitable, except from a vending machine.
January 30, 2020
On Thursday, 30 January 2020 at 18:20:47 UTC, uranuz wrote:
> 2. Where in the documentation is mentioned that when I create alias to name that is a function or method that has overloads then this alias is actually an alias not only for the first or second or randomly selected overload in overload set, but an alias for all of overloads in set at the same time?
>
> Thanks. Have a good day!

It is directly implied (although not outright stated) by the paragraph I quoted in my previous reply, which says that aliases may be used to merge overload sets. This feature would not work if the alias referred only to a single member of the overload set.

The documentation here could definitely use some improvement, but I think it is at least sufficient to reassure you that the behavior is intentional and can be safely relied upon.
February 01, 2020
OK. Thanks. Created two reports related to these questions:
https://issues.dlang.org/show_bug.cgi?id=20553
https://issues.dlang.org/show_bug.cgi?id=20555