Thread overview
best way to handle UFCS with ambiguous names: using std.typetuple.Alias!
Jun 10, 2013
Timothee Cour
Jun 10, 2013
John Colvin
Jun 11, 2013
timotheecour
Jun 11, 2013
John Colvin
Jun 11, 2013
Jakob Ovrum
Jun 11, 2013
ixid
June 10, 2013
UFCS chains are problematic when a symbol is ambiguous (eg after import std.stdio:write;import std.file:write);

I previously suggested to add the syntax
'arg1.(std.file.write)(arg2)'
(see 'support UFCS with fully qualified function names (was in
"digitalmars.D.learn")'  to avoid breaking UFCS chains.

Others have suggested using renamed local imports:
import std.file:write2=write;
'arg1.write2(arg2)'

This issue keeps coming up, eg ' http://forum.dlang.org/post/mailman.980.1370764406.13711.digitalmars-d@puremagic.com', prompting some to prefer symbols with unique, redundant names eg std.compress.lzw.lzwCompress instead of std.compress.lzw.compress.

However I found a much better way:

*import std. typetuple:Alias;*
*'arg1.Alias!(std.file.write).arg2'*

Interestingly, I haven't found this pattern in phobos.

advantage:

* UFCS chain not broken; no loss of efficiency
* library solution, already works, no need to add new syntax
* avoids the renamed local imports, which I argue is a bad idea (makes it
harder to search for usages of a function, ie 'grep' won't work)
* systematic way to handle the such cases, whereas renamed local imports
require to 'guess' a good name, eg import std.file:write2=write;
* renamed local imports require 1 import declaration syntax per ambiguous
UFCS function (eg import std.file:write2=write needed even if import
std.file is already there), whereas a single import std.typetuple
declaration handles all ambiguous cases).

Bigger example:
----
void main(){
import std.typetuple;

import std.stdio;
import std.file;
import std.range;
import std.algorithm;

"hello2".Alias!(std.stdio.write);
3.iota.map!(a=>a*a).Alias!(std.algorithm.reduce!"a+b").Alias!(std.stdio.writeln);
}
----


June 10, 2013
On Monday, 10 June 2013 at 02:02:09 UTC, Timothee Cour wrote:
> UFCS chains are problematic when a symbol is ambiguous (eg after import
> std.stdio:write;import std.file:write);
>
> I previously suggested to add the syntax
> 'arg1.(std.file.write)(arg2)'
> (see 'support UFCS with fully qualified function names (was in
> "digitalmars.D.learn")'  to avoid breaking UFCS chains.

We should allow this anyway, simply to deal with static imports.
June 11, 2013
On Monday, 10 June 2013 at 08:13:42 UTC, John Colvin wrote:
> On Monday, 10 June 2013 at 02:02:09 UTC, Timothee Cour wrote:
>> UFCS chains are problematic when a symbol is ambiguous (eg after import
>> std.stdio:write;import std.file:write);
>>
>> I previously suggested to add the syntax
>> 'arg1.(std.file.write)(arg2)'
>> (see 'support UFCS with fully qualified function names (was in
>> "digitalmars.D.learn")'  to avoid breaking UFCS chains.
>
> We should allow this anyway, simply to deal with static imports.

What do you mean? Are you arguing in favor of arg1.(std.file.write)(arg2) ?
It seems people didn't like that first proposal. In any case, I'm arguing that Alias as I've suggested is always better than renamed import.
June 11, 2013
I think selective, renamed imports are much better.

On Monday, 10 June 2013 at 02:02:09 UTC, Timothee Cour wrote:
> * library solution, already works, no need to add new syntax
> * avoids the renamed local imports, which I argue is a bad idea (makes it
> harder to search for usages of a function, ie 'grep' won't work)

The search will yield the site of renaming, where the alias can be found and included in the search. It's not overly troublesome. Most good renames might include the original name as part of the alias anyway, in which case all you might need is case-insensitive search.

> * systematic way to handle the such cases, whereas renamed local imports
> require to 'guess' a good name, eg import std.file:write2=write;

Do you "guess" identifier names when you introduce other symbols, too?

> * renamed local imports require 1 import declaration syntax per ambiguous
> UFCS function (eg import std.file:write2=write needed even if import
> std.file is already there), whereas a single import std.typetuple
> declaration handles all ambiguous cases).

Conflicts are very rare and the rename can be included at function scope which is often going to be feasible.

Also, a separate import statement is not necessary in cases where selective imports are already used.
June 11, 2013
On Tuesday, 11 June 2013 at 18:47:08 UTC, timotheecour wrote:
> On Monday, 10 June 2013 at 08:13:42 UTC, John Colvin wrote:
>> On Monday, 10 June 2013 at 02:02:09 UTC, Timothee Cour wrote:
>>> UFCS chains are problematic when a symbol is ambiguous (eg after import
>>> std.stdio:write;import std.file:write);
>>>
>>> I previously suggested to add the syntax
>>> 'arg1.(std.file.write)(arg2)'
>>> (see 'support UFCS with fully qualified function names (was in
>>> "digitalmars.D.learn")'  to avoid breaking UFCS chains.
>>
>> We should allow this anyway, simply to deal with static imports.
>
> What do you mean? Are you arguing in favor of arg1.(std.file.write)(arg2) ?
> It seems people didn't like that first proposal.

Having thought about it it's probably not a good idea.
June 11, 2013
On Monday, 10 June 2013 at 02:02:09 UTC, Timothee Cour wrote:
> UFCS chains are problematic when a symbol is ambiguous (eg after import
> std.stdio:write;import std.file:write);
>
> I previously suggested to add the syntax
> 'arg1.(std.file.write)(arg2)'
> (see 'support UFCS with fully qualified function names (was in
> "digitalmars.D.learn")'  to avoid breaking UFCS chains.
>
> Others have suggested using renamed local imports:
> import std.file:write2=write;
> 'arg1.write2(arg2)'
>
> This issue keeps coming up, eg '
> http://forum.dlang.org/post/mailman.980.1370764406.13711.digitalmars-d@puremagic.com',
> prompting some to prefer symbols with unique, redundant names eg
> std.compress.lzw.lzwCompress instead of std.compress.lzw.compress.
>
> However I found a much better way:
>
> *import std. typetuple:Alias;*
> *'arg1.Alias!(std.file.write).arg2'*
>
> Interestingly, I haven't found this pattern in phobos.
>
> advantage:
>
> * UFCS chain not broken; no loss of efficiency
> * library solution, already works, no need to add new syntax
> * avoids the renamed local imports, which I argue is a bad idea (makes it
> harder to search for usages of a function, ie 'grep' won't work)
> * systematic way to handle the such cases, whereas renamed local imports
> require to 'guess' a good name, eg import std.file:write2=write;
> * renamed local imports require 1 import declaration syntax per ambiguous
> UFCS function (eg import std.file:write2=write needed even if import
> std.file is already there), whereas a single import std.typetuple
> declaration handles all ambiguous cases).
>
> Bigger example:
> ----
> void main(){
> import std.typetuple;
>
> import std.stdio;
> import std.file;
> import std.range;
> import std.algorithm;
>
> "hello2".Alias!(std.stdio.write);
> 3.iota.map!(a=>a*a).Alias!(std.algorithm.reduce!"a+b").Alias!(std.stdio.writeln);
> }
> ----

It seems like a goofy choice to have two extremely common library functions share the same name.