February 17, 2017
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

February 17, 2017
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.
February 18, 2017
> 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-learn@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.digitalmars-d@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.
February 21, 2017
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-learn@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.digitalmars-d@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.
February 22, 2017
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
February 22, 2017
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

May 23, 2017
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.
1 2 3 4 5 6 7 8 9 10
Next ›   Last »