January 10, 2019
On Thu, Jan 10, 2019 at 02:00:25PM +0000, Atila Neves via Digitalmars-d wrote:
> On Thursday, 10 January 2019 at 12:37:38 UTC, H. S. Teoh wrote:
[...]
> > Don't worry, this is Atila we're talking about. If he comes up with any solution, you can be sure it will not hurt his precious compile times!  ;-)
> 
> Actually, they're so bad right now anyway from a baseline of acceptability
> to me that nothing I add on top makes it that much worse. Currently
> I'm trying to work out an efficient way to interpret D to run unit
> tests so I don't have to pay the linker tax and just avoid compiling
> code whilst developing. It'll be a lot of work, though... :(

Recently I've started to compile unittests separately from the final executable. The default behaviour of running unittests before main() is nice for one-off scripts and short-term projects, but for serious code I'm finding more and more that it makes more sense to compile and run unittests separately.  I haven't gotten to the point of evading linker tax, though.

But I surmise it should be relatively easy to just compile modules separately with -unittest -run, using -i to automatically pick up imports. Put this in a test target in your build script and have the tests built and run incrementally. Not sure how much time will be saved, due to -i potentially causing the same tests to run multiple times. I should try this out on one of my larger projects to see how it does.


T

-- 
They pretend to pay us, and we pretend to work. -- Russian saying
January 10, 2019
On Thursday, 10 January 2019 at 16:22:27 UTC, H. S. Teoh wrote:
> These days, whenever my functions start needing so many optional arguments that this becomes a problem, I just start using a struct to encapsulate them instead. I wouldn't claim it's the perfect solution, but it does pretty much have equivalent functionality: you can pass values in order (MyArgs(...)), or pass them by name (MyArgs args; args.field1 = 123;), and there can be default arguments (default field values). It does need a bit more typing, but other than that it works pretty well.

This is a viable solution. It works for many usecases. APIs like Vulkan and Direct3D like to use the struct solution to pass arguments to their methods. https://github.com/wilzbach/DIPs/blob/b1283b455b635d7dcbc2c871d2aa47cc67190059/DIPs/DIP1xxx-sw.md would make it much sweeter to work with structs though.
January 10, 2019
On 01/10/2019 06:35 AM, JN wrote:

> the real cost is the fact that you have to create all those structs
> meticulously and you can only use that with functions that expect such
> usage.

Weka uses the generic TypedIdentifier for integers:

  https://github.com/weka-io/mecca/blob/master/src/mecca/lib/typedid.d#L532

Ali

January 10, 2019
On Thursday, 10 January 2019 at 14:35:33 UTC, JN wrote:
> On Thursday, 10 January 2019 at 13:53:40 UTC, Atila Neves wrote:
>>
>> What's the _real_ difference between `someFunc(firstName="Alice")` and `someFunc(FirstName("Alice"))`? The former saves one character? Is that really worth the cost of language support? I have a feeling a lot of feature requests neglect that each and every one of them has a cost, and there's only enough budget for so many.
>>
> Isn't there a performance cost added when using structs like that?

No.

> And the real cost is the fact that you have to create all those structs meticulously

Meticulously? It's a name and the type you were going to write anyway. You can always call the field `_` to avoid even more typing.

> and you can only use that with functions that expect such usage.

Yes. But I'm writing the API.

> With language support, you could have named arguments for every code there exists.

I'd love to see a DIP that did that and dealt with all the corner cases. I suspect that it's not as easy as implied here.

> Anyway, the fact that arguments are named are only a bonus, the real strength of named arguments comes with optional arguments.

Again, I want a library for this. I know how to write it, I just haven't yet.

> Look at the Builder pattern, it's pretty much a workaround for lack of named/keyword arguments.

Java doesn't have variadic templates, D does. No builder pattern needed.

> Also, named/keyword arguments shouldn't be an issue in regards to overloading and argument order. Every language I know that has named/kw arguments allows either only keyword arguments or keywords arguments at the end of the argument list. You can do:
>
> foo(x=10)
> foo(10, 20, z=30)
>
> but you can't do:
>
> foo(x=10, 20)
>
> because it'd be ambiguous.

I don't know of any language that does that and has overloading. Walter knows way more about this than I do.

January 10, 2019
On Thursday, 10 January 2019 at 16:33:51 UTC, H. S. Teoh wrote:
> On Thu, Jan 10, 2019 at 02:00:25PM +0000, Atila Neves via Digitalmars-d wrote:
>> [...]
> [...]
>> [...]
>
> Recently I've started to compile unittests separately from the final executable. The default behaviour of running unittests before main() is nice for one-off scripts and short-term projects, but for serious code I'm finding more and more that it makes more sense to compile and run unittests separately.  I haven't gotten to the point of evading linker tax, though.
>
> But I surmise it should be relatively easy to just compile modules separately with -unittest -run, using -i to automatically pick up imports. Put this in a test target in your build script and have the tests built and run incrementally. Not sure how much time will be saved, due to -i potentially causing the same tests to run multiple times. I should try this out on one of my larger projects to see how it does.
>
>
> T

I _only_ build unit tests apart from the production code now. I'm toying with not using `unittest` at all since I can reflect and find tests on my own, and I don't have to pay the compile time tax of importing a phobos module with `-unittest`.
January 10, 2019
On Thu, Jan 10, 2019 at 06:29:27PM +0000, Atila Neves via Digitalmars-d wrote:
> On Thursday, 10 January 2019 at 16:33:51 UTC, H. S. Teoh wrote:
[...]
> > Recently I've started to compile unittests separately from the final executable. The default behaviour of running unittests before main() is nice for one-off scripts and short-term projects, but for serious code I'm finding more and more that it makes more sense to compile and run unittests separately.  I haven't gotten to the point of evading linker tax, though.
> > 
> > But I surmise it should be relatively easy to just compile modules separately with -unittest -run, using -i to automatically pick up imports. Put this in a test target in your build script and have the tests built and run incrementally. Not sure how much time will be saved, due to -i potentially causing the same tests to run multiple times. I should try this out on one of my larger projects to see how it does.
[...]
> I _only_ build unit tests apart from the production code now. I'm toying with not using `unittest` at all since I can reflect and find tests on my own, and I don't have to pay the compile time tax of importing a phobos module with `-unittest`.

The last time somebody looked, the real problem wasn't that Phobos (or any 3rd party library) unittests were being compiled over and over; it was caused by a change in template instantiation behaviour when -unittest is specified, such that many more templates are instantiated that probably don't need to be, thus causing the observed compile-time spike.  There's a reason it was done this way, but I'm here gnashing my teeth wishing that there was a way to turn off this annoying behaviour.


T

-- 
Why waste time learning, when ignorance is instantaneous? -- Hobbes, from Calvin & Hobbes
January 10, 2019
On Thu, 10 Jan 2019 10:12:24 -0800, Ali Çehreli wrote:

> On 01/10/2019 06:35 AM, JN wrote:
> 
>  > the real cost is the fact that you have to create all those structs
>  > meticulously and you can only use that with functions that expect
>  > such usage.
> 
> Weka uses the generic TypedIdentifier for integers:
> 
>    https://github.com/weka-io/mecca/blob/master/src/mecca/lib/
typedid.d#L532
> 
> Ali

Which can be done equally well with std.typecons.Typedef. It still has a lot of the same issues as custom structs, but at least you can use a different module's named arg structs as long as they're not doing anything funky.

Here's a slightly better version:

---
struct Named(T)
{
  template opDispatch(string name)
  {
    alias opDispatch = Typedef!(T, T.init, name);
  }
}
struct Arg
{
  template opDispatch(string name)
  {
    alias opDispatch = makeTypedef!name;
  }
}
template makeTypedef(string name)
{
  Typedef!(T, T.init, name) makeTypedef(T)(T value)
  {
    return Typedef!(T, T.init, name)(value);
  }
}
---

Usage:

---
void foo(Named!int.age a, Named!string.name b)
{
  writefln("name: %s age: %s", b, a);
}
void main()
{
  foo(Arg.age(12), Arg.name("Rydia"));
}
---

Something like that is the best you're likely to get with the struct-per- argument model.
January 10, 2019
On 1/10/19 1:49 PM, H. S. Teoh wrote:

> The last time somebody looked, the real problem wasn't that Phobos (or
> any 3rd party library) unittests were being compiled over and over; it
> was caused by a change in template instantiation behaviour when
> -unittest is specified, such that many more templates are instantiated
> that probably don't need to be, thus causing the observed compile-time
> spike.  There's a reason it was done this way, but I'm here gnashing my
> teeth wishing that there was a way to turn off this annoying behaviour.

Yes, it's that when unittest is enabled effectively -allinst is enabled as well.

That wasn't the only problem, but it was the main reason why importing e.g. std.regex with -unittest was a huge penalty.

-Steve
January 11, 2019
On 11/01/2019 3:35 AM, JN wrote:
> Also, named/keyword arguments shouldn't be an issue in regards to overloading and argument order. Every language I know that has named/kw arguments allows either only keyword arguments or keywords arguments at the end of the argument list. You can do:
> 
> foo(x=10)
> foo(10, 20, z=30)
> 
> but you can't do:
> 
> foo(x=10, 20)
> 
> because it'd be ambiguous.

Actually every example there is ambiguous and problematic in D.
It conflicts with AssignExpression which is identical in syntax and usage!
January 11, 2019
On Friday, 11 January 2019 at 07:53:56 UTC, rikki cattermole wrote:
> On 11/01/2019 3:35 AM, JN wrote:
>> Also, named/keyword arguments shouldn't be an issue in regards to overloading and argument order. Every language I know that has named/kw arguments allows either only keyword arguments or keywords arguments at the end of the argument list. You can do:
>> 
>> foo(x=10)
>> foo(10, 20, z=30)
>> 
>> but you can't do:
>> 
>> foo(x=10, 20)
>> 
>> because it'd be ambiguous.
>
> Actually every example there is ambiguous and problematic in D.
> It conflicts with AssignExpression which is identical in syntax and usage!

well, it's because I used the equality sign, languages like C# use :,

I guess:

foo(x:10, 20)

would be better?