Jump to page: 1 2
Thread overview
hidden passing of __FILE__ and __LINE__ into function
Apr 17, 2017
Dmitry
Apr 17, 2017
Basile B.
Apr 17, 2017
Dmitry
Apr 17, 2017
Jonathan M Davis
Apr 17, 2017
Basile B.
Apr 17, 2017
Jonathan M Davis
Apr 17, 2017
Dmitry
Apr 17, 2017
Jonathan M Davis
Apr 17, 2017
Dmitry
Apr 19, 2017
Lewis
Apr 18, 2017
Jonathan M Davis
Apr 18, 2017
Solomon E
Apr 18, 2017
Stanislav Blinov
Apr 18, 2017
Solomon E
Apr 19, 2017
Dmitry
April 17, 2017
Hi there.

Currently for messages about errors I use code like this:

    void add(string name, ref Scene scene)
    {
        if (name in listOfScenes)
        {
            EError(__FILE__, __LINE__, "scene already exists".L, quoted(name));
        }
    ...
    }

Is there way for avoid using (avoid writing) `__FILE__` and `__LINE__` in each call? I.e. I want use simple

    EError("scene already exists".L, quoted(name));

but function `EError` must print info (file and line) of where was called.

P.S. `EError` just prints info into console, result for this example is:

> [Error] (source\core\EScene.d, 35) Scene already exists: "Scene 1"

and code is:

    void EError(S...)(S args)
    {
        write("[Error] (", args[0], ", ", args[1], ") ", args[2..$], '\n');}
    }

April 17, 2017
On Monday, 17 April 2017 at 10:22:47 UTC, Dmitry wrote:
> Hi there.
>
> Currently for messages about errors I use code like this:
>
>     void add(string name, ref Scene scene)
>     {
>         if (name in listOfScenes)
>         {
>             EError(__FILE__, __LINE__, "scene already exists".L, quoted(name));
>         }
>     ...
>     }
>
> Is there way for avoid using (avoid writing) `__FILE__` and `__LINE__` in each call? I.e. I want use simple
>
>     EError("scene already exists".L, quoted(name));
>
> but function `EError` must print info (file and line) of where was called.
>
> P.S. `EError` just prints info into console, result for this example is:
>
>> [Error] (source\core\EScene.d, 35) Scene already exists: "Scene 1"
>
> and code is:
>
>     void EError(S...)(S args)
>     {
>         write("[Error] (", args[0], ", ", args[1], ") ", args[2..$], '\n');}
>     }

when used as template value parameter, __FILE__ and __LINE__evaluate to the file and line of the call site. So help yourself ans use something like this:

void error(string f = __FILE__, int l = __LINE__)(string msg){}
April 17, 2017
On Monday, 17 April 2017 at 10:30:35 UTC, Basile B. wrote:
> when used as template value parameter, __FILE__ and __LINE__evaluate to the file and line of the call site. So help yourself ans use something like this:
>
> void error(string f = __FILE__, int l = __LINE__)(string msg){}

Thank you, Basile, it works perfect.
April 17, 2017
On Monday, April 17, 2017 10:30:35 Basile B. via Digitalmars-d-learn wrote:
> On Monday, 17 April 2017 at 10:22:47 UTC, Dmitry wrote:
> > Hi there.
> >
> > Currently for messages about errors I use code like this:
> >     void add(string name, ref Scene scene)
> >     {
> >
> >         if (name in listOfScenes)
> >         {
> >
> >             EError(__FILE__, __LINE__, "scene already
> >
> > exists".L, quoted(name));
> >
> >         }
> >
> >     ...
> >     }
> >
> > Is there way for avoid using (avoid writing) `__FILE__` and `__LINE__` in each call? I.e. I want use simple
> >
> >     EError("scene already exists".L, quoted(name));
> >
> > but function `EError` must print info (file and line) of where
> > was called.
> >
> > P.S. `EError` just prints info into console, result for this
> >
> > example is:
> >> [Error] (source\core\EScene.d, 35) Scene already exists:
> >> "Scene 1"
> >
> > and code is:
> >     void EError(S...)(S args)
> >     {
> >
> >         write("[Error] (", args[0], ", ", args[1], ") ",
> >
> > args[2..$], '\n');}
> >
> >     }
>
> when used as template value parameter, __FILE__ and __LINE__evaluate to the file and line of the call site. So help yourself ans use something like this:
>
> void error(string f = __FILE__, int l = __LINE__)(string msg){}

They works, but it results in a new template being instantiated for every call, so you really shouldn't use __FILE__ or __LINE__ as template arguments if you can avoid it. Usually, the better way to handle it is to use runtime arguments, e.g.

void error(string msg, string file = __FILE__, size_t line = __LINE__)
{
    ...
}

That's what Exception's constructor does as well as functions like std.exception.enforce.

- Jonathan M Davis

April 17, 2017
On Monday, 17 April 2017 at 10:55:30 UTC, Jonathan M Davis wrote:
> On Monday, April 17, 2017 10:30:35 Basile B. via Digitalmars-d-learn wrote:
>> On Monday, 17 April 2017 at 10:22:47 UTC, Dmitry wrote:
> void error(string msg, string file = __FILE__, size_t line = __LINE__)
> {
>     ...
> }
>
> That's what Exception's constructor does as well as functions like std.exception.enforce.
>
> - Jonathan M Davis

I didn't know that this also works for regular parameters. Then it's obviously better.
April 17, 2017
On Monday, April 17, 2017 10:58:36 Basile B. via Digitalmars-d-learn wrote:
> On Monday, 17 April 2017 at 10:55:30 UTC, Jonathan M Davis wrote:
> > On Monday, April 17, 2017 10:30:35 Basile B. via
> >
> > Digitalmars-d-learn wrote:
> >> On Monday, 17 April 2017 at 10:22:47 UTC, Dmitry wrote:
> > void error(string msg, string file = __FILE__, size_t line =
> > __LINE__)
> > {
> >
> >     ...
> >
> > }
> >
> > That's what Exception's constructor does as well as functions like std.exception.enforce.
> >
> > - Jonathan M Davis
>
> I didn't know that this also works for regular parameters. Then it's obviously better.

It doesn't in C++ (which is _really_ annoying), but it does in D. In C++, it uses the file and line number of the declaration site, whereas in D, it uses the file and line number of the call site.

- Jonathan M Davis

April 17, 2017
On Monday, 17 April 2017 at 10:55:30 UTC, Jonathan M Davis wrote:
> They works, but it results in a new template being instantiated for every call, so you really shouldn't use __FILE__ or __LINE__ as template arguments if you can avoid it.
Does it matter if I anyway use template (S...) ?
And what problem with that new templates for every call? Increases .exe size? Needs more memory (runtime? compile-time?)? Something else?

> Usually, the better way to handle it is to use runtime arguments, e.g.
> void error(string msg, string file = __FILE__, size_t line = __LINE__)
Is possible use this with (S...)? In some cases I use many arguments (5-10, mixed strings and numbers) and I tried to avoid the concatenation them into string.

What will be better? Concatenation or templates? Or maybe an another way?
April 17, 2017
On Monday, April 17, 2017 13:45:18 Dmitry via Digitalmars-d-learn wrote:
> On Monday, 17 April 2017 at 10:55:30 UTC, Jonathan M Davis wrote:
> > They works, but it results in a new template being instantiated for every call, so you really shouldn't use __FILE__ or __LINE__ as template arguments if you can avoid it.
>
> Does it matter if I anyway use template (S...) ?
> And what problem with that new templates for every call?
> Increases .exe size? Needs more memory (runtime? compile-time?)?
> Something else?

Every time there's a new template instantiation, it's essentially copy-pasting the entire template. So, if you have the templated function

auto foo(T)(T bar)
{
    return bar;
}

and then call

foo(5);
foo(true);
foo("hello");

then you get the equivalent of

int foo!int(int bar)
{
    return bar;
}

bool foo!bool(bool bar)
{
    return bar;
}

string foo!string(string bar)
{
    return bar;
}

in your program. If you have

string foo(string file = __FILE__, size_t line = line)(string bar)
{
    return bar;
}

and you call that function 17 times, then you get 17 separate functions. If you call it 120 times you get 120 separate functions. So, if you call the function very many times, the template bloat would be enormous. The executable will be _much_ larger and will thus take up much more space on disk and much more RAM when it's loaded into memory. In some cases, that makes sense, but it usually doesn't.

> > Usually, the better way to handle it is to use runtime
> > arguments, e.g.
> > void error(string msg, string file = __FILE__, size_t line =
> > __LINE__)
>
> Is possible use this with (S...)? In some cases I use many
> arguments (5-10, mixed strings and numbers) and I tried to avoid
> the concatenation them into string.
>
> What will be better? Concatenation or templates? Or maybe an another way?

The short answer is that if you're using variadic templates, you can't use default arguments. Something like

auto foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__)
{
    ...
}

auto result = foo("hello", 42);

does not work. So, if you want to have the file and line number passed automatically with a variadic template, then you're forced to use template parameters instead of function paramaters and incur whatever bloat that goes with that.

Now, that being said, surprisingly, it does look like it works to do

auto foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__)
{
    ...
}

auto result = foo!(string, int)("hello", 42);

So, if you're okay with explicitly instantiating your variadic function template instead of having the types inferred, then it can work, but otherwise, no. Making it work would require a language enhancement, and even then, if you ever wanted to explicitly provide the file and line number arguments instead of using the default arguments, you'd almost certainly be forced to explicitly instantiate the template, since the compiler would have no other way of determining whether the file and line arguments on the end were intended to be the file and line arguments or just more variadic arguments.

- Jonathan M Davis

April 17, 2017
On Monday, 17 April 2017 at 14:23:50 UTC, Jonathan M Davis wrote:
> So, if you're okay with explicitly instantiating your variadic function template instead of having the types inferred, then it
Yes, it's my case. That's a game engine, so some kilobytes isn't a problem.
Moreover, possible that function will be used only in debug mode.

Thank you for explaining, I appreciate it.
April 18, 2017
On Monday, April 17, 2017 07:23:50 Jonathan M Davis via Digitalmars-d-learn wrote:
> So, if you're okay with explicitly instantiating your variadic function template instead of having the types inferred, then it can work, but otherwise, no. Making it work would require a language enhancement

Actually, not only is there already a bug report for this

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

which is marked as a bug and not an enhancement, and when Walter commented on it when an ICE related to it was fixed, he didn't change it from a bug to an enhancement. So, it looks like he agrees that it's a bug rather than considering it an enhancement. It has yet to be fixed regardless though.

- Jonathan M Davis

« First   ‹ Prev
1 2