Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-05-23 Thread Martin Nowak via Digitalmars-d

On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:

On 2/14/2017 8:25 AM, Andrei Alexandrescu wrote:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

The function name is on the first line.


It could be improved slightly using indentation:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

But there's another issue here. remove() has other overloads:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s == SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& Offset.length >= 1)

Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, 
Range)

(Range range)
if (isBidirectionalRange!Range
&& hasLvalueElements!Range)

Two constraints are common to all three, those are the only 
ones that actually need to be in the constraint. The others can 
go in the body under `static if`, as the user need not be 
concerned with them.


Turns out that this advice is somewhat problematic. When the 
constraints are too general, it might easily attempt to hijack 
other calls, leading to conflicts between unrelated functions of 
the same name.


See https://github.com/dlang/phobos/pull/5149 which introduced a 
conflict between std.algorithm.copy and std.file.copy for 
(string, string) arguments.


Still your point is valid, separating different overloads using 
constraints unnecessarily complicates documentation.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-22 Thread Andrei Alexandrescu via Digitalmars-d

On 02/22/2017 06:53 AM, Atila Neves wrote:

On Thursday, 16 February 2017 at 13:21:04 UTC, Andrei Alexandrescu wrote:

On 2/16/17 7:11 AM, Atila Neves wrote:

On Wednesday, 15 February 2017 at 17:10:26 UTC, Adam D. Ruppe wrote:

On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob Carlborg wrote:

Your documentation is an improvement but it doesn't help when reading
the source code.


Yeah, I think there's a few things we can do in the source too. We
should find the common combinations and abstract them out, like I said
before, isInputRangeOf is potentially useful.

Though, like Andrei, I'm skeptical on doing too much of that, since
the combinations can quickly explode and then you just have to search
through more to figure out wtf they mean.

That'd help the source and docs if we find the right balance.


I submitted a Phobos PR for `isInputRangeOf`. It was nuked from orbit. I
understand why: as you mention, the combinatorial explosion of names is
an issue. But: it's a mess rangeifying code when this:

void fun(Foo[] foos);  // yay! readable

becomes:

void fun(R)(R foos) if(isInputRange!R && is(Unqual!(ElementType!R) ==
Foo);


If you find a number of these, that would be good evidence. -- Andrei


I found just over 70 similar lines, which is more than I expected given
how generic Phobos is. The real issue is in client code though. I write
less range-based code than I'd like, because it's a lot easier to make
it a regular array and change it later if the function needs to be
called with other ranges.


If you submit a pull request that simplifies >70 constraints in Phobos 
and implicitly promises to simplify client-level constraints as much, 
that would have a good chance to be accepted. Destroy! -- Andrei




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-22 Thread Atila Neves via Digitalmars-d
On Thursday, 16 February 2017 at 13:21:04 UTC, Andrei 
Alexandrescu wrote:

On 2/16/17 7:11 AM, Atila Neves wrote:
On Wednesday, 15 February 2017 at 17:10:26 UTC, Adam D. Ruppe 
wrote:
On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob 
Carlborg wrote:
Your documentation is an improvement but it doesn't help 
when reading

the source code.


Yeah, I think there's a few things we can do in the source 
too. We
should find the common combinations and abstract them out, 
like I said

before, isInputRangeOf is potentially useful.

Though, like Andrei, I'm skeptical on doing too much of that, 
since
the combinations can quickly explode and then you just have 
to search

through more to figure out wtf they mean.

That'd help the source and docs if we find the right balance.


I submitted a Phobos PR for `isInputRangeOf`. It was nuked 
from orbit. I
understand why: as you mention, the combinatorial explosion of 
names is

an issue. But: it's a mess rangeifying code when this:

void fun(Foo[] foos);  // yay! readable

becomes:

void fun(R)(R foos) if(isInputRange!R && 
is(Unqual!(ElementType!R) == Foo);


If you find a number of these, that would be good evidence. -- 
Andrei


I found just over 70 similar lines, which is more than I expected 
given how generic Phobos is. The real issue is in client code 
though. I write less range-based code than I'd like, because it's 
a lot easier to make it a regular array and change it later if 
the function needs to be called with other ranges.


Atila


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-21 Thread Nick Treleaven via Digitalmars-d

On Sunday, 19 February 2017 at 01:53:58 UTC, Timothee Cour wrote:

Doesn't add indentation:

with (module_!"std.stdio, std.traits")
void fun(T)(File input, T value)
if (isIntegral!T);


* what is the implementation of `module_` ? `from` defined 
earlier doesn't allow for multiple modules as in 
from!"std.stdio, std.traits"`. But let's assume it can be done 
for now.


I don't know how to implement it. Possibly with multiple alias 
this.



* when `with` covers multiple declarations, it adds indentation:
with(module_!"std.stdio"){
  declaration1;
  declaration2;
}

* when `with` covers a single one, it doesn't add indentation, 
but then `::` can be used instead, with arguably simpler syntax:


`void fun(T)(std.stdio::File input, T value);`
vs
`with (module_!"std.stdio") void fun(T)(File input, T value);`


What about when the 2nd argument uses File as well? That's the 
violation of DRY I meant.


with/module_ solves the UFCS member stand-in problem 
elegantly, how does your proposal solve it?:

with (module_!"std.range.primitives")
void func(alias pred, R)(R range)
if (isInputRange!R && is(typeof(pred(range.front)) == bool);

.front has to refer to *either* a member or an imported UFCS 
function.


UFCS equally affects the `::`  proposal and the 
`module_!""`-without-`with` proposal.


Besides the option of not using UFCS, we can actually use Alias 
for

this, as I've proposed a while ago in
http://forum.dlang.org/post/mailman.1002.1370829729.13711.digitalmars-d-le...@puremagic.com:

`with (module_!"std.range.primitives") ... pred(range.front)`
vs:
`... pred(range.Alias!(std.range.primitives::front))`

or, if a feature that I've proposed earlier in
http://forum.dlang.org/post/mailman.1453.1369099708.4724.digitalmar...@puremagic.com
(support UFCS with fully qualified function names) is accepted, 
it

becomes even simpler:

`... pred(range.(std.range.primitives::front))`


No, then front only refers to the std.range one, not R.front if 
it exists. The with() solution is like a lazy scoped import, 
affecting overloading, whereas using just from! or mod:: forces a 
lookup in that module scope only.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-18 Thread Timothee Cour via Digitalmars-d
> Doesn't add indentation:
>
> with (module_!"std.stdio, std.traits")
> void fun(T)(File input, T value)
> if (isIntegral!T);

* what is the implementation of `module_` ? `from` defined earlier
doesn't allow for multiple modules as in from!"std.stdio,
std.traits"`. But let's assume it can be done for now.

* when `with` covers multiple declarations, it adds indentation:
with(module_!"std.stdio"){
  declaration1;
  declaration2;
}

* when `with` covers a single one, it doesn't add indentation, but
then `::` can be used instead, with arguably simpler syntax:

`void fun(T)(std.stdio::File input, T value);`
vs
`with (module_!"std.stdio") void fun(T)(File input, T value);`


> with/module_ solves the UFCS member stand-in problem elegantly, how does your 
> proposal solve it?:
> with (module_!"std.range.primitives")
> void func(alias pred, R)(R range)
> if (isInputRange!R && is(typeof(pred(range.front)) == bool);
>
> .front has to refer to *either* a member or an imported UFCS function.

UFCS equally affects the `::`  proposal and the
`module_!""`-without-`with` proposal.

Besides the option of not using UFCS, we can actually use Alias for
this, as I've proposed a while ago in
http://forum.dlang.org/post/mailman.1002.1370829729.13711.digitalmars-d-le...@puremagic.com:

`with (module_!"std.range.primitives") ... pred(range.front)`
vs:
`... pred(range.Alias!(std.range.primitives::front))`

or, if a feature that I've proposed earlier in
http://forum.dlang.org/post/mailman.1453.1369099708.4724.digitalmar...@puremagic.com
(support UFCS with fully qualified function names) is accepted, it
becomes even simpler:

`... pred(range.(std.range.primitives::front))`


To reiterate what I said earlier:

* `foo.bar::symol` is very well suited for the common case of 1-off
imports, ie when the import is only needed at a particular location.
This is a common case.

* If we want to cover multiple declarations, using something like
`with (module_!"std.stdio, std.traits")` makes sense and is more DRY.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-17 Thread Nick Treleaven via Digitalmars-d

On Friday, 17 February 2017 at 04:09:14 UTC, timotheecour wrote:
* with(module_!"std.foo") is useful for scoping imports to 
cover several declarations and being DRY; at the expense of 
adding indentation/nesting and less nice syntax


Doesn't add indentation:

with (module_!"std.stdio, std.traits")
void fun(T)(File input, T value)
if (isIntegral!T);

with/module_ solves the UFCS member stand-in problem elegantly, 
how does your proposal solve it?:


with (module_!"std.range.primitives")
void func(alias pred, R)(R range)
if (isInputRange!R && is(typeof(pred(range.front)) == bool);

.front has to refer to *either* a member or an imported UFCS 
function.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread timotheecour via Digitalmars-d
On Wednesday, 15 February 2017 at 20:21:45 UTC, Nick Treleaven 
wrote:
On Wednesday, 15 February 2017 at 20:09:46 UTC, Timothee Cour 
wrote:
This thread completely diverged from the original post, which 
was propsing `::` instead of `from!`:


```
void fun(T)(std.stdio::File input, T value) if 
(std.traits::isIntegral!T)

{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T)
{...}
```

I see it as a clear improvment in readability (see original 
post for details along with shortcomings of `from!` approach )


I really think allowing `with (module_!"std.foo")` before 
declarations is a better solution from a DRY perspective, plus 
it works for UFCS. This is a more general change that has other 
benefits that apply to any static aggregate e.g. enum names - 
`with(Enum)`, not just imports.


both are useful:

* std.stdio::File is nice for 1-off symbols only used 1 or a few 
times; simple syntax and doesn't add indentation / nesting


* with(module_!"std.foo") is useful for scoping imports to cover 
several declarations and being DRY; at the expense of adding 
indentation/nesting and less nice syntax




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread Daniel Nielsen via Digitalmars-d
On Wednesday, 15 February 2017 at 19:39:52 UTC, Andrei 
Alexandrescu wrote:

On 02/15/2017 06:20 AM, Daniel N wrote:

On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N wrote:

template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}


(lunch-break => time to hack D!)

template every(T...)
{
  template satisfies(U...)
  {
enum satisfies = {
  foreach(t; T)
foreach(u; U)
  if(!u!t)
return false;
  return true;
}();
  }
}


That looks pretty neat. Can you find 4-5 cases in which this 
could be used gainfully in Phobos? Thanks! -- Andrei


Thanks, I'll get back to you. Unfortunately I just contracted 
fever, not fit to leave bed. Nothing dangerous, just am K.O.




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread Andrei Alexandrescu via Digitalmars-d

On 2/16/17 7:11 AM, Atila Neves wrote:

On Wednesday, 15 February 2017 at 17:10:26 UTC, Adam D. Ruppe wrote:

On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob Carlborg wrote:

Your documentation is an improvement but it doesn't help when reading
the source code.


Yeah, I think there's a few things we can do in the source too. We
should find the common combinations and abstract them out, like I said
before, isInputRangeOf is potentially useful.

Though, like Andrei, I'm skeptical on doing too much of that, since
the combinations can quickly explode and then you just have to search
through more to figure out wtf they mean.

That'd help the source and docs if we find the right balance.


I submitted a Phobos PR for `isInputRangeOf`. It was nuked from orbit. I
understand why: as you mention, the combinatorial explosion of names is
an issue. But: it's a mess rangeifying code when this:

void fun(Foo[] foos);  // yay! readable

becomes:

void fun(R)(R foos) if(isInputRange!R && is(Unqual!(ElementType!R) == Foo);


If you find a number of these, that would be good evidence. -- Andrei



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread Atila Neves via Digitalmars-d
On Wednesday, 15 February 2017 at 17:10:26 UTC, Adam D. Ruppe 
wrote:
On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob Carlborg 
wrote:
Your documentation is an improvement but it doesn't help when 
reading the source code.


Yeah, I think there's a few things we can do in the source too. 
We should find the common combinations and abstract them out, 
like I said before, isInputRangeOf is potentially useful.


Though, like Andrei, I'm skeptical on doing too much of that, 
since the combinations can quickly explode and then you just 
have to search through more to figure out wtf they mean.


That'd help the source and docs if we find the right balance.


I submitted a Phobos PR for `isInputRangeOf`. It was nuked from 
orbit. I understand why: as you mention, the combinatorial 
explosion of names is an issue. But: it's a mess rangeifying code 
when this:


void fun(Foo[] foos);  // yay! readable

becomes:

void fun(R)(R foos) if(isInputRange!R && 
is(Unqual!(ElementType!R) == Foo);


Ugh.

Atila


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread ZombineDev via Digitalmars-d
On Thursday, 16 February 2017 at 07:48:37 UTC, Jacob Carlborg 
wrote:

On 2017-02-16 01:40, John Colvin wrote:


Slightly OT, but it is related so bear with me:

Design by introspection is great and prevent having to make 
new names
for every possible combo of features. Unfortunately, it 
doesn't work so
well for introspecting multiple types at once: normally you 
have to then
make a new symbol, with a new name, to pass to e.g. 
allSatisfy. That
annoys me, so I've been wanting this sort of thing for a while 
(which
would also make `every` way better to use, instead of having 
to make a

name for every predicate:

You know how we have named parameterised enums and aliases?
enum isInt(a) = is(a == int);
and
alias sizeof(a) = a.sizeof;

why not allow *anonymous* parameterised enums and aliases, 
like this:


enum areAllInt(TL ...) = allSatisfy!(enum(a) => is(a == int), 
TL);


void foo(TL...)(TL args)
if (allSatisfy!(enum(T) => T.sizeof <= 4, TL))
{
// ...
}


I've been thinking something similar. But this is the way I see 
it:


A lambda is an anonymous template function which is not yet 
instantiated. But with the lambda syntax only one the different 
template parameters are allowed. Why not generalize the lambda 
syntax to allow different kind of template parameters. Example:


What we have today:

[1, 2, 3].map!(e => e * 2);

Is basically the same as:

T __anonymous(T)(T e)
{
return e * 2;
}

[1, 2, 3].map!(__anonymous!(int));

But today we cannot represent the following template with a 
lambda:


size_t sizeof(alias a)()
{
return a.sizeof;
}

So why not allow this lambda syntax:

alias sizeof = (alias a) => a.sizeof;

It would be nice if we could reuse the existing syntax for 
regular template parameters as well:


alias isInt = t => is(t == int);
auto b = isInt!(int);

If the above is not possible, we could add an additional 
parameter list to lambdas:


alias isInt = (t)() => is(t == int);


You can sort of do this even today. All you need is struct with 
template-ed opCall.


See 
https://github.com/ZombineDev/rxd/blob/v0.0.3/source/rxd/meta2/lambda.d#L12 and

https://github.com/ZombineDev/rxd/blob/v0.0.3/source/rxd/xf/xform.d#L54

This one of the few (only?) places that C++14 is better than D, 
because in C++14 polymorphic lamdas are first-class values, 
whereas in D alias function literals are templates (i.e. you can 
refer to them only by alias, can't assign them to enum or auto 
constants / variables).


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread ZombineDev via Digitalmars-d
On Thursday, 16 February 2017 at 07:34:02 UTC, Jacob Carlborg 
wrote:

On 2017-02-16 01:37, ZombineDev wrote:

BTW, shouldn't we use `enum`, instead of `auto`, since 
everywhere else
`enum` means guaranteed to be computed at compile-time whereas 
`auto`

means the opposite?


Far enough, since it's not possible to change the parameter 
inside the function anyway.


Question though, what happens with an array literal, example:

void foo(int[] a = [1, 2, 3])()
{
auto b = a; // allocation ?
auto c = a; // allocation ?
}

As far as I understand, if an array is declared as a manifest 
constant it will cause a new allocation for each time it's used.


enum a = [1, 2, 3];
auto b = a; // new allocation
auto c = a; // new allocation

What happens when an array literal is a default value for a 
template parameter?


enums are just literals - values without identity. This means 
that if you need them at runtime, the compiler will need to 
allocate storage for each time they are used. In cases where such 
a values is used in more places, it may be more economical to 
assign it to a static immutable variable and reference it in 
place of the enum.


In the case of template parameters I would expect this to be even 
more true, because an array by definition is a contiguous chunk 
of memory and a template parameter is something encoded in the 
mangled name of the symbol at runtime, so the compiler can't get 
away from allocating additional storage for each usage of the 
template value parameter at runtime.


(@compiler devs, please correct me if I am wrong)


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-16 Thread ZombineDev via Digitalmars-d

On Thursday, 16 February 2017 at 00:40:19 UTC, John Colvin wrote:
On Wednesday, 15 February 2017 at 19:39:52 UTC, Andrei 
Alexandrescu wrote:

On 02/15/2017 06:20 AM, Daniel N wrote:
On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N 
wrote:

template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}


(lunch-break => time to hack D!)

template every(T...)
{
  template satisfies(U...)
  {
enum satisfies = {
  foreach(t; T)
foreach(u; U)
  if(!u!t)
return false;
  return true;
}();
  }
}


That looks pretty neat. Can you find 4-5 cases in which this 
could be used gainfully in Phobos? Thanks! -- Andrei


Slightly OT, but it is related so bear with me:

Design by introspection is great and prevent having to make new 
names for every possible combo of features. Unfortunately, it 
doesn't work so well for introspecting multiple types at once: 
normally you have to then make a new symbol, with a new name, 
to pass to e.g. allSatisfy. That annoys me, so I've been 
wanting this sort of thing for a while (which would also make 
`every` way better to use, instead of having to make a name for 
every predicate:


You know how we have named parameterised enums and aliases?
enum isInt(a) = is(a == int);
and
alias sizeof(a) = a.sizeof;

why not allow *anonymous* parameterised enums and aliases, like 
this:


enum areAllInt(TL ...) = allSatisfy!(enum(a) => is(a == int), 
TL);


void foo(TL...)(TL args)
if (allSatisfy!(enum(T) => T.sizeof <= 4, TL))
{
// ...
}

[snip]



I have a library that allows just that, but with even shorter 
syntax :P


https://github.com/ZombineDev/rxd/blob/v0.0.3/source/rxd/xf/xform.d#L50
https://github.com/ZombineDev/rxd/blob/v0.0.3/source/rxd/meta2/type.d#L241

Though I have feeling that it will make uplinkCoder cringe, 
because of the pressure it is probably putting on the compiler :D


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-16 01:40, John Colvin wrote:


Slightly OT, but it is related so bear with me:

Design by introspection is great and prevent having to make new names
for every possible combo of features. Unfortunately, it doesn't work so
well for introspecting multiple types at once: normally you have to then
make a new symbol, with a new name, to pass to e.g. allSatisfy. That
annoys me, so I've been wanting this sort of thing for a while (which
would also make `every` way better to use, instead of having to make a
name for every predicate:

You know how we have named parameterised enums and aliases?
enum isInt(a) = is(a == int);
and
alias sizeof(a) = a.sizeof;

why not allow *anonymous* parameterised enums and aliases, like this:

enum areAllInt(TL ...) = allSatisfy!(enum(a) => is(a == int), TL);

void foo(TL...)(TL args)
if (allSatisfy!(enum(T) => T.sizeof <= 4, TL))
{
// ...
}


I've been thinking something similar. But this is the way I see it:

A lambda is an anonymous template function which is not yet 
instantiated. But with the lambda syntax only one the different template 
parameters are allowed. Why not generalize the lambda syntax to allow 
different kind of template parameters. Example:


What we have today:

[1, 2, 3].map!(e => e * 2);

Is basically the same as:

T __anonymous(T)(T e)
{
return e * 2;
}

[1, 2, 3].map!(__anonymous!(int));

But today we cannot represent the following template with a lambda:

size_t sizeof(alias a)()
{
return a.sizeof;
}

So why not allow this lambda syntax:

alias sizeof = (alias a) => a.sizeof;

It would be nice if we could reuse the existing syntax for regular 
template parameters as well:


alias isInt = t => is(t == int);
auto b = isInt!(int);

If the above is not possible, we could add an additional parameter list 
to lambdas:


alias isInt = (t)() => is(t == int);

--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-16 01:37, ZombineDev wrote:


BTW, shouldn't we use `enum`, instead of `auto`, since everywhere else
`enum` means guaranteed to be computed at compile-time whereas `auto`
means the opposite?


Far enough, since it's not possible to change the parameter inside the 
function anyway.


Question though, what happens with an array literal, example:

void foo(int[] a = [1, 2, 3])()
{
auto b = a; // allocation ?
auto c = a; // allocation ?
}

As far as I understand, if an array is declared as a manifest constant 
it will cause a new allocation for each time it's used.


enum a = [1, 2, 3];
auto b = a; // new allocation
auto c = a; // new allocation

What happens when an array literal is a default value for a template 
parameter?


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread John Colvin via Digitalmars-d

On Thursday, 16 February 2017 at 00:37:00 UTC, ZombineDev wrote:
On Thursday, 16 February 2017 at 00:08:12 UTC, Walter Bright 
wrote:
On 2/15/2017 12:31 PM, Jonathan M Davis via Digitalmars-d 
wrote:
It's one of those features that I was surprised when you 
couldn't do it.


It was an oversight. We just never thought of it.


What do you think about generalizing this feature to allow 
introducing template value parameters without default value, 
i.e.:


// Note: `beg` and `end` have no default value

auto bounded
(auto beg, auto end, auto onErrPolicy = Enforce("Value out 
of range"), T)

(T value)
{
return Bounded!(beg, end, Policy)(value);
}



note that this would still be usable with constraits via e.g. 
if(is(typeof(beg) : int))


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread John Colvin via Digitalmars-d
On Wednesday, 15 February 2017 at 19:39:52 UTC, Andrei 
Alexandrescu wrote:

On 02/15/2017 06:20 AM, Daniel N wrote:

On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N wrote:

template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}


(lunch-break => time to hack D!)

template every(T...)
{
  template satisfies(U...)
  {
enum satisfies = {
  foreach(t; T)
foreach(u; U)
  if(!u!t)
return false;
  return true;
}();
  }
}


That looks pretty neat. Can you find 4-5 cases in which this 
could be used gainfully in Phobos? Thanks! -- Andrei


Slightly OT, but it is related so bear with me:

Design by introspection is great and prevent having to make new 
names for every possible combo of features. Unfortunately, it 
doesn't work so well for introspecting multiple types at once: 
normally you have to then make a new symbol, with a new name, to 
pass to e.g. allSatisfy. That annoys me, so I've been wanting 
this sort of thing for a while (which would also make `every` way 
better to use, instead of having to make a name for every 
predicate:


You know how we have named parameterised enums and aliases?
enum isInt(a) = is(a == int);
and
alias sizeof(a) = a.sizeof;

why not allow *anonymous* parameterised enums and aliases, like 
this:


enum areAllInt(TL ...) = allSatisfy!(enum(a) => is(a == int), TL);

void foo(TL...)(TL args)
if (allSatisfy!(enum(T) => T.sizeof <= 4, TL))
{
// ...
}

an example from phobos:

bool ordered(alias less = "a < b", T...)(T values)
if (T.length == 2 && is(typeof(binaryFun!less(values[1], 
values[0])) : bool) || T.length > 2 && 
is(typeof(ordered!less(values[0..1 + $ / 2]))) && 
is(typeof(ordered!less(values[$ / 2..$]


becomes this:

bool ordered(alias less = "a < b", T...)(T values)
if (T.length > 2 &&
allSatisfy!(enum(size_t i) =>
   is(typeof(binaryFun!less(values[i], 
values[i+1])) : bool),

Iota!(T.length - 1))

I admit it's not a huge win, but hiding the log_2(N) template 
depth behind allSatisfy is great: you shouldn't have to (and 
people wont) think about that when writing a template constraint 
like this.


There is a part of me that thinks all this meta-template stuff is 
madness though and that modifications to ctfe could make it 
mostly obsolete, but that's a story for later...


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread ZombineDev via Digitalmars-d
On Thursday, 16 February 2017 at 00:08:12 UTC, Walter Bright 
wrote:

On 2/15/2017 12:31 PM, Jonathan M Davis via Digitalmars-d wrote:
It's one of those features that I was surprised when you 
couldn't do it.


It was an oversight. We just never thought of it.


What do you think about generalizing this feature to allow 
introducing template value parameters without default value, i.e.:


// Note: `beg` and `end` have no default value

auto bounded
(auto beg, auto end, auto onErrPolicy = Enforce("Value out of 
range"), T)

(T value)
{
return Bounded!(beg, end, Policy)(value);
}

struct Enforce
{ this(string) { /* */ } }

int tmp;
readf("%s", &x);

enum policy = Enforce("User age must be between 18 and 150");
auto userAge = bounded!(18, 150, policy)(tmp);

"Declaring non-type template arguments with auto" is also coming 
to C++17: 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0127r1.html


BTW, shouldn't we use `enum`, instead of `auto`, since everywhere 
else `enum` means guaranteed to be computed at compile-time 
whereas `auto` means the opposite?


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

On 2/15/2017 12:31 PM, Jonathan M Davis via Digitalmars-d wrote:

It's one of those features that I was surprised when you couldn't do it.


It was an oversight. We just never thought of it.



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d
Also, as mentioned in the std.algorithm.mutation.remove case, constraints in 
Phobos often confuse "requirements" with "specializations".


Requirements should be user-facing constraints, while specializations are 
implementation details better handled with internal static if.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

On 2/15/2017 1:24 PM, Jonathan M Davis via Digitalmars-d wrote:

So, regardless of the exact terminology, we have a whole set of very similar
but subtly different traits. And as it stands, they _will_ get screwed up
unless someone is carefully looking at each to make sure that they actually
use the right one as well as testing with various types that frequently get
missed in unit tests - like types which use alias this or enums with a base
type of string.


I suspect the only way forward is to go through Phobos and collect all the 
plethora of constraints used for strings, and examine them for commonalities. 
Not doing this will just result in more accumulation of confusing junk.




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Andrei Alexandrescu via Digitalmars-d

On 02/15/2017 03:31 PM, Jonathan M Davis via Digitalmars-d wrote:

On Wednesday, February 15, 2017 14:30:02 Andrei Alexandrescu via
Digitalmars-d wrote:

On 02/15/2017 02:22 PM, Jacob Carlborg wrote:

On 2017-02-15 15:01, Andrei Alexandrescu wrote:

That's nice, could you please submit as an enhancement request on
bugzilla?


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


Thanks. I'll take it up to Walter for preapproval. -- Andrei


It's one of those features that I was surprised when you couldn't do it.


We agree. It's preapproved now. -- Andrei


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread H. S. Teoh via Digitalmars-d
On Wed, Feb 15, 2017 at 09:03:46PM +, Jack Stouffer via Digitalmars-d wrote:
> On Wednesday, 15 February 2017 at 20:54:02 UTC, Walter Bright wrote:
> > I'd like to take a step back and devise a consistent taxonomy of these
> > things
> 
> Ok
> 
> > 1. auto decoding dynamic arrays
> 
> Narrow strings
> 
> > 2. not auto decoding arrays
> 
> Wide strings
> 
> > 3. static arrays
> 
> Do these need to be called anything other than "static arrays"? Also,
> they're not ranges, so they're usually tested with isStaticArray
> 
> > 4. aggregates with an 'alias this' to a string
> 
> isConvertibleToString
> 
> > 5. ranges of characters
> 
> Character range
> 
> > 6. something convertible to a string
> 
> Same as 4

This describes the current state of Phobos, but I think what Walter is
driving at is, does it *have* to be this way?  I think we can (and
should) simplify this taxonomy to avoid needless duplication and also
create a more consistent conceptual model of how Phobos deals with
strings and string-like things.

First of all, I think we should try out best to avoid treating arrays
and character ranges differently.  I know this is inevitable because
we're still in a state where autodecoding can't be fully eliminated yet,
but as far as possible, I think we should try to treat them the same
way.

(1) Functions that need to work with string contents (e.g., find,
toUpperCase, etc.) should in general accept any input ranges whose
elements are convertible in some way to dchar.  Some of these functions
may require forward ranges or bidirectional / random-access ranges. Most
of these functions can allow infinite ranges (so we only need the
occasional !isInfinite check).

(2) Functions that don't need to work with string contents, i.e., the
strings are treated as opaque blobs to be passed to, say, an underlying
OS function, require finite ranges, but should be able to work with any
type that converts to string in one form or another.  So anything from
(finite) ranges of char-like elements to aggregates with alias this to
string ought to be accepted.  They can be internally converted to
strings if necessary (e.g., to pass to an OS call).

I suspect that many of the functions in category (1) can be coalesced
with generic range algorithms, so they should not even be exposing their
sig constraints in the public API.  Instead, they should take a generic
range and then use static if or module-private helper functions to
dispatch to the right implementation(s).

Category (2) functions can internally call helpers (maybe in std.string
or std.array) that convert any incoming type that can be converted to
string in some way.

As for static arrays, I think the consensus is (was?) that they are not
ranges, and so the user is required to take a slice before handing it to
a Phobos function expecting string or string-like arguments. Well,
actually, not just string-like things, but anything to do with ranges.
I don't think there's a need to treat static arrays of char separately
from static arrays in general.


T

-- 
Bare foot: (n.) A device for locating thumb tacks on the floor.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

On 2/15/2017 1:03 PM, Jack Stouffer wrote:

On Wednesday, 15 February 2017 at 20:54:02 UTC, Walter Bright wrote:

I'd like to take a step back and devise a consistent taxonomy of these things


Ok


1. auto decoding dynamic arrays


Narrow strings


2. not auto decoding arrays


Wide strings


3. static arrays


Do these need to be called anything other than "static arrays"? Also, they're
not ranges, so they're usually tested with isStaticArray


4. aggregates with an 'alias this' to a string


isConvertibleToString


5. ranges of characters


Character range


6. something convertible to a string


Same as 4



That's a good start. A test of that is to look at Phobos' actual usage of 
constraints and see if they fit in.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, February 15, 2017 21:03:46 Jack Stouffer via Digitalmars-d 
wrote:
> On Wednesday, 15 February 2017 at 20:54:02 UTC, Walter Bright
>
> wrote:
> > I'd like to take a step back and devise a consistent taxonomy
> > of these things
>
> Ok
>
> > 1. auto decoding dynamic arrays
>
> Narrow strings
>
> > 2. not auto decoding arrays
>
> Wide strings
>
> > 3. static arrays
>
> Do these need to be called anything other than "static arrays"?
> Also, they're not ranges, so they're usually tested with
> isStaticArray
>
> > 4. aggregates with an 'alias this' to a string
>
> isConvertibleToString
>
> > 5. ranges of characters
>
> Character range
>
> > 6. something convertible to a string
>
> Same as 4

Except that you're forgetting enums. Also, there's this mess:

enum bool isNarrowString(T) =
(is(T : const char[]) || is(T : const wchar[])) &&
!isAggregateType!T &&
!isStaticArray!T;

enum bool isAutodecodableString(T) =
(is(T : const char[]) || is(T : const wchar[])) &&
!isStaticArray!T;

A type with alias this passes isAutodecodableString but not isNarrowString,
making for really subtle difference. Also, enums of strings pass both, which
is potentially a problem as they really should be treated the same as types
with alias this given how they need to be used in a templated function.
enums also pass isSomeString, which makes using isSomeString a no-go for any
range-based function if it doesn't then test for enums - but aggregate types
_don't_ pass isSomeString. And then there's

template isConvertibleToString(T)
{
enum isConvertibleToString =
(isAggregateType!T || isStaticArray!T || is(T == enum))
&& is(StringTypeOf!T);
}

So, regardless of the exact terminology, we have a whole set of very similar
but subtly different traits. And as it stands, they _will_ get screwed up
unless someone is carefully looking at each to make sure that they actually
use the right one as well as testing with various types that frequently get
missed in unit tests - like types which use alias this or enums with a base
type of string.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jack Stouffer via Digitalmars-d
On Wednesday, 15 February 2017 at 20:54:02 UTC, Walter Bright 
wrote:
I'd like to take a step back and devise a consistent taxonomy 
of these things


Ok


1. auto decoding dynamic arrays


Narrow strings


2. not auto decoding arrays


Wide strings


3. static arrays


Do these need to be called anything other than "static arrays"? 
Also, they're not ranges, so they're usually tested with 
isStaticArray



4. aggregates with an 'alias this' to a string


isConvertibleToString


5. ranges of characters


Character range


6. something convertible to a string


Same as 4



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

Please fix your newsreader so it submits postings in text format, not html.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, February 15, 2017 12:54:02 Walter Bright via Digitalmars-d 
wrote:
> On 2/15/2017 10:51 AM, Andrei Alexandrescu wrote:
> > isStringLike. I wanted to add this for a while already. Please do! --
> > Andrei
> What I've found messy and confusing with string overloads in Phobos is
> there are at least 6 kinds of strings:
>
> 1. auto decoding dynamic arrays
> 2. not auto decoding arrays
> 3. static arrays
> 4. aggregates with an 'alias this' to a string
> 5. ranges of characters
> 6. something convertible to a string
>
> These classifications seem to be tested for in a unique ad-hoc manner in
> every case.
>
> I'd like to take a step back and devise a consistent taxonomy of these
> things, based on how Phobos uses them, before adding more names.

Yeah. It's a bit of a mess. And types with alias this and enums _really_
don't help things.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

On 2/15/2017 10:51 AM, Andrei Alexandrescu wrote:

isStringLike. I wanted to add this for a while already. Please do! -- Andrei


What I've found messy and confusing with string overloads in Phobos is there are 
at least 6 kinds of strings:


1. auto decoding dynamic arrays
2. not auto decoding arrays
3. static arrays
4. aggregates with an 'alias this' to a string
5. ranges of characters
6. something convertible to a string

These classifications seem to be tested for in a unique ad-hoc manner in every 
case.

I'd like to take a step back and devise a consistent taxonomy of these things, 
based on how Phobos uses them, before adding more names.




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, February 15, 2017 14:30:02 Andrei Alexandrescu via 
Digitalmars-d wrote:
> On 02/15/2017 02:22 PM, Jacob Carlborg wrote:
> > On 2017-02-15 15:01, Andrei Alexandrescu wrote:
> >> That's nice, could you please submit as an enhancement request on
> >> bugzilla?
> >
> > https://issues.dlang.org/show_bug.cgi?id=17186
>
> Thanks. I'll take it up to Walter for preapproval. -- Andrei

It's one of those features that I was surprised when you couldn't do it.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Nick Treleaven via Digitalmars-d
On Wednesday, 15 February 2017 at 20:09:46 UTC, Timothee Cour 
wrote:
This thread completely diverged from the original post, which 
was propsing `::` instead of `from!`:


```
void fun(T)(std.stdio::File input, T value) if 
(std.traits::isIntegral!T)

{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T)
{...}
```

I see it as a clear improvment in readability (see original 
post for details along with shortcomings of `from!` approach )


I really think allowing `with (module_!"std.foo")` before 
declarations is a better solution from a DRY perspective, plus it 
works for UFCS. This is a more general change that has other 
benefits that apply to any static aggregate e.g. enum names - 
`with(Enum)`, not just imports.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Seb via Digitalmars-d
On Wednesday, 15 February 2017 at 18:51:40 UTC, Andrei 
Alexandrescu wrote:

On 02/15/2017 12:18 PM, Seb wrote:


uint getAttributes(R)(R name)
if (isInputRange!R && !isInfinite!R &&
isSomeChar!(ElementEncodingType!R) && 
!isConvertibleToString!R);



Now as this same block is used > 30x in Phobos one could argue 
that it

makes sense to use a convenience trait like:


isStringLike. I wanted to add this for a while already. Please 
do! -- Andrei


https://github.com/dlang/phobos/pull/5137


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Timothee Cour via Digitalmars-d
This thread completely diverged from the original post, which was propsing
`::` instead of `from!`:

```
void fun(T)(std.stdio::File input, T value) if (std.traits::isIntegral!T)
{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T)
{...}
```

I see it as a clear improvment in readability (see original post for
details along with shortcomings of `from!` approach )


On Wed, Feb 15, 2017 at 11:39 AM, Andrei Alexandrescu via Digitalmars-d <
digitalmars-d@puremagic.com> wrote:

> On 02/15/2017 06:20 AM, Daniel N wrote:
>
>> On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N wrote:
>>
>>> template every(T...)
>>> {
>>> template satisfies(U...)
>>> {
>>> enum satisfies = true;
>>> }
>>> }
>>>
>>
>> (lunch-break => time to hack D!)
>>
>> template every(T...)
>> {
>>   template satisfies(U...)
>>   {
>> enum satisfies = {
>>   foreach(t; T)
>> foreach(u; U)
>>   if(!u!t)
>> return false;
>>   return true;
>> }();
>>   }
>> }
>>
>
> That looks pretty neat. Can you find 4-5 cases in which this could be used
> gainfully in Phobos? Thanks! -- Andrei
>
>
>


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Andrei Alexandrescu via Digitalmars-d

On 02/15/2017 06:20 AM, Daniel N wrote:

On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N wrote:

template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}


(lunch-break => time to hack D!)

template every(T...)
{
  template satisfies(U...)
  {
enum satisfies = {
  foreach(t; T)
foreach(u; U)
  if(!u!t)
return false;
  return true;
}();
  }
}


That looks pretty neat. Can you find 4-5 cases in which this could be 
used gainfully in Phobos? Thanks! -- Andrei





Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Andrei Alexandrescu via Digitalmars-d

On 02/15/2017 02:22 PM, Jacob Carlborg wrote:

On 2017-02-15 15:01, Andrei Alexandrescu wrote:


That's nice, could you please submit as an enhancement request on
bugzilla?


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


Thanks. I'll take it up to Walter for preapproval. -- Andrei



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-15 15:01, Andrei Alexandrescu wrote:


That's nice, could you please submit as an enhancement request on bugzilla?


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

--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Andrei Alexandrescu via Digitalmars-d

On 02/15/2017 12:18 PM, Seb wrote:


uint getAttributes(R)(R name)
if (isInputRange!R && !isInfinite!R &&
isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R);


Now as this same block is used > 30x in Phobos one could argue that it
makes sense to use a convenience trait like:


isStringLike. I wanted to add this for a while already. Please do! -- Andrei


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Adam D. Ruppe via Digitalmars-d

On Wednesday, 15 February 2017 at 17:18:15 UTC, Seb wrote:

Now as this same block is used > 30x in Phobos


That tells me you already have an empirical clear win! If you 
wrote exactly the same thing 30x inside the functions, you'd move 
it out to a new function too.



if (isSomeInputRangeChar!R)

What's your opinion on such a case?


Yeah, I'd say do it, and it is similar to isSomeString in use 
elsewhere.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Adam D. Ruppe via Digitalmars-d
On Wednesday, 15 February 2017 at 16:20:30 UTC, Chris Wright 
wrote:
The greatest annoyance is if I have to read through several 
files of phobos sources just to figure out why there's no 
matching overload for this function call that looks right to me.


I really really REALLY REALLY wish the compiler would tell you at 
least which part of the boolean expression failed. Then, at 
least, you could dig deeper with your own static asserts on those 
individual things or something.


tbh I actually want opt-in XML error messages with obscene levels 
of detail. We'd pwn IDE integration with that and can really save 
programmers wads of time by giving them all the info they 
actually need.


D used to promote its readable error messages as a strength over 
C++. We've fallen far behind in that category now.


 This doc improvement means I only have to go to
dpldocs.info (which I'm probably already at), search for the 
term, and click a few times.


indeed, I'm pretty happy with my navigation. And I'm slowly but 
surely fixing the automatic cross referencing. D name lookup 
across modules is kinda hard, this is one place dmd/ddoc would 
have a strong theoretical advantage since it understands the 
semantics and already knows the module graph.


But, I'm already 80% there... and it is yielding pretty great 
results in practice. I'll do alias lookups next time I spend a 
few hours on this (tbh since it is good enough for me, it is all 
low priority relative to the other things I have to do, so it is 
moving slowly now.)


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Seb via Digitalmars-d
On Wednesday, 15 February 2017 at 17:10:26 UTC, Adam D. Ruppe 
wrote:
On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob Carlborg 
wrote:
Your documentation is an improvement but it doesn't help when 
reading the source code.


Yeah, I think there's a few things we can do in the source too. 
We should find the common combinations and abstract them out, 
like I said before, isInputRangeOf is potentially useful.


Though, like Andrei, I'm skeptical on doing too much of that, 
since the combinations can quickly explode and then you just 
have to search through more to figure out wtf they mean.


That'd help the source and docs if we find the right balance.


Speaking of right balance, there's currently a PR at Phobos that 
is a good candidate to get a common measure on how this balance 
should be set:


https://github.com/dlang/phobos/pull/5132

The open question here is that for nearly every function in 
std.file & std.path the constraint block looks like this:


uint getAttributes(R)(R name)
if (isInputRange!R && !isInfinite!R && 
isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R);



Now as this same block is used > 30x in Phobos one could argue 
that it makes sense to use a convenience trait like:


enum isSomeInputRangeChar(R) = isInputRange!R && !isInfinite!R && 
isSomeChar!(ElementEncodingType!R) && !isConvertibleToString!R


which would obviously lead to:

uint getAttributes(R)(R name)
if (isSomeInputRangeChar!R)

What's your opinion on such a case?


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Adam D. Ruppe via Digitalmars-d
On Wednesday, 15 February 2017 at 07:56:00 UTC, Jacob Carlborg 
wrote:
Your documentation is an improvement but it doesn't help when 
reading the source code.


Yeah, I think there's a few things we can do in the source too. 
We should find the common combinations and abstract them out, 
like I said before, isInputRangeOf is potentially useful.


Though, like Andrei, I'm skeptical on doing too much of that, 
since the combinations can quickly explode and then you just have 
to search through more to figure out wtf they mean.


That'd help the source and docs if we find the right balance.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Chris Wright via Digitalmars-d
On Wed, 15 Feb 2017 08:56:00 +0100, Jacob Carlborg wrote:
> Your documentation is an improvement but it doesn't help when reading
> the source code.

For me, it almost entirely obviates reading the source code. I only need 
to read it if I'm trying to modify it, at which point I'm already 
committing to spend at least thirty minutes on it.

The greatest annoyance is if I have to read through several files of 
phobos sources just to figure out why there's no matching overload for 
this function call that looks right to me. This doc improvement means I 
only have to go to dpldocs.info (which I'm probably already at), search 
for the term, and click a few times. I don't have to pull out grep, peer 
myopically through the pages of results, and figure out which ones are the 
definitions of the template constraints I need.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Chris Wright via Digitalmars-d
On Wed, 15 Feb 2017 05:28:11 +, Adam D. Ruppe wrote:

> On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:
>> A further improvement in the documentation would be to add links to
>> isBidirectionalRange and hasLvalueElements.
> 
> Kneel before your god!

We're not worthy!


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, February 15, 2017 14:35:40 Jack Stouffer via Digitalmars-d 
wrote:
> On Wednesday, 15 February 2017 at 08:53:30 UTC, Jacob Carlborg
>
> wrote:
> > "The static if feature recently proposed for C++ [1, 2] is
> > fundamentally flawed, and its adoption would be a disaster for
> > the language"
> > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf
>
> I honestly feel bad for the C++ people here. Looks like someone
> didn't explain the benefits/uses of static if very well.
>
> It also looks like they failed to point to Phobos as an example
> of great static if usage. I imagine many heads would explode
> after seeing Andrei's `find` improvements with static if.

LOL. It would be interesting to know which parts of D or Phobos blew
people's minds. Personally, startsWith blew my mind. I remember taking up
the challenge of making endsWith work with all of the same kind of arguments
that startsWith did, and at the time, I had no idea how startsWith was
implemented. Seeing how it used recursive template instantiations definitely
took a bit to wrap my mind around and was _very_ eye opening.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jack Stouffer via Digitalmars-d
On Wednesday, 15 February 2017 at 14:01:28 UTC, Andrei 
Alexandrescu wrote:
It still has a cargo cult flavor because it introduces a new 
scope, which kinda misses the point of static if.


That's an understatement.

Having static if introduce a new scope makes static if useless. 
Creating a new scope means that code duplication inside of a 
function is now a must. At that point you might as well just make 
what you were going to put in the other static if branch as a 
different overload.


It also means design by introspection/range composition is now 
impossible.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jack Stouffer via Digitalmars-d
On Wednesday, 15 February 2017 at 08:53:30 UTC, Jacob Carlborg 
wrote:
"The static if feature recently proposed for C++ [1, 2] is 
fundamentally flawed, and its adoption would be a disaster for 
the language" 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf


I honestly feel bad for the C++ people here. Looks like someone 
didn't explain the benefits/uses of static if very well.


It also looks like they failed to point to Phobos as an example 
of great static if usage. I imagine many heads would explode 
after seeing Andrei's `find` improvements with static if.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jack Stouffer via Digitalmars-d

On Tuesday, 14 February 2017 at 22:01:47 UTC, H. S. Teoh wrote:
Thankfully, the docs for std.conv.to have been greatly improved 
since the last time I had to work with the code -- everything 
is now consolidated under a single template function 
std.conv.to, and the implementation details are hidden behind 
module-private overloads. This is the way it should be.


I'm currently trying to do this again in std.format, this is the 
first step: https://github.com/dlang/phobos/pull/5130


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Andrei Alexandrescu via Digitalmars-d

On 2/15/17 3:53 AM, Jacob Carlborg wrote:

I do see a possibility for a slightly improvement in a different area,
in the example of "remove". If we look at the signature, without the
constraints:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)

Why isn't it possible to use "auto" when declaring a parameter with a
default argument?

Range remove
(auto s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)

A minor improvement, but I also feel like it would lift an arbitrary
limitation in the language.


That's nice, could you please submit as an enhancement request on bugzilla?


I haven't followed the C++ concepts lately either and not very closely
at all so I don't feel I can comment on the C++ concepts.


You may want to correct that if you want to make a serious proposal for 
D concepts.



But if I
recall correctly, you're "static if" proposal wasn't well received [1].
But now with "if constexpr" it looks like they're changing their minds.

[1] "The static if feature recently proposed for C++ [1, 2] is
fundamentally flawed, and its adoption would be a disaster for the
language" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf


"I made a terrible mistake" is spelled 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0128r0.html 
here. It still has a cargo cult flavor because it introduces a new 
scope, which kinda misses the point of static if.



Andrei




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:

Range remove

[...]

But there's another issue here. remove() has other overloads:

[...]


Two constraints are common to all three, those are the only 
ones that actually need to be in the constraint. The others can 
go in the body under `static if`, as the user need not be 
concerned with them.


This is a general issue in Phobos that too many constraints are 
user-facing when they don't need to be.


This!

Getting rid of overloads and at the same time simplify the 
constraints by moving them in the function with static if!

That would really improve the function signatures!


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Atila Neves via Digitalmars-d
On Tuesday, 14 February 2017 at 16:25:17 UTC, Andrei Alexandrescu 
wrote:

On 02/14/2017 10:49 AM, Jacob Carlborg wrote:

On 2017-02-14 15:37, Andrei Alexandrescu wrote:


How are they so,


Example [1]. That signature spans 8 lines, it took me 10 
seconds to find

the actual function name.


Copying here to make things easier:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

The function name is on the first line. I think 10 seconds 
would be an exaggeration of an admittedly real issue.



Example [2], 5 lines.


Copying here as well (reflowed for email):

Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, 
InputRange2 r2)

if (isInputRange!(InputRange1) && isInputRange!(InputRange2)
&& hasSwappableElements!(InputRange1)
&& hasSwappableElements!(InputRange2)
&& is(ElementType!(InputRange1) == 
ElementType!(InputRange2)));


One immediate matter here is redundant parens, of which 
elimination would lead to the marginally more palatable:


Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, 
InputRange2 r2)

if (isInputRange!InputRange1 && isInputRange!InputRange2
&& hasSwappableElements!InputRange1
&& hasSwappableElements!InputRange2
&& is(ElementType!InputRange1 == ElementType!InputRange2));


and what steps can we take to improve them. Could you
please give a few examples on how to do things better? Thx! 
-- Andrei


Well, I would prefer to have template constraints as its own 
entity in
the language not not just a bunch of boolean conditions. This 
has been

talked about before several times. Something like:

constraint Foo
{
void foo();
}

void bar(T : Foo)(T t);


My recollection is past discussions got stalled because the 
approach is combinatorially bankrupt. How would one express the 
constraints of the functions above with simple named 
constraints? (Not rhetorical; please do provide an example if 
possible.) Before long there is an explosion in names 
("BidirectionalWithLvalueElementsAndLength", ...).


If I had my way, like so:

Tuple!(InputRange1, InputRange2)
swapRanges
(InputRange1: (InputRange, HasSwappableElements),
 InputRange2: (InputRange, HasSwappableElements))
(InputRange1 r1, InputRange2 r2)
if (is(ElementType!(InputRange1) == ElementType!(InputRange2)));

Assuming I'm still having my way, the above would result in the 
compiler telling me that given:


struct Foo {
 enum empty = false;
 enum front = 42;
}

If I tried to instantiate swapRanges!(Foo, Foo), I'd want to get 
something akin to:


error: foo.Foo does not satisfy InputRange: no function 
`popFront` for `foo.Foo`


For now I'm getting quite a bit of mileage from my concepts 
library.



Atila






Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread bachmeier via Digitalmars-d
On Wednesday, 15 February 2017 at 01:09:59 UTC, Chris Wright 
wrote:
Because now I have to look up the definition of fooConstraint 
and then I have to look up the definition of each element 
within it.


To be honest, I don't often look at function definitions for the 
template constraints, but this thread suggests that's the main 
reason others read source code. My opinion is that inlining the 
constraints greatly detracts from readability and provides little 
benefit in return. I also don't understand the problem with using 
simple names.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Daniel N via Digitalmars-d

On Wednesday, 15 February 2017 at 09:22:14 UTC, Daniel N wrote:

template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}


(lunch-break => time to hack D!)

template every(T...)
{
  template satisfies(U...)
  {
enum satisfies = {
  foreach(t; T)
foreach(u; U)
  if(!u!t)
return false;
  return true;
}();
  }
}



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Daniel N via Digitalmars-d
On Wednesday, 15 February 2017 at 08:59:49 UTC, Jacob Carlborg 
wrote:

On 2017-02-15 09:19, Walter Bright wrote:

On 2/14/2017 9:28 PM, Adam D. Ruppe wrote:
On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright 
wrote:
A further improvement in the documentation would be to add 
links to

isBidirectionalRange and hasLvalueElements.


Kneel before your god!

http://dpldocs.info/experimental-docs/std.algorithm.mutation.remove.1.html


Take a look at this insane automatic cross referencing:

http://dpldocs.info/experimental-docs/std.range.chain.html


My ref thing still isn't perfect, but dpldocs is already 
streets ahead of
anything dlang.org has to offer and continues to make bursts 
of strides.


That looks pretty sweet!


Doesn't help when reading the source code :(.


Something akin to this would improve readability at least for me, 
also more DRY.


   isInputRange!(InputRange1)
&& isInputRange!(InputRange2)
&& hasSwappableElements!(InputRange1)
&& hasSwappableElements!(InputRange2)

  =>

every!(InputRange1, InputRange2).
satisfies!(isInputRange, hasSwappableElements);



template every(T...)
{
template satisfies(U...)
{
enum satisfies = true;
}
}



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-15 09:19, Walter Bright wrote:

On 2/14/2017 9:28 PM, Adam D. Ruppe wrote:

On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:

A further improvement in the documentation would be to add links to
isBidirectionalRange and hasLvalueElements.


Kneel before your god!

http://dpldocs.info/experimental-docs/std.algorithm.mutation.remove.1.html


Take a look at this insane automatic cross referencing:

http://dpldocs.info/experimental-docs/std.range.chain.html


My ref thing still isn't perfect, but dpldocs is already streets ahead of
anything dlang.org has to offer and continues to make bursts of strides.


That looks pretty sweet!


Doesn't help when reading the source code :(.

--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-14 17:25, Andrei Alexandrescu wrote:


My recollection is past discussions got stalled because the approach is
combinatorially bankrupt. How would one express the constraints of the
functions above with simple named constraints? (Not rhetorical; please
do provide an example if possible.) Before long there is an explosion in
names ("BidirectionalWithLvalueElementsAndLength", ...).


Forgot to say that I don't think it's unreasonable to have a named 
constraint for each function (regardless if using only existing language 
features or adding something new). That way you can lift out the 
constraint separately from the function declaration. One way to make 
something complex less complex, is to split it up. It's not like you 
would have the complete source code of an application in a single file, 
that would be too much to read in one place (yes, there are other 
reasons to have multiple files). Same idea here.


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-14 17:25, Andrei Alexandrescu wrote:


My recollection is past discussions got stalled because the approach is
combinatorially bankrupt. How would one express the constraints of the
functions above with simple named constraints? (Not rhetorical; please
do provide an example if possible.)


It would obviously take a while for me to figure that out. Is not like I 
have a fully defined new language feature in my head.


I do see a possibility for a slightly improvement in a different area, 
in the example of "remove". If we look at the signature, without the 
constraints:


Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)

Why isn't it possible to use "auto" when declaring a parameter with a 
default argument?


Range remove
(auto s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)

A minor improvement, but I also feel like it would lift an arbitrary 
limitation in the language.


Alternatively something that Swift supports:

Range remove
(SwapStrategy s = .stable, Range, Offset...)
(Range range, Offset offset)

The compiler knows that the type of "s" is SwapStrategy, therefore 
"stable" has to be a member of SwapStrategy. In the case of D, the 
leading dot has a different meaning so another syntax would be required. 
Unfortunately this has already been discussed and rejected by Walter.



Before long there is an explosion in
names ("BidirectionalWithLvalueElementsAndLength", ...). This is what
has buried not one, but two concepts proposals for C++, leading to the
current Concepts Lite proposal.


I don't see that as a problem, but I would rather name it "Removable" or 
something that does not include all the conditions in the name. But I 
imagine that a constraint would consist of a combination of declarations 
(like an interface) and boolean conditions.


Lets look it differently. For a regular (non-template) function with a 
user defined type (class, struct). If it was possible to define the type 
inline, would you? I hope that answer is no. Example:


Standard D:

struct Bar
{
int a;
int b;
}

void foo(Bar bar);

With inline user defined types:

void foo(struct { int a; int b; } bar);

Assuming the answer is no, why would it be any different for a template 
type? You can see all the template constraints for a type as a form of 
metatype.



I haven't followed that lately but I
remember it combines an engineering effort to reduce the number of names
introduced (for the standard library only, which is a limitation) with
adding support to Boolean logic (surprise, surprise) to the feature (see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4377.pdf), the
most recent proposal, which was rejected for C++17. Over time, C++
concepts have moved from the broken combinatorially-bankrupt form slowly
toward D's Boolean constraints (just with a gratuitously awkward
notation). I presume they will be merged into the language when they'll
have capabilities comparable to D's system.

The question is, given this experience, do we want to move the opposite
direction?


I haven't followed the C++ concepts lately either and not very closely 
at all so I don't feel I can comment on the C++ concepts. But if I 
recall correctly, you're "static if" proposal wasn't well received [1]. 
But now with "if constexpr" it looks like they're changing their minds.


[1] "The static if feature recently proposed for C++ [1, 2] is 
fundamentally flawed, and its adoption would be a disaster for the 
language" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Walter Bright via Digitalmars-d

On 2/14/2017 9:28 PM, Adam D. Ruppe wrote:

On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:

A further improvement in the documentation would be to add links to
isBidirectionalRange and hasLvalueElements.


Kneel before your god!

http://dpldocs.info/experimental-docs/std.algorithm.mutation.remove.1.html

Take a look at this insane automatic cross referencing:

http://dpldocs.info/experimental-docs/std.range.chain.html


My ref thing still isn't perfect, but dpldocs is already streets ahead of
anything dlang.org has to offer and continues to make bursts of strides.


That looks pretty sweet!


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-15 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-15 06:28, Adam D. Ruppe wrote:


Kneel before your god!

http://dpldocs.info/experimental-docs/std.algorithm.mutation.remove.1.html

Take a look at this insane automatic cross referencing:

http://dpldocs.info/experimental-docs/std.range.chain.html


My ref thing still isn't perfect, but dpldocs is already streets ahead
of anything dlang.org has to offer and continues to make bursts of strides.


Your documentation is an improvement but it doesn't help when reading 
the source code.


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Adam D. Ruppe via Digitalmars-d

On Tuesday, 14 February 2017 at 20:46:17 UTC, Walter Bright wrote:
A further improvement in the documentation would be to add 
links to isBidirectionalRange and hasLvalueElements.


Kneel before your god!

http://dpldocs.info/experimental-docs/std.algorithm.mutation.remove.1.html

Take a look at this insane automatic cross referencing:

http://dpldocs.info/experimental-docs/std.range.chain.html


My ref thing still isn't perfect, but dpldocs is already streets 
ahead of anything dlang.org has to offer and continues to make 
bursts of strides.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Chris Wright via Digitalmars-d
On Tue, 14 Feb 2017 19:08:53 +, bachmeier wrote:
> I am not familiar with all of the past discussion of this issue, but
> something that I have wondered is why we can't do something like
> 
> alias fooConstraint = (s != SwapStrategy.stable
>&& isBidirectionalRange!Range && hasLvalueElements!Range &&
>hasLength!Range && Offset.length >= 1);
> 
> Range remove
>(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
>(Range range, Offset offset) if fooConstraint;

Because now I have to look up the definition of fooConstraint and then I 
have to look up the definition of each element within it.

If the entirety of the constraint is in the body of that helper template, 
that's a step up from what we have today. But that would involve code 
duplication, which people tend to dislike.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Chris Wright via Digitalmars-d
On Tue, 14 Feb 2017 21:33:00 +, Lurker wrote:

> On Tuesday, 14 February 2017 at 16:25:17 UTC, Andrei Alexandrescu wrote:
>> Range remove (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
>> (Range range, Offset offset)
>> if (s != SwapStrategy.stable
>> && isBidirectionalRange!Range && hasLvalueElements!Range &&
>> hasLength!Range && Offset.length >= 1);
>>
>>
> Range remove (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
> (Range range, Offset offset)
> if CanRemove!(s, range, offset);

Which adds another layer to determine what sort of arguments the thing 
requires. Fewer layers is better.

In the past, I tried to track down compilation errors in Phobos (due to my 
changes) relating to, I think, template overload selection in std.conv 
based on template constraints. It was hell. Multiple layers with `static 
if (__traits(compiles))` interspersed.

I'm not too keen on template constraints in general. If you need them, 
keep them short and keep the entire definition in one place.

>> The function name is on the first line. I think 10 seconds would be an
>> exaggeration of an admittedly real issue.
>>
>>
> Thought so, too, but then I *did* spend 10 seconds trying to find it
> myself!

Does your editor not have syntax highlighting? For me, I just look 
immediately below the giant block of blue comment text and check the 
second word in the line below.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Walter Bright via Digitalmars-d

On 2/14/2017 2:01 PM, H. S. Teoh via Digitalmars-d wrote:

This is a good idea. +1.


Please take this on!

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


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread kinke via Digitalmars-d
On Tuesday, 14 February 2017 at 20:03:13 UTC, Jonathan M Davis 
wrote:
That being said, at some point, you have to ask whether each 
added feature is worth the cost when you consider how it's 
going to clutter up function signatures even further. And while 
I do think that there is value in DIP 1005 and the proposed 
from template, I also think that it's taking it too far. IMHO, 
it's just not worth marking functions even further - at least 
not in most code. Maybe it's worth it in something like Phobos 
where everyone is using it and benefiting from the compilation 
speed up, but Walter has been wanting to implement lazy imports 
anyway, and that would fix the problem without doing anything 
to any function signatures. It does lose the benefits of tying 
the imports to the function, but personally, I don't think that 
that's's worth the extra cost of further cluttering up the 
function signature. As it is, I'm increasingly of the opinion 
that local and selective imports aren't worth it. It's just so 
much nicer to able to slap the required imports at the 
beginning of the module and forget about them than having to 
worry about maintaining a list of selective imports or have all 
of the extra import lines inside of all of the functions. And 
adding imports to the function signatures is just making the 
whole local import situation that much worse.


+1. D's beautiful syntax plays a key role for attracting new 
folks, and I see it endangered by recent developments.




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread H. S. Teoh via Digitalmars-d
On Tue, Feb 14, 2017 at 12:46:17PM -0800, Walter Bright via Digitalmars-d wrote:
[...]
> Range remove
> (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
> (Range range, Offset offset)
> if (s != SwapStrategy.stable
> && isBidirectionalRange!Range
> && hasLvalueElements!Range
> && hasLength!Range
> && Offset.length >= 1);
> 
> But there's another issue here. remove() has other overloads:
> 
> Range remove
> (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
> (Range range, Offset offset)
> if (s == SwapStrategy.stable
> && isBidirectionalRange!Range
> && hasLvalueElements!Range
> && Offset.length >= 1)
> 
> Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
> (Range range)
> if (isBidirectionalRange!Range
> && hasLvalueElements!Range)
> 
> Two constraints are common to all three, those are the only ones that
> actually need to be in the constraint. The others can go in the body
> under `static if`, as the user need not be concerned with them.
> 
> This is a general issue in Phobos that too many constraints are
> user-facing when they don't need to be.

+1.  I've raised this point many times, but didn't seem to generate much
response.  Basically, there are two more-or-less equivalent ways of
having multiple implementations of a function based on its arguments:
(1) via signature constraints, and (2) via static if's inside the
function (or template) body.

>From an implementor's POV, (1) is more desirable, because it's easy to
add a new overload when you need to extend the function to handle new
types. However, from a user's POV, (2) is much more friendly -- one only
needs to look at the old overloads of std.conv.toImpl to see why: it was
an obtuse mass of only slightly different sig constraints over a
ridiculous number of overloads, each intended to work with very specific
argument combinations, all of which are implementation details the user
need not know about.

Thankfully, the docs for std.conv.to have been greatly improved since
the last time I had to work with the code -- everything is now
consolidated under a single template function std.conv.to, and the
implementation details are hidden behind module-private overloads. This
is the way it should be.

I argue that the same pattern should be applied to (most of the) other
overloaded Phobos functions as well, such as remove() shown above. There
really should only be *one* remove() function with the two constraints
Walter indicated, and the current overloads should either be refactored
under static if's inside the function body, or else renamed and made
into module-private implementation functions called by remove().
Multiple user-facing overloads really only should be used where each
overload represents a *conceptually-different* aspect of the function
(which should be relatively rare).

In general, if a template function (or set of overloads) conceptually
does the same thing, it should be made into a *single* function. If the
implementation differs, that's the problem of the Phobos maintainers,
and should be handled as module-private symbols forwarded to by the
single user-facing function.

Another bonus to this approach is that it allows us to customize nicer
error messages via static assert if none of the (internal) overloads
match the passed argument types. E.g., if the user passes a swappable
bidirectional range to remove() but for whatever reason the arguments
fail to match any of its implementations, then instead of spewing out
pages of inscrutable encrypted Klingon (argument types XYZ do not match
any overloads of remove(), candidates are: [... snip 5 pages of
unreadable function signatures...]), we can, say, do something like:

static if (...)
return removeImplA(args);
else static if (...)
return removeImplB(args);
...
else
static assert("Arguments to remove() must satisfy conditions X, 
Y, Z [insert explanation here]");

That's a 1-line error message that tells the user exactly what went
wrong, instead of 5 pages of 10-line function signatures that the user
must parse and then mentally evaluate each Boolean condition for, in
order to deduce exactly why the passed arguments didn't work.


> A further improvement in the documentation would be to add links to
> isBidirectionalRange and hasLvalueElements.

This is a good idea. +1.


T

-- 
"I'm running Windows '98." "Yes." "My computer isn't working now." "Yes, you 
already said that." -- User-Friendly


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Lurker via Digitalmars-d
On Tuesday, 14 February 2017 at 16:25:17 UTC, Andrei Alexandrescu 
wrote:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);



Range
remove (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if CanRemove!(s, range, offset);

The function name is on the first line. I think 10 seconds 
would be an exaggeration of an admittedly real issue.




Thought so, too, but then I *did* spend 10 seconds trying to find 
it myself!



Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, 
InputRange2 r2)

if (isInputRange!(InputRange1) && isInputRange!(InputRange2)
&& hasSwappableElements!(InputRange1)
&& hasSwappableElements!(InputRange2)
&& is(ElementType!(InputRange1) == 
ElementType!(InputRange2)));




Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 
r2)

if CanSwapRanges!(InputRange1, InputRange2);


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Walter Bright via Digitalmars-d

On 2/14/2017 12:46 PM, Walter Bright wrote:

A further improvement in the documentation would be to add links to
isBidirectionalRange and hasLvalueElements.


For reference:

http://dlang.org/phobos/std_algorithm_mutation.html#.remove


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Walter Bright via Digitalmars-d

On 2/14/2017 8:25 AM, Andrei Alexandrescu wrote:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

The function name is on the first line.


It could be improved slightly using indentation:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

But there's another issue here. remove() has other overloads:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s == SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& Offset.length >= 1)

Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)
(Range range)
if (isBidirectionalRange!Range
&& hasLvalueElements!Range)

Two constraints are common to all three, those are the only ones that actually 
need to be in the constraint. The others can go in the body under `static if`, 
as the user need not be concerned with them.


This is a general issue in Phobos that too many constraints are user-facing when 
they don't need to be.


A further improvement in the documentation would be to add links to 
isBidirectionalRange and hasLvalueElements.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, February 14, 2017 09:37:39 Andrei Alexandrescu via Digitalmars-d 
wrote:
> On 02/14/2017 04:55 AM, Jacob Carlborg wrote:
> > The signatures we already have in Phobos is quite ridiculous
>
> How are they so, and what steps can we take to improve them. Could you
> please give a few examples on how to do things better? Thx! -- Andrei

Unfortunately, I'm not sure that there's much that we can do. Each of the
features that clutter up a function signature is useful and valuable in and
of itself, but when you add them all together, it can get pretty messy.
We've managed to improve some aspects over time, but there has to be a limit
to it. At some point, the information takes up however much space it takes
up.

Having auto functions helped considerably for cleaning up function
signatures where templates were involved. Declaring eponymous templates to
use as traits for commonly used idioms helps - and in some cases, maybe we
should add more of those for common combinations, but the best we could do
is clean up some common cases, because it ultimately doesn't scale well for
the reasons that you explained why C++ has had issue with getting concepts
into the standard. Having different defaults for function attributes would
help in some cases (e.g. have @safe and pure be the default), but I don't
see how we could do that at this point without breaking a bunch of code. And
attribute inference already takes care of the attributes on the most
cluttered functions, since those are going to be templated functions with
template constraints.

I think that things just reach a point where if you want the functionality,
you get a messy function signature, and you can't do much more than try and
format it nicely. For better or worse, it's just one of the costs of what D
provides.

That being said, at some point, you have to ask whether each added feature
is worth the cost when you consider how it's going to clutter up function
signatures even further. And while I do think that there is value in DIP
1005 and the proposed from template, I also think that it's taking it too
far. IMHO, it's just not worth marking functions even further - at least not
in most code. Maybe it's worth it in something like Phobos where everyone is
using it and benefiting from the compilation speed up, but Walter has been
wanting to implement lazy imports anyway, and that would fix the problem
without doing anything to any function signatures. It does lose the benefits
of tying the imports to the function, but personally, I don't think that
that's's worth the extra cost of further cluttering up the function
signature. As it is, I'm increasingly of the opinion that local and
selective imports aren't worth it. It's just so much nicer to able to slap
the required imports at the beginning of the module and forget about them
than having to worry about maintaining a list of selective imports or have
all of the extra import lines inside of all of the functions. And adding
imports to the function signatures is just making the whole local import
situation that much worse.

So, regardless of what happens with DIP 1005 or from, I'd very much like to
see lazy imports implemented, and I don't expect use DIP 1005 or from in
much code that I write.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread bachmeier via Digitalmars-d

On Tuesday, 14 February 2017 at 19:27:36 UTC, Adam D. Ruppe wrote:
But the problems is: what name do you give it? Quite often it 
would just be `fooConstraint` or `removable` or other 
non-reusable things... you'd just be *adding* complication 
because you'd need to forward all the arguments and write 
different ones for each function anyway.


There's a few common cases we might combine, like Phobos often 
uses `isInputRange!Range && is(ElementType!Range == Something)` 
and perhaps that could be combined into `isInputRangeOf!(Range, 
Something)` or something like that, but in many cases, there'd 
be an equal number of aliases constraints to existing inline 
ones anyway


Makes sense. I had assumed there would be a lot of duplication of 
constraints.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread bachmeier via Digitalmars-d

On Tuesday, 14 February 2017 at 19:15:06 UTC, H. S. Teoh wrote:


This is already possible:

enum fooConstraint(R) = isBidirectionalRange!Range &&
hasLvalueElements!Range && ... ;

	Range remove(SwapStrategy s, R)(...) if (fooConstraint!R) { 
... }



T


That's good to know. I didn't try that syntax, though, which 
explains why I couldn't get it to work.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Adam D. Ruppe via Digitalmars-d

On Tuesday, 14 February 2017 at 19:08:53 UTC, bachmeier wrote:
I am not familiar with all of the past discussion of this 
issue, but something that I have wondered is why we can't do 
something like


alias fooConstraint = (s != SwapStrategy.stable


You can do that, it would just be a helper function / template 
instead of an alias. You can use the shorthand enum syntax:


enum removable(R) = isBidirectionalRange!R && isInputRange!R;

Range remove(Range)(Range r) if(removable!Range) {
return r;
}


That works today.


But the problems is: what name do you give it? Quite often it 
would just be `fooConstraint` or `removable` or other 
non-reusable things... you'd just be *adding* complication 
because you'd need to forward all the arguments and write 
different ones for each function anyway.


There's a few common cases we might combine, like Phobos often 
uses `isInputRange!Range && is(ElementType!Range == Something)` 
and perhaps that could be combined into `isInputRangeOf!(Range, 
Something)` or something like that, but in many cases, there'd be 
an equal number of aliases constraints to existing inline ones 
anyway


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jack Stouffer via Digitalmars-d

On Tuesday, 14 February 2017 at 19:08:53 UTC, bachmeier wrote:
I am not familiar with all of the past discussion of this 
issue, but something that I have wondered is why we can't do 
something like


Because at that point, it's no longer a set of lego's being put 
together (design by introspection) which build a larger whole. 
It's the genericism problem of requiring a name for everything.


At the end of the day this would actually make constraints less 
*verbose*, but more *complicated*.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread H. S. Teoh via Digitalmars-d
On Tue, Feb 14, 2017 at 07:14:08PM +, bachmeier via Digitalmars-d wrote:
> On Tuesday, 14 February 2017 at 19:08:53 UTC, bachmeier wrote:
> 
> > I am not familiar with all of the past discussion of this issue, but
> > something that I have wondered is why we can't do something like
> > 
> > alias fooConstraint = (s != SwapStrategy.stable
> >   && isBidirectionalRange!Range
> >   && hasLvalueElements!Range
> >   && hasLength!Range
> >   && Offset.length >= 1);
> > 
> > Range remove
> >   (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
> >   (Range range, Offset offset) if fooConstraint;
> 
> I mean, is there some reason that this shouldn't be allowed? Any
> feature can be abused, but it looks useful in many cases.

This is already possible:

enum fooConstraint(R) = isBidirectionalRange!Range &&
hasLvalueElements!Range && ... ;

Range remove(SwapStrategy s, R)(...) if (fooConstraint!R) { ... }


T

-- 
"Maybe" is a strange word.  When mom or dad says it it means "yes", but when my 
big brothers say it it means "no"! -- PJ jr.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread bachmeier via Digitalmars-d

On Tuesday, 14 February 2017 at 19:08:53 UTC, bachmeier wrote:

I am not familiar with all of the past discussion of this 
issue, but something that I have wondered is why we can't do 
something like


alias fooConstraint = (s != SwapStrategy.stable
  && isBidirectionalRange!Range
  && hasLvalueElements!Range
  && hasLength!Range
  && Offset.length >= 1);

Range remove
  (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
  (Range range, Offset offset) if fooConstraint;


I mean, is there some reason that this shouldn't be allowed? Any 
feature can be abused, but it looks useful in many cases.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread bachmeier via Digitalmars-d
On Tuesday, 14 February 2017 at 16:25:17 UTC, Andrei Alexandrescu 
wrote:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);


[...]

My recollection is past discussions got stalled because the 
approach is combinatorially bankrupt. How would one express the 
constraints of the functions above with simple named 
constraints? (Not rhetorical; please do provide an example if 
possible.) Before long there is an explosion in names 
("BidirectionalWithLvalueElementsAndLength", ...). This is what 
has buried not one, but two concepts proposals for C++, leading 
to the current Concepts Lite proposal. I haven't followed that 
lately but I remember it combines an engineering effort to 
reduce the number of names introduced (for the standard library 
only, which is a limitation) with adding support to Boolean 
logic (surprise, surprise) to the feature (see 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4377.pdf), the most recent proposal, which was rejected for C++17. Over time, C++ concepts have moved from the broken combinatorially-bankrupt form slowly toward D's Boolean constraints (just with a gratuitously awkward notation). I presume they will be merged into the language when they'll have capabilities comparable to D's system.


The question is, given this experience, do we want to move the 
opposite direction?


I am not familiar with all of the past discussion of this issue, 
but something that I have wondered is why we can't do something 
like


alias fooConstraint = (s != SwapStrategy.stable
  && isBidirectionalRange!Range
  && hasLvalueElements!Range
  && hasLength!Range
  && Offset.length >= 1);

Range remove
  (SwapStrategy s = SwapStrategy.stable, Range, Offset...)
  (Range range, Offset offset) if fooConstraint;


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jack Stouffer via Digitalmars-d
On Tuesday, 14 February 2017 at 09:55:51 UTC, Jacob Carlborg 
wrote:
Why? It looks awful. The signatures we already have in Phobos 
is quite ridiculous, this will not improve. Isn't this and the 
whole idea of DIP 1005 just a workaround for the compiler not 
lazily analyzing the symbols.


https://github.com/dlang/DIPs/blob/master/DIPs/DIP1005.md#alternative-lazy-imports


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jack Stouffer via Digitalmars-d
On Tuesday, 14 February 2017 at 14:37:39 UTC, Andrei Alexandrescu 
wrote:

what steps can we take to improve them.


You really can't unfortunately. Verbose-ness is a nessesary 
component of type-safe duck typing.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Andrei Alexandrescu via Digitalmars-d

On 02/14/2017 10:49 AM, Jacob Carlborg wrote:

On 2017-02-14 15:37, Andrei Alexandrescu wrote:


How are they so,


Example [1]. That signature spans 8 lines, it took me 10 seconds to find
the actual function name.


Copying here to make things easier:

Range remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
(Range range, Offset offset)
if (s != SwapStrategy.stable
&& isBidirectionalRange!Range
&& hasLvalueElements!Range
&& hasLength!Range
&& Offset.length >= 1);

The function name is on the first line. I think 10 seconds would be an 
exaggeration of an admittedly real issue.



Example [2], 5 lines.


Copying here as well (reflowed for email):

Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
if (isInputRange!(InputRange1) && isInputRange!(InputRange2)
&& hasSwappableElements!(InputRange1)
&& hasSwappableElements!(InputRange2)
&& is(ElementType!(InputRange1) == ElementType!(InputRange2)));

One immediate matter here is redundant parens, of which elimination 
would lead to the marginally more palatable:


Tuple!(InputRange1, InputRange2)
swapRanges(InputRange1, InputRange2)(InputRange1 r1, InputRange2 r2)
if (isInputRange!InputRange1 && isInputRange!InputRange2
&& hasSwappableElements!InputRange1
&& hasSwappableElements!InputRange2
&& is(ElementType!InputRange1 == ElementType!InputRange2));


and what steps can we take to improve them. Could you
please give a few examples on how to do things better? Thx! -- Andrei


Well, I would prefer to have template constraints as its own entity in
the language not not just a bunch of boolean conditions. This has been
talked about before several times. Something like:

constraint Foo
{
void foo();
}

void bar(T : Foo)(T t);


My recollection is past discussions got stalled because the approach is 
combinatorially bankrupt. How would one express the constraints of the 
functions above with simple named constraints? (Not rhetorical; please 
do provide an example if possible.) Before long there is an explosion in 
names ("BidirectionalWithLvalueElementsAndLength", ...). This is what 
has buried not one, but two concepts proposals for C++, leading to the 
current Concepts Lite proposal. I haven't followed that lately but I 
remember it combines an engineering effort to reduce the number of names 
introduced (for the standard library only, which is a limitation) with 
adding support to Boolean logic (surprise, surprise) to the feature (see 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4377.pdf), the 
most recent proposal, which was rejected for C++17. Over time, C++ 
concepts have moved from the broken combinatorially-bankrupt form slowly 
toward D's Boolean constraints (just with a gratuitously awkward 
notation). I presume they will be merged into the language when they'll 
have capabilities comparable to D's system.


The question is, given this experience, do we want to move the opposite 
direction?



Andrei




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-14 15:37, Andrei Alexandrescu wrote:


How are they so,


Example [1]. That signature spans 8 lines, it took me 10 seconds to find 
the actual function name. Example [2], 5 lines. Adding attributes on top 
of that would increase the length of the signature even more. 
Fortunately templates will infer most attributes.



and what steps can we take to improve them. Could you
please give a few examples on how to do things better? Thx! -- Andrei


Well, I would prefer to have template constraints as its own entity in 
the language not not just a bunch of boolean conditions. This has been 
talked about before several times. Something like:


constraint Foo
{
void foo();
}

void bar(T : Foo)(T t);

[1] 
https://github.com/dlang/phobos/blob/master/std/algorithm/mutation.d#L1682-L1689


[2] 
https://github.com/dlang/phobos/blob/master/std/algorithm/mutation.d#L2729-L2733


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Andrei Alexandrescu via Digitalmars-d

On 02/14/2017 04:55 AM, Jacob Carlborg wrote:

The signatures we already have in Phobos is quite ridiculous


How are they so, and what steps can we take to improve them. Could you 
please give a few examples on how to do things better? Thx! -- Andrei


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Meta via Digitalmars-d
On Tuesday, 14 February 2017 at 09:55:51 UTC, Jacob Carlborg 
wrote:

On 2017-02-14 04:49, Timothee Cour via Digitalmars-d wrote:
What about allowing syntax sugar as an alternative to relying 
on the new

`from/Module` inline import idiom:

```
void fun(T)(std.stdio::File input, T value) if
(std.traits::isIntegral!T) {...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T) {...}
```

Rationale:

* this reads much better (less noise); same as `=>` syntax for 
lambdas


* this is expected to be a very common pattern, so might as 
well make it

as simple as possible


Why? It looks awful. The signatures we already have in Phobos 
is quite ridiculous, this will not improve. Isn't this and the 
whole idea of DIP 1005 just a workaround for the compiler not 
lazily analyzing the symbols.


This is what I had thought as well when Andrei first posted 
DIP1005, but he said that his main goal is actually making it so 
a declaration can carry all of its imports with it in a 
self-contained unit. When you look at it that way it makes a bit 
more sense as to why we might want constructs such as introduced 
by DIP1005 or this self-important lookup idiom.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Johannes Pfau via Digitalmars-d
Am Tue, 14 Feb 2017 10:23:51 +
schrieb Daniel N :

> On Tuesday, 14 February 2017 at 10:21:03 UTC, Johannes Pfau wrote:
> > Am Mon, 13 Feb 2017 19:49:28 -0800
> > schrieb Timothee Cour via Digitalmars-d 
> > :
> >  
> >> What about allowing syntax sugar as an alternative to relying 
> >> on the new `from/Module` inline import idiom:
> >> 
> >> ```
> >> void fun(T)(std.stdio::File input, T value) if
> >> (std.traits::isIntegral!T) {...}
> >> ```  
> >
> > If you use a single ':' instead you can argue it's simply a 
> > shortened, inline version of a selective import:
> >
> > import std.stdio : File;
> > //still valid D
> > import std.stdio:File;
> > //expression instead of statement => remove ;
> > import std.stdio:File
> > //We're not importing a symbol, we're simply referring to it
> > std.stdio:File
> >
> > -- Johannes  
> 
> my_module:File
> 
> is it a label followed by File or File inside my_module?
> 

This might be a problem. Labels can only occur in front of a
statement though:
https://dlang.org/spec/statement.html#LabeledStatement

So it boils down to:
ModuleFullyQualifiedName:ImportBind vs LabeledStatement


-- Johannes



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Sebastiaan Koppe via Digitalmars-d
On Tuesday, 14 February 2017 at 09:55:51 UTC, Jacob Carlborg 
wrote:
Why? It looks awful. The signatures we already have in Phobos 
is quite ridiculous, this will not improve. Isn't this and the 
whole idea of DIP 1005 just a workaround for the compiler not 
lazily analyzing the symbols.


This.



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, February 14, 2017 10:55:51 Jacob Carlborg via Digitalmars-d 
wrote:
> On 2017-02-14 04:49, Timothee Cour via Digitalmars-d wrote:
> > What about allowing syntax sugar as an alternative to relying on the new
> > `from/Module` inline import idiom:
> >
> > ```
> > void fun(T)(std.stdio::File input, T value) if
> > (std.traits::isIntegral!T) {...}
> > ```
> >
> > instead of:
> >
> > ```
> > void fun(T)(Module!"std.stdio".File input, T value) if
> > (Module!"std.traits".isIntegral!T) {...}
> > ```
> >
> > Rationale:
> >
> > * this reads much better (less noise); same as `=>` syntax for lambdas
> >
> > * this is expected to be a very common pattern, so might as well make it
> > as simple as possible
>
> Why? It looks awful. The signatures we already have in Phobos is quite
> ridiculous, this will not improve. Isn't this and the whole idea of DIP
> 1005 just a workaround for the compiler not lazily analyzing the symbols.

Mostly, but not just that. By having something like DIP 1005, all of the
imports required for the function can be associated with the function. So,
people reading the code then have an easier time figuring out where the
symbols come from, and it could be that the compiler could take advantage of
that somehow. It does seem though that the main motivator for DIP 1005 is
the fact that we don't have lazy imports, and Walter has talked before about
wanting to do fully lazy imports. So, I expect that we'll get them at some
point, at which point, any performance improvements from DIP 1005 or the
from template would likely become moot, and the only benefit left is
essentially documentation.

Personally, I might use DIP 1005 in some cases if we end up with it, but I
won't use from unless I'm forced to. As cool as it is that we can do it with
the language as-is, it's far too verbose and far too ugly. As it is, I'm
getting sick of doing local and selective imports all over the place like
everyone seems to think is best practice. I understand why they're
theoretically good, but it results in longer code, and it gets very tedious
to have to try and maintain the list of symbols that are imported instead of
just importing the modules you need at the top of the module and forgetting
about it. Doing what DIP 1005 and from push for just takes that pain to
another level. It might be worth it in code used by tons of people (like
Phobos), but for most code, I'm increasingly of the opinion that it's not
worth it. And having proper lazy imports would largely fix the compilation
cost of simply importing modules. So, I'm very much in favor of getting lazy
imports, and while I do see _some_ value in documenting where stuff comes
from via something like DIP 1005, I seriosuly question that it's worth the
extra pain. And when you have all of those function attributes to worry
about on top of that... It's just getting to be too much.

- Jonathan M Davis



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Daniel Kozak via Digitalmars-d

Dne 14.2.2017 v 11:21 Johannes Pfau via Digitalmars-d napsal(a):


Am Mon, 13 Feb 2017 19:49:28 -0800
schrieb Timothee Cour via Digitalmars-d :


What about allowing syntax sugar as an alternative to relying on the
new `from/Module` inline import idiom:

```
void fun(T)(std.stdio::File input, T value) if
(std.traits::isIntegral!T) {...}
```

If you use a single ':' instead you can argue it's simply a shortened,
inline version of a selective import:

import std.stdio : File;
//still valid D
import std.stdio:File;
//expression instead of statement => remove ;
import std.stdio:File
//We're not importing a symbol, we're simply referring to it
std.stdio:File
-- Johannes

Exactly! I was going to write the same


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Daniel N via Digitalmars-d

On Tuesday, 14 February 2017 at 10:23:51 UTC, Daniel N wrote:


-- Johannes


my_module:File

is it a label followed by File or File inside my_module?


This would be unambiguous AFAIK, since labels can't start with 
"import."


import.my_module:File




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Daniel N via Digitalmars-d

On Tuesday, 14 February 2017 at 10:21:03 UTC, Johannes Pfau wrote:

Am Mon, 13 Feb 2017 19:49:28 -0800
schrieb Timothee Cour via Digitalmars-d 
:


What about allowing syntax sugar as an alternative to relying 
on the new `from/Module` inline import idiom:


```
void fun(T)(std.stdio::File input, T value) if
(std.traits::isIntegral!T) {...}
```


If you use a single ':' instead you can argue it's simply a 
shortened, inline version of a selective import:


import std.stdio : File;
//still valid D
import std.stdio:File;
//expression instead of statement => remove ;
import std.stdio:File
//We're not importing a symbol, we're simply referring to it
std.stdio:File

-- Johannes


my_module:File

is it a label followed by File or File inside my_module?



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Johannes Pfau via Digitalmars-d
Am Mon, 13 Feb 2017 19:49:28 -0800
schrieb Timothee Cour via Digitalmars-d :

> What about allowing syntax sugar as an alternative to relying on the
> new `from/Module` inline import idiom:
> 
> ```
> void fun(T)(std.stdio::File input, T value) if
> (std.traits::isIntegral!T) {...}
> ```

If you use a single ':' instead you can argue it's simply a shortened,
inline version of a selective import:

import std.stdio : File;
//still valid D
import std.stdio:File;
//expression instead of statement => remove ;
import std.stdio:File
//We're not importing a symbol, we're simply referring to it
std.stdio:File

-- Johannes



Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Daniel N via Digitalmars-d
On Tuesday, 14 February 2017 at 09:55:51 UTC, Jacob Carlborg 
wrote:


Why? It looks awful. The signatures we already have in Phobos 
is quite ridiculous, this will not improve. Isn't this and the 
whole idea of DIP 1005 just a workaround for the compiler not 
lazily analyzing the symbols.


Even those of you who favor...
with(import std.stdio)

... wouldn't you agree that this is better?
with(Module!"std.stdio")

Less intrusive compiler change because the same syntax already 
works everywhere "with" is valid.




Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Jacob Carlborg via Digitalmars-d

On 2017-02-14 04:49, Timothee Cour via Digitalmars-d wrote:

What about allowing syntax sugar as an alternative to relying on the new
`from/Module` inline import idiom:

```
void fun(T)(std.stdio::File input, T value) if
(std.traits::isIntegral!T) {...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T) {...}
```

Rationale:

* this reads much better (less noise); same as `=>` syntax for lambdas

* this is expected to be a very common pattern, so might as well make it
as simple as possible


Why? It looks awful. The signatures we already have in Phobos is quite 
ridiculous, this will not improve. Isn't this and the whole idea of DIP 
1005 just a workaround for the compiler not lazily analyzing the symbols.


--
/Jacob Carlborg


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-14 Thread Walter Bright via Digitalmars-d

Please fix your newsreader client to send as text, not as html.

The html is both excessively large, and has randomly changing fonts embedded in 
it.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Timothee Cour via Digitalmars-d
`#std.stdio.File` doesn't work, we don't know where is the module
separator:
that could mean `module std` with a class stdio with a field File.

so the syntax would have be:

`std.stdio SYMBOL File`

frankly I don't care which symbol, so long it looks like that. And as I
said, `std.stdio::File` is reasonable since it's used for similar purpose
in rust and C++



On Mon, Feb 13, 2017 at 10:21 PM, Chris M via Digitalmars-d <
digitalmars-d@puremagic.com> wrote:

> On Tuesday, 14 February 2017 at 03:49:28 UTC, Timothee Cour wrote:
>
>> What about allowing syntax sugar as an alternative to relying on the new
>> `from/Module` inline import idiom:
>>
>> ```
>> void fun(T)(std.stdio::File input, T value) if (std.traits::isIntegral!T)
>> {...}
>> ```
>>
>> instead of:
>>
>> ```
>> void fun(T)(Module!"std.stdio".File input, T value) if
>> (Module!"std.traits".isIntegral!T) {...}
>> ```
>>
>> Rationale:
>>
>> * this reads much better (less noise); same as `=>` syntax for lambdas
>>
>> * this is expected to be a very common pattern, so might as well make it
>> as simple as possible
>>
>> * not particular on which symbol is used, could be something else, so
>> long it doesn't involve writing a string such as from!"std.traits". But ::
>> will be familiar to those coming from C++/rust etc.
>>
>> * from!"" is too loose and can be abused arbitrarily:
>>
>> ```
>> // this compiles
>> void fun(){
>>   from!"std.stdio; pragma(msg,`abuse...`); import std.stdio".File a;
>> }
>> ```
>>
>> Furthermore this is useful in other scenarios, namely when an import is
>> used only once in a context:
>> ```
>> auto fun(){  return std.file::getcwd; }
>> ```
>> is more DRY; instead of:
>> ```
>> auto fun(){ static import std.file;  return std.file.getcwd; }
>> auto fun(){ return Module!"std.file".getcwd; }
>> ```
>>
>> NOTE: if :: is not feasible for whatever reason, let's consider other
>> symbols without prejudice to this proposal.
>>
>
> Well, as Jack said there's no real clean way to do this without cluttering
> the function signatures more. However if this does happen through a
> language change, :: would look kind of awkward imo. I'd go with the
> following idea instead.
>
> void fun(T)(#std.stdio.File input, T value)
> if (#std.traits.isIntegral!T)
> {...}
>
> Doesn't necessarily have to be the octothorpe, but I think it looks a bit
> cleaner.
>


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Chris M via Digitalmars-d

On Tuesday, 14 February 2017 at 03:49:28 UTC, Timothee Cour wrote:
What about allowing syntax sugar as an alternative to relying 
on the new `from/Module` inline import idiom:


```
void fun(T)(std.stdio::File input, T value) if 
(std.traits::isIntegral!T)

{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T) {...}
```

Rationale:

* this reads much better (less noise); same as `=>` syntax for 
lambdas


* this is expected to be a very common pattern, so might as 
well make it as simple as possible


* not particular on which symbol is used, could be something 
else, so long it doesn't involve writing a string such as 
from!"std.traits". But :: will be familiar to those coming from 
C++/rust etc.


* from!"" is too loose and can be abused arbitrarily:

```
// this compiles
void fun(){
  from!"std.stdio; pragma(msg,`abuse...`); import 
std.stdio".File a;

}
```

Furthermore this is useful in other scenarios, namely when an 
import is

used only once in a context:
```
auto fun(){  return std.file::getcwd; }
```
is more DRY; instead of:
```
auto fun(){ static import std.file;  return std.file.getcwd; }
auto fun(){ return Module!"std.file".getcwd; }
```

NOTE: if :: is not feasible for whatever reason, let's consider 
other symbols without prejudice to this proposal.


Well, as Jack said there's no real clean way to do this without 
cluttering the function signatures more. However if this does 
happen through a language change, :: would look kind of awkward 
imo. I'd go with the following idea instead.


void fun(T)(#std.stdio.File input, T value)
if (#std.traits.isIntegral!T)
{...}

Doesn't necessarily have to be the octothorpe, but I think it 
looks a bit cleaner.


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Timothee Cour via Digitalmars-d
as for language change, I believe the proposed syntax (`::`) can be reduced
to a minimum if we we make `fullyqualifiedName` `::` a reduction to the
from/Module inline import idiom. No complex corner case or new bug
introduced, it could be done as a pure AST transformation


On Mon, Feb 13, 2017 at 9:32 PM, Timothee Cour 
wrote:

> > The only thing from has going for it is that it doesn't require a
> language change. Yours does, so it should be compared to the proposals in
> DIP1005 and not just from.
>
> indeed. But just because something can be done in library code doesn't
> mean it should. Same exact rationale for:
> `lazy`, `=>`, scope(exit), etc. All of these coul've been done in pure
> library code, but the syntax sugar makes them particularly easy to use.
> Syntax sugar should be used sparingly, but it makes sense if
>
> * it simplifies syntax compared to best possible library code
> * it's for a common use case
>
>
>
> On Mon, Feb 13, 2017 at 9:03 PM, Jack Stouffer via Digitalmars-d <
> digitalmars-d@puremagic.com> wrote:
>
>> On Tuesday, 14 February 2017 at 03:49:28 UTC, Timothee Cour wrote:
>>
>>> What about allowing syntax sugar as an alternative to relying on the new
>>> `from/Module` inline import idiom:
>>>
>>> ```
>>> void fun(T)(std.stdio::File input, T value) if (std.traits::isIntegral!T)
>>> {...}
>>> ```
>>>
>>> instead of:
>>>
>>> ```
>>> void fun(T)(Module!"std.stdio".File input, T value) if
>>> (Module!"std.traits".isIntegral!T) {...}
>>> ```
>>>
>>> Rationale:
>>>
>>> * this reads much better (less noise); same as `=>` syntax for lambdas
>>>
>>> * this is expected to be a very common pattern, so might as well make it
>>> as simple as possible
>>>
>>> * not particular on which symbol is used, could be something else, so
>>> long it doesn't involve writing a string such as from!"std.traits". But ::
>>> will be familiar to those coming from C++/rust etc.
>>>
>>> * from!"" is too loose and can be abused arbitrarily:
>>>
>>> ```
>>> // this compiles
>>> void fun(){
>>>   from!"std.stdio; pragma(msg,`abuse...`); import std.stdio".File a;
>>> }
>>> ```
>>>
>>> Furthermore this is useful in other scenarios, namely when an import is
>>> used only once in a context:
>>> ```
>>> auto fun(){  return std.file::getcwd; }
>>> ```
>>> is more DRY; instead of:
>>> ```
>>> auto fun(){ static import std.file;  return std.file.getcwd; }
>>> auto fun(){ return Module!"std.file".getcwd; }
>>> ```
>>>
>>> NOTE: if :: is not feasible for whatever reason, let's consider other
>>> symbols without prejudice to this proposal.
>>>
>>
>> The only thing from has going for it is that it doesn't require a
>> language change. Yours does, so it should be compared to the proposals in
>> DIP1005 and not just from.
>>
>> TBQH all the the proposed syntaxes for the DIP1005 problem kind of suck,
>> because at the end of the day there's no good way to solve the problem.
>>
>> Every proposed solution either
>>
>> 1. Looks terrible (and some people highly underestimate the cost of a
>> language looking bad), or
>> 2. Complicate our already complex function definitions even further. How
>> is a beginner not going to look at this and feel like barfing
>>
>> with (import std.datetime, std.range.primitives) void fun(R)(scope R r,
>> const ref Systime value) if (isInputRange!R && !isFinite!R)  { ... }
>>
>> But, I'm still of the opinion that the `with` syntax is currently the
>> best proposal. Others have already shown the weaknesses of the `from!`
>> approach.
>>
>
>


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Timothee Cour via Digitalmars-d
> The only thing from has going for it is that it doesn't require a
language change. Yours does, so it should be compared to the proposals in
DIP1005 and not just from.

indeed. But just because something can be done in library code doesn't mean
it should. Same exact rationale for:
`lazy`, `=>`, scope(exit), etc. All of these coul've been done in pure
library code, but the syntax sugar makes them particularly easy to use.
Syntax sugar should be used sparingly, but it makes sense if

* it simplifies syntax compared to best possible library code
* it's for a common use case



On Mon, Feb 13, 2017 at 9:03 PM, Jack Stouffer via Digitalmars-d <
digitalmars-d@puremagic.com> wrote:

> On Tuesday, 14 February 2017 at 03:49:28 UTC, Timothee Cour wrote:
>
>> What about allowing syntax sugar as an alternative to relying on the new
>> `from/Module` inline import idiom:
>>
>> ```
>> void fun(T)(std.stdio::File input, T value) if (std.traits::isIntegral!T)
>> {...}
>> ```
>>
>> instead of:
>>
>> ```
>> void fun(T)(Module!"std.stdio".File input, T value) if
>> (Module!"std.traits".isIntegral!T) {...}
>> ```
>>
>> Rationale:
>>
>> * this reads much better (less noise); same as `=>` syntax for lambdas
>>
>> * this is expected to be a very common pattern, so might as well make it
>> as simple as possible
>>
>> * not particular on which symbol is used, could be something else, so
>> long it doesn't involve writing a string such as from!"std.traits". But ::
>> will be familiar to those coming from C++/rust etc.
>>
>> * from!"" is too loose and can be abused arbitrarily:
>>
>> ```
>> // this compiles
>> void fun(){
>>   from!"std.stdio; pragma(msg,`abuse...`); import std.stdio".File a;
>> }
>> ```
>>
>> Furthermore this is useful in other scenarios, namely when an import is
>> used only once in a context:
>> ```
>> auto fun(){  return std.file::getcwd; }
>> ```
>> is more DRY; instead of:
>> ```
>> auto fun(){ static import std.file;  return std.file.getcwd; }
>> auto fun(){ return Module!"std.file".getcwd; }
>> ```
>>
>> NOTE: if :: is not feasible for whatever reason, let's consider other
>> symbols without prejudice to this proposal.
>>
>
> The only thing from has going for it is that it doesn't require a language
> change. Yours does, so it should be compared to the proposals in DIP1005
> and not just from.
>
> TBQH all the the proposed syntaxes for the DIP1005 problem kind of suck,
> because at the end of the day there's no good way to solve the problem.
>
> Every proposed solution either
>
> 1. Looks terrible (and some people highly underestimate the cost of a
> language looking bad), or
> 2. Complicate our already complex function definitions even further. How
> is a beginner not going to look at this and feel like barfing
>
> with (import std.datetime, std.range.primitives) void fun(R)(scope R r,
> const ref Systime value) if (isInputRange!R && !isFinite!R)  { ... }
>
> But, I'm still of the opinion that the `with` syntax is currently the best
> proposal. Others have already shown the weaknesses of the `from!` approach.
>


Re: syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Jack Stouffer via Digitalmars-d

On Tuesday, 14 February 2017 at 03:49:28 UTC, Timothee Cour wrote:
What about allowing syntax sugar as an alternative to relying 
on the new `from/Module` inline import idiom:


```
void fun(T)(std.stdio::File input, T value) if 
(std.traits::isIntegral!T)

{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T) {...}
```

Rationale:

* this reads much better (less noise); same as `=>` syntax for 
lambdas


* this is expected to be a very common pattern, so might as 
well make it as simple as possible


* not particular on which symbol is used, could be something 
else, so long it doesn't involve writing a string such as 
from!"std.traits". But :: will be familiar to those coming from 
C++/rust etc.


* from!"" is too loose and can be abused arbitrarily:

```
// this compiles
void fun(){
  from!"std.stdio; pragma(msg,`abuse...`); import 
std.stdio".File a;

}
```

Furthermore this is useful in other scenarios, namely when an 
import is

used only once in a context:
```
auto fun(){  return std.file::getcwd; }
```
is more DRY; instead of:
```
auto fun(){ static import std.file;  return std.file.getcwd; }
auto fun(){ return Module!"std.file".getcwd; }
```

NOTE: if :: is not feasible for whatever reason, let's consider 
other symbols without prejudice to this proposal.


The only thing from has going for it is that it doesn't require a 
language change. Yours does, so it should be compared to the 
proposals in DIP1005 and not just from.


TBQH all the the proposed syntaxes for the DIP1005 problem kind 
of suck, because at the end of the day there's no good way to 
solve the problem.


Every proposed solution either

1. Looks terrible (and some people highly underestimate the cost 
of a language looking bad), or
2. Complicate our already complex function definitions even 
further. How is a beginner not going to look at this and feel 
like barfing


with (import std.datetime, std.range.primitives) void 
fun(R)(scope R r, const ref Systime value) if (isInputRange!R && 
!isFinite!R)  { ... }


But, I'm still of the opinion that the `with` syntax is currently 
the best proposal. Others have already shown the weaknesses of 
the `from!` approach.


syntax sugar: std.path::buildPath instead of from!"std.path".buildPath

2017-02-13 Thread Timothee Cour via Digitalmars-d
What about allowing syntax sugar as an alternative to relying on the new
`from/Module` inline import idiom:

```
void fun(T)(std.stdio::File input, T value) if (std.traits::isIntegral!T)
{...}
```

instead of:

```
void fun(T)(Module!"std.stdio".File input, T value) if
(Module!"std.traits".isIntegral!T) {...}
```

Rationale:

* this reads much better (less noise); same as `=>` syntax for lambdas

* this is expected to be a very common pattern, so might as well make it as
simple as possible

* not particular on which symbol is used, could be something else, so long
it doesn't involve writing a string such as from!"std.traits". But :: will
be familiar to those coming from C++/rust etc.

* from!"" is too loose and can be abused arbitrarily:

```
// this compiles
void fun(){
  from!"std.stdio; pragma(msg,`abuse...`); import std.stdio".File a;
}
```

Furthermore this is useful in other scenarios, namely when an import is
used only once in a context:
```
auto fun(){  return std.file::getcwd; }
```
is more DRY; instead of:
```
auto fun(){ static import std.file;  return std.file.getcwd; }
auto fun(){ return Module!"std.file".getcwd; }
```

NOTE: if :: is not feasible for whatever reason, let's consider other
symbols without prejudice to this proposal.