Thread overview
Help me escape optional parens hell
Jun 24, 2017
Meta
Jun 24, 2017
ketmar
Jun 24, 2017
ketmar
Jun 24, 2017
ketmar
Jun 24, 2017
Meta
June 24, 2017
The code:

alias Response = Nullable!(string, "empty response (error)");

Response processMessage(string commandModule)(string message, bool isCommand)
{
    import std.meta;
    import std.string;
    import std.traits;

    import command_uda;

    mixin("import " ~ commandModule ~ ';');
    bool foundCommandMatch = false;
    foreach(symbol; getSymbolsByUDA!(mixin(commandModule), Command))
    {
        enum commandUDA = getUDAs!(symbol, Command)[0];
        auto commandPhrase = commandUDA.phrase == "" ? symbol.stringof : commandUDA.phrase; //Error: function <function signature> is not callable using argument types ()
        auto commandPhrasePattern = regex(`^%s\s`.format(commandPhrase));
        if (message.matchFirst(commandPhrasePattern) && !foundCommandMatch)
        {
            version(responseDebug) writeln("Matched command ", symbol.stringof, " with phrase '", commandPhrase, "'\n"); //Same issue
            return Response(symbol(message.strip()));
        }
    }

    return Response.init;
}

I've been banging my head against this and cannot figure out why `symbol.stringof` is being called instead of getting a string of the symbol. I tried to create a reduced test case but it works fine:

import std.stdio;
import std.traits;

enum Attr;

@Attr string test1() { return __FUNCTION__; }
@Attr string test2() { return __FUNCTION__; }

void process()
{
	foreach (symbol; getSymbolsByUDA!(mixin(__MODULE__), Attr))
	{
		writeln("The result of calling ", symbol.stringof, " is ", symbol());
	}
}

void main()
{
	process();
}

So I have no clue what I'm doing wrong. This is driving me insane.
June 24, 2017
Meta wrote:

> So I have no clue what I'm doing wrong. This is driving me insane.

aaaah. known $#^#$@^@%.

	enum SymName = (&symbol).stringof[2..$]; // this, instead of symbol.stringof

dirty hack, let's hope that DMD devs won't change `.toString()` output (i.e. first two chars will always be "& ").

besides this, i know no other way to stop compiler from calling the function there.
June 24, 2017
ketmar wrote:

> `.toString()`

toChars().

;-)
June 24, 2017
ketmar wrote:

> Meta wrote:
>
>> So I have no clue what I'm doing wrong. This is driving me insane.
>
> aaaah. known $#^#$@^@%.
>
> 	enum SymName = (&symbol).stringof[2..$]; // this, instead of symbol.stringof
>
> dirty hack, let's hope that DMD devs won't change `.toString()` output (i.e. first two chars will always be "& ").
>
> besides this, i know no other way to stop compiler from calling the function there.

i hope devs won't break string representation: i bet that there is ALOT of code that is using this trick. i myself borrowed it from some other module several years ago. and it looks that the module where i found it borrowed the trick from some another module. a really long history. ;-)
June 24, 2017
On 6/24/17 3:53 AM, Meta wrote:
> The code:
> 
> alias Response = Nullable!(string, "empty response (error)");
> 
> Response processMessage(string commandModule)(string message, bool isCommand)
> {
>      import std.meta;
>      import std.string;
>      import std.traits;
> 
>      import command_uda;
> 
>      mixin("import " ~ commandModule ~ ';');
>      bool foundCommandMatch = false;
>      foreach(symbol; getSymbolsByUDA!(mixin(commandModule), Command))
>      {
>          enum commandUDA = getUDAs!(symbol, Command)[0];
>          auto commandPhrase = commandUDA.phrase == "" ? symbol.stringof : commandUDA.phrase; //Error: function <function signature> is not callable using argument types ()
>          auto commandPhrasePattern = regex(`^%s\s`.format(commandPhrase));
>          if (message.matchFirst(commandPhrasePattern) && !foundCommandMatch)
>          {
>              version(responseDebug) writeln("Matched command ", symbol.stringof, " with phrase '", commandPhrase, "'\n"); //Same issue
>              return Response(symbol(message.strip()));
>          }
>      }
> 
>      return Response.init;
> }
> 
> I've been banging my head against this and cannot figure out why `symbol.stringof` is being called instead of getting a string of the symbol. I tried to create a reduced test case but it works fine:
> 
> import std.stdio;
> import std.traits;
> 
> enum Attr;
> 
> @Attr string test1() { return __FUNCTION__; }
> @Attr string test2() { return __FUNCTION__; }
> 
> void process()
> {
>      foreach (symbol; getSymbolsByUDA!(mixin(__MODULE__), Attr))
>      {
>          writeln("The result of calling ", symbol.stringof, " is ", symbol());
>      }
> }
> 
> void main()
> {
>      process();
> }
> 
> So I have no clue what I'm doing wrong. This is driving me insane.

I know what you are doing wrong in your reduced case. Try this instead:

@Attr string test1(int) { return __FUNCTION__; }
@Attr string test2(int) { return __FUNCTION__; }

void process()
{
    foreach (symbol; getSymbolsByUDA!(mixin(__MODULE__), Attr))
    {
        writeln("The result of calling ", symbol.stringof, " is ", symbol(1));
    }
}

The reason your version "works" is because your functions actually are callable with no args!

I tried many things including:

enum symbolname = symbol.stringof;
enum symbolname = (symbol).stringof;
pragma(msg, symbol.stringof);

Nothing works. If this isn't already a bug, you should file it. Aside from ketmar's workaround, I can't think of one.

It's interesting that the ability to call without parentheses is what causes the error, yet when you *can* call without parentheses, it doesn't actually do so (symbol.stringof prints the name of the symbol). This seems very obviously to be a bug.

-Steve
June 24, 2017
On Saturday, 24 June 2017 at 08:08:33 UTC, ketmar wrote:
> Meta wrote:
>
>> So I have no clue what I'm doing wrong. This is driving me insane.
>
> aaaah. known $#^#$@^@%.
>
> 	enum SymName = (&symbol).stringof[2..$]; // this, instead of symbol.stringof
>
> dirty hack, let's hope that DMD devs won't change `.toString()` output (i.e. first two chars will always be "& ").
>
> besides this, i know no other way to stop compiler from calling the function there.

It's dirty but I guess I'll have to go with this hack for the time being.

Also, I filed a bug:

https://issues.dlang.org/show_bug.cgi?id=17546