June 19, 2016
On Saturday, 18 June 2016 at 18:13:22 UTC, Johan Engelen wrote:
> An example of how __FILE__ as template parameter will break your library:
>
> In library, distributed in binary+source form:
> ```
> alias file_templ_alias = file_templ!bool;
> T file_templ(T, string file = __FILE__, size_t line = __LINE__) (T value) {
>     return value;
> }
> ```
> In user code, linking to the library binary:
> ```
> bool foo(bool b){
>     return file_templ_alias(b);
> }
> ```
> By calling the alias, both DMD and LDC will decide that the template does not need reinstantiation in the user object file and will try to link with the symbol in the library binary. So you have to be lucky to install the library source in the same path as where it was when the library was built on someone else's machine, otherwise you'll get a linker error and are left wondering what went wrong.
>
> -Johan

Can't one just use __MODULE__ instead?

So:
T file_templ(T, string mod = __MODULE__, size_t line = __LINE__)
(T value) {
    return value;
}

June 20, 2016
On 06/20/2016 01:13 AM, Johan Engelen wrote:
> On Sunday, 19 June 2016 at 21:40:20 UTC, David Nadlinger wrote:
>> On Sunday, 19 June 2016 at 21:13:00 UTC, Johan Engelen wrote:
>>> On Sunday, 19 June 2016 at 21:11:59 UTC, Johan Engelen wrote:
>>>> (I think we can pretty much inline anything the user throws at us)
>>>
>>> (as long as it is not a naked asm function)
>>
>> Another example is `alloca`, which you might not want to inline.
> 
> And also variadic functions, for which Dicebot needs __FILE__ to be a template param..............

It is template-based variadic list though in all Phobos cases. This is
one of logger examples I was referring to :
https://github.com/dlang/phobos/blob/master/std/experimental/logger/core.d#L202-L216

How about defining semantics like "try inlining if possible, fallback to always emitting symbol to object file otherwise"? That would also allow compatible implementation in dmd.

My reasoning for proposing that is that for all legitimate cases I'd have to use __FILE__ as a template argument I'd also want the symbol inlined to prevent the bloat. After all CT computation such functions tend to contain 1-2 lines of runtime code only.
June 20, 2016
On 2016-06-19 12:43, Dicebot wrote:

> Yes. It is necessary because runtime parameter list is variadic -
> template bloat in such cases is usually eliminated by forwarding to
> another private method immediately turning file/line into first runtime
> argument instead.

Would it be a bad idea to allow this in the compiler:

void foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__);

It wouldn't be possible to pass "file" or "line" when calling "foo". But it's useful for the special default values, __FILE__ and __LINE__.

-- 
/Jacob Carlborg
June 20, 2016
On Monday, 20 June 2016 at 14:28:06 UTC, Jacob Carlborg wrote:
>
> Would it be a bad idea to allow this in the compiler:
>
> void foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__);
>
> It wouldn't be possible to pass "file" or "line" when calling "foo". But it's useful for the special default values, __FILE__ and __LINE__.

I very much agree with this idea. Like with the current system of forwarding to a function with explicit file and line run-time arguments, a function can be made accessible that has them as explicit parameters for those cases when you want to pretend to be somewhere you're not. :p

--
  Simen
June 21, 2016
On Monday, 20 June 2016 at 14:28:06 UTC, Jacob Carlborg wrote:
> On 2016-06-19 12:43, Dicebot wrote:
>
>> Yes. It is necessary because runtime parameter list is variadic -
>> template bloat in such cases is usually eliminated by forwarding to
>> another private method immediately turning file/line into first runtime
>> argument instead.
>
> Would it be a bad idea to allow this in the compiler:
>
> void foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__);
>
> It wouldn't be possible to pass "file" or "line" when calling "foo". But it's useful for the special default values, __FILE__ and __LINE__.

I think it would be good idea to take this even further:

T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Args args, T2 t2, T3 t3)

In other words, I think that the limitation that variadic template parameter list must be at the end of the function parameters is arbitrary and just a deficiency of the current implementation.
A fixed number of parameters proceeding or following a variadic list should all work equally well, even in combination with IFTI.

BTW, Ruby also allows to define methods with such parameters: foo(first_arg, *middle_arguments, last_arg)


June 21, 2016
On Tuesday, 21 June 2016 at 02:59:44 UTC, ZombineDev wrote:
> On Monday, 20 June 2016 at 14:28:06 UTC, Jacob Carlborg wrote:
>> On 2016-06-19 12:43, Dicebot wrote:
>>
>>> Yes. It is necessary because runtime parameter list is variadic -
>>> template bloat in such cases is usually eliminated by forwarding to
>>> another private method immediately turning file/line into first runtime
>>> argument instead.
>>
>> Would it be a bad idea to allow this in the compiler:
>>
>> void foo(Args...)(Args args, string file = __FILE__, size_t line = __LINE__);
>>
>> It wouldn't be possible to pass "file" or "line" when calling "foo". But it's useful for the special default values, __FILE__ and __LINE__.
>
> I think it would be good idea to take this even further:
>
> T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Args args, T2 t2, T3 t3)
>
> In other words, I think that the limitation that variadic template parameter list must be at the end of the function parameters is arbitrary and just a deficiency of the current implementation.
> A fixed number of parameters proceeding or following a variadic list should all work equally well, even in combination with IFTI.
>
> BTW, Ruby also allows to define methods with such parameters: foo(first_arg, *middle_arguments, last_arg)

I meant:

T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Ts ts, T2 t2, T3 t3)

June 21, 2016
On Tuesday, 21 June 2016 at 02:59:44 UTC, ZombineDev wrote:
> I think it would be good idea to take this even further:
>
> T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Args args, T2 t2, T3 t3)
>
> In other words, I think that the limitation that variadic template parameter list must be at the end of the function parameters is arbitrary and just a deficiency of the current implementation.

I don't disagree with you, but this is a separate issue. If the arguments trailing Args have default values (as they would in the case of __FILE__, __LINE__) it will create ambiguity.

void foo(Args...)(Args args, int n = 1);

What happens if I do this? foo(1, 2, 3, 4); Is n 1 or 4?

June 21, 2016
On Tuesday, 21 June 2016 at 10:28:03 UTC, pineapple wrote:
> On Tuesday, 21 June 2016 at 02:59:44 UTC, ZombineDev wrote:
>> I think it would be good idea to take this even further:
>>
>> T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Args args, T2 t2, T3 t3)
>>
>> In other words, I think that the limitation that variadic template parameter list must be at the end of the function parameters is arbitrary and just a deficiency of the current implementation.
>
> I don't disagree with you, but this is a separate issue. If the arguments trailing Args have default values (as they would in the case of __FILE__, __LINE__) it will create ambiguity.
>
> void foo(Args...)(Args args, int n = 1);
>
> What happens if I do this? foo(1, 2, 3, 4); Is n 1 or 4?

Another thought: What if in this case the trailing arguments are always the default value? In this case n is /always/ 1, file and line would always be __FILE__ and __LINE__. This would be a more general solution and maybe not too intolerably ugly.
June 21, 2016
On Monday, 20 June 2016 at 08:10:19 UTC, Dicebot wrote:
> How about defining semantics like "try inlining if possible, fallback to always emitting symbol to object file otherwise"? That would also allow compatible implementation in dmd.

This would get rid of the undefined symbols, but there is a much more subtle problem here that nobody has brought up yet: If the template ends up being emitted twice with different mangled names, then, well, it ends up existing twice in the final executable.

This is not really an issue for functions, but very much so for data symbols (e.g. a static variable inside a function), where you could end up with the same alias referring to two different pieces of data depending on where it is used from.

The root of this issue is that __FILE__ introduces incidental environmental state into the otherwise pure module system.

 — David
June 21, 2016
On Tuesday, 21 June 2016 at 10:34:01 UTC, pineapple wrote:
> On Tuesday, 21 June 2016 at 10:28:03 UTC, pineapple wrote:
>> On Tuesday, 21 June 2016 at 02:59:44 UTC, ZombineDev wrote:
>>> I think it would be good idea to take this even further:
>>>
>>> T4 foo(T4, T0, T1, Ts..., T2, T3)(T0 t0, T1 t1, Args args, T2 t2, T3 t3)
>>>
>>> In other words, I think that the limitation that variadic template parameter list must be at the end of the function parameters is arbitrary and just a deficiency of the current implementation.
>>
>> I don't disagree with you, but this is a separate issue. If the arguments trailing Args have default values (as they would in the case of __FILE__, __LINE__) it will create ambiguity.
>>
>> void foo(Args...)(Args args, int n = 1);
>>
>> What happens if I do this? foo(1, 2, 3, 4); Is n 1 or 4?
>
> Another thought: What if in this case the trailing arguments are always the default value? In this case n is /always/ 1, file and line would always be __FILE__ and __LINE__. This would be a more general solution and maybe not too intolerably ugly.

It should work just like the regular expression .*.? - if all parameters after the variadic list have default values, then the list should capture all arguments and the last parameters use their default values. E.g. args is (1, 2, 3, 4) and n is 1 in your example.
In general the strategy should be: the variadic list captures as much arguments as its constraints allow it to capture.

// regex: (\d*)(.)(.?)
// (pretend that \d means scalar type)
void foo(T1, T2, Args...)(Args args, T1 t1, T2 t2 = "default"w)
    if (allSatisfy!(isScalarType, Args))
{
    pragma (msg, Args, ", ", T1, ", ", T2);
}

foo(0, 0L, "asd");       // (int, long), string, wstring
foo("asd", "sdf");       // (), string, string
foo('c', new Object, 3); // (char), Object, int