Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Dmitry via Digitalmars-d-learn

On Tuesday, 18 April 2017 at 13:48:57 UTC, Stanislav Blinov wrote:
There's a much more concise workaround, both in code written 
and generated ;)


import std.stdio;

template func(string file = __FILE__, int line = __LINE__)
{
auto func(T...)(auto ref T args)
{
writeln("called func with ", T.length, " args at ",
file, ":", line);
}
}

void main()
{
func();
func(1, 2, 3);
}


Very nice. Thank you!


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Lewis via Digitalmars-d-learn

On Monday, 17 April 2017 at 14:23:50 UTC, Jonathan M Davis wrote:
On Monday, April 17, 2017 13:45:18 Dmitry via 
Digitalmars-d-learn wrote:

[...]


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


[...]


The other reason to avoid excessive template instantiation is 
that it inflates your compile time. A while back I changed my 
custom assertf() and logf() functions to be non-templated in 
exactly the way Jonathan M Davis described, and it shaved ~0.5s 
off my 3s build time. This particular project is currently only 
8000 LOC, but on a larger project you can see the hit could be 
pretty significant.


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Solomon E via Digitalmars-d-learn

On Tuesday, 18 April 2017 at 13:48:57 UTC, Stanislav Blinov wrote:

On Tuesday, 18 April 2017 at 13:28:06 UTC, Solomon E wrote:


I tried to produce an example of calling a function with
variadic template arguments using special tokens __FILE__ and 
__LINE__.


This compiles and runs, producing the output shown, using the 
default gdc
provided by Ubuntu 17.04. This appears to be a workaround for 
Issue 8687...


There's a much more concise workaround, both in code written 
and generated ;)


import std.stdio;

template func(string file = __FILE__, int line = __LINE__)
{
auto func(T...)(auto ref T args)
{
writeln("called func with ", T.length, " args at ",
file, ":", line);
}
}

void main()
{
func();
func(1, 2, 3);
}


Thank you for reminding me that templates can contain a 
definition of a function
of the same name, which still surprises me as convenient, not as 
a bad thing.


Unfortunately, when I tried it, I found that while that attempt 
at a workaround is
twice as concise in lines of code and symbols introduced, it is 
not acceptable.
It gets the lines reported wrong. It reports the line for where 
the template was
first instantiated for the same tuple of argument types, instead 
of exactly the line

of each call of `func`.


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Tuesday, 18 April 2017 at 13:28:06 UTC, Solomon E wrote:


I tried to produce an example of calling a function with
variadic template arguments using special tokens __FILE__ and 
__LINE__.


This compiles and runs, producing the output shown, using the 
default gdc
provided by Ubuntu 17.04. This appears to be a workaround for 
Issue 8687...


There's a much more concise workaround, both in code written and 
generated ;)


import std.stdio;

template func(string file = __FILE__, int line = __LINE__)
{
auto func(T...)(auto ref T args)
{
writeln("called func with ", T.length, " args at ",
file, ":", line);
}
}

void main()
{
func();
func(1, 2, 3);
}



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Solomon E via Digitalmars-d-learn

On Tuesday, 18 April 2017 at 10:13:09 UTC, Jonathan M Davis wrote:
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


import std.stdio: writeln;
import std.conv: to;

void main()
{
add("Scene 1", "Scene 2", "Scene 3");
add("Scene 3", "Scene 4", "Scene 5");
add(5, 6, 7);
add(7, "Scene 8", "Scene 9");
writeln("total scenes added: ", sceneCount);
}

struct Scene
{
string name;
string file;
size_t line;
}

Scene*[] listOfScenes;
int[string] indexOfScenes;
int sceneCount = 0;

void add_impl(T...)(string file, size_t line, T args)
{
foreach(arg; args)
{
static if (is(typeof(arg) == string))
{
auto name = arg;
}
else
{
auto name = "Scene " ~ arg.to!string;
}
if (name in indexOfScenes)
{
EError(file, line, "scene already exists", name);
}
else
{
indexOfScenes[name] = sceneCount;
listOfScenes ~= new Scene(name, file, line);
sceneCount += 1;
writeln("added " ~ name);
}
}
}

void add(string file = __FILE__, size_t line = __LINE__, T...)(T 
args)

{
add_impl!T(file, line, args);
}

void EError(string file, size_t line, string message, string name)
{
writeln(name, ": ", message,
" in file ", file, " in line ", line);
auto previous = listOfScenes[indexOfScenes[name]];
writeln("previous definition of ", previous.name,
" was in ", previous.file, " in line ", 
previous.line);

}

/* output:

added Scene 1
added Scene 2
added Scene 3
Scene 3: scene already exists in file vlf.d in line 7
previous definition of Scene 3 was in vlf.d in line 6
added Scene 4
added Scene 5
Scene 5: scene already exists in file vlf.d in line 8
previous definition of Scene 5 was in vlf.d in line 7
added Scene 6
added Scene 7
Scene 7: scene already exists in file vlf.d in line 9
previous definition of Scene 7 was in vlf.d in line 8
added Scene 8
added Scene 9
total scenes added: 9

*/


I tried to produce an example of calling a function with
variadic template arguments using special tokens __FILE__ and 
__LINE__.


This compiles and runs, producing the output shown, using the 
default gdc
provided by Ubuntu 17.04. This appears to be a workaround for 
Issue 8687.
The instantiations of the wrapper function `add` should only add 
minimally

to the compiled object code size, once per call of `add`.
I'm not sure about the quality of any of this code.



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-18 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Dmitry via Digitalmars-d-learn

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.


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Dmitry via Digitalmars-d-learn

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?


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Basile B. via Digitalmars-d-learn

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.


Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Jonathan M Davis via Digitalmars-d-learn
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



Re: hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Basile B. via Digitalmars-d-learn

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){}


hidden passing of __FILE__ and __LINE__ into function

2017-04-17 Thread Dmitry via Digitalmars-d-learn

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');}

}