D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 5491 - filter cannot be used in a function?
Summary: filter cannot be used in a function?
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: x86 Linux
: P2 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-01-26 10:36 UTC by Timofei Bolshakov
Modified: 2012-04-24 18:55 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Timofei Bolshakov 2011-01-26 10:36:32 UTC
The following code:
_______________________________________________________________________________
import std.algorithm, std.conv, std.stdio;

enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 = 0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
struct UsbDevice { //{{{ 
    UsbDevType dev_type;
    // not essential here ...
    string toString(){ return to!string( dev_type ); }
}

UsbDevice [] gateways_only( UsbDevice []devices ){ return filter!("a.dev_type == UsbDevType.gateway" )( devices ); }

unittest{
    auto devices  = [ UsbDevice( UsbDevType.gateway ), UsbDevice( UsbDevType.indifferent ), UsbDevice( UsbDevType.hub_dub_7 ) ];
    auto gateways = gateways_only( devices );
    foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
}
______________________________________________________________________________
does not compile telling:
bugs/tbolsh_d2_bug2.d(10): Error: cannot implicitly convert expression (filter(devices)) of type Filter!(result,UsbDevice[]) to UsbDevice[]
Comment 1 Timofei Bolshakov 2011-01-26 10:40:17 UTC
Following variant do not work either:
______________________________________________________________________________
import std.algorithm, std.conv, std.stdio;

enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 = 0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
struct UsbDevice { //{{{ 
    UsbDevType dev_type;
    // not essential here ...
    string toString(){ return to!string( dev_type ); }
}

unittest{
    auto devices  = [ UsbDevice( UsbDevType.gateway ), UsbDevice( UsbDevType.indifferent ), UsbDevice( UsbDevType.hub_dub_7 ) ];
    auto gateways = filter!( "a.dev_type == UsbDevType.gateway" )( devices );
    foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
}
______________________________________________________________________________
compiler tells:
tbolshakov@owner-laptop:~/projects/D$ dmd -unittest bugs/tbolsh_d2_bug3.d 
/usr/include/d/dmd/phobos/std/functional.d(74): Error: static assert  "Bad unary function: a.dev_type == UsbDevType.gateway for type UsbDevice"
/usr/include/d/dmd/phobos/std/functional.d(87):        instantiated from here: Body!(UsbDevice)
/usr/include/d/dmd/phobos/std/algorithm.d(857):        instantiated from here: result!(UsbDevice)
/usr/include/d/dmd/phobos/std/algorithm.d(842):        instantiated from here: Filter!(result,UsbDevice[])
bugs/tbolsh_d2_bug3.d(12):        instantiated from here: filter!(UsbDevice[])
Comment 2 Timofei Bolshakov 2011-01-26 10:50:03 UTC
And this one does not compile:
__________________________________________________________________________________
import std.algorithm, std.conv, std.stdio;

enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 = 0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
struct UsbDevice { //{{{ 
    UsbDevType dev_type;
    ubyte usb_id;
    // not essential here ...
    string toString(){ return to!string( dev_type ); }
}
UsbDevice [ ubyte ] associate_devices( UsbDevice []devices ){//{{{
    UsbDevice [ubyte] retval; 
    foreach( UsbDevice dev ; devices ) retval[ dev.usb_id ] = dev;  
    return retval;
}//}}}

unittest{
    auto devices  = [ UsbDevice( UsbDevType.gateway, 1 ), UsbDevice( UsbDevType.indifferent, 2 ), UsbDevice( UsbDevType.hub_dub_7, 3 ) ];
    auto devmap = associate_devices( 
        filter!( delegate bool( UsbDevice a ){ return a.dev_type == UsbDevType.gateway; } )( devices ) );
    foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
}

void main(){}
______________________________________________________________________________
Telling:
tbolshakov@owner-laptop:~/projects/D$ dmd -unittest bugs/tbolsh_d2_bug4.d 
bugs/tbolsh_d2_bug4.d(18): Error: function tbolsh_d2_bug4.associate_devices (UsbDevice[] devices) is not callable using argument types (Filter!(__dgliteral1,UsbDevice[]))
bugs/tbolsh_d2_bug4.d(19): Error: cannot implicitly convert expression (filter(devices)) of type Filter!(__dgliteral1,UsbDevice[]) to UsbDevice[]
bugs/tbolsh_d2_bug4.d(20): Error: undefined identifier gateways
bugs/tbolsh_d2_bug4.d(20): Error: foreach: _error_ is not an aggregate type
Comment 3 Timofei Bolshakov 2011-01-26 10:53:14 UTC
I am sorry for the line 

> UsbDevType.gateway; } )( devices ) );
>     foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
> }

It is not needed there - cut and paste error. But it will remove only 2 last errors, "filter" related errors will still be there:

> tbolshakov@owner-laptop:~/projects/D$ dmd -unittest bugs/tbolsh_d2_bug4.d 
> bugs/tbolsh_d2_bug4.d(18): Error: function tbolsh_d2_bug4.associate_devices
> (UsbDevice[] devices) is not callable using argument types
> (Filter!(__dgliteral1,UsbDevice[]))
> bugs/tbolsh_d2_bug4.d(19): Error: cannot implicitly convert expression
> (filter(devices)) of type Filter!(__dgliteral1,UsbDevice[]) to UsbDevice[]
Comment 4 Timofei Bolshakov 2011-01-26 11:05:52 UTC
I got several other similar errors in find, like

/usr/include/d/dmd/phobos/std/functional.d(74): Error: static assert  "Bad unary function: a.parent_id == usb_id for type UsbDevice"
/usr/include/d/dmd/phobos/std/functional.d(87):        instantiated from here: Body!(UsbDevice)
/usr/include/d/dmd/phobos/std/algorithm.d(2699):        instantiated from here: result!(UsbDevice)
ampt/field_computer/usbmon.d(312):        instantiated from here: find!("a.parent_id == usb_id",Filter!(gateways_pred,UsbDevice[]))

Or 

ampt/field_computer/usbmon.d(295): Error: cannot implicitly convert expression (filter(devlist)) of type Filter!(gateways_pred,UsbDevice[]) to UsbDevice[]


That all makes functional style marginal - I do not know when and why it break next time.
Comment 5 bearophile_hugs 2011-01-26 11:37:32 UTC
(In reply to comment #0)

> import std.algorithm, std.conv, std.stdio;
> 
> enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 =
> 0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
> struct UsbDevice { //{{{ 
>     UsbDevType dev_type;
>     // not essential here ...
>     string toString(){ return to!string( dev_type ); }
> }
> 
> UsbDevice [] gateways_only( UsbDevice []devices ){ return filter!("a.dev_type
> == UsbDevType.gateway" )( devices ); }

This works:

auto gateways_only(UsbDevice[] devices) {
    return filter!((a){ return a.dev_type == UsbDevType.gateway; })(devices);
}(In reply to comment #0)
> The following code:
> _______________________________________________________________________________
> import std.algorithm, std.conv, std.stdio;
> 
> enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 =
> 0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
> struct UsbDevice { //{{{ 
>     UsbDevType dev_type;
>     // not essential here ...
>     string toString(){ return to!string( dev_type ); }
> }
> 
> UsbDevice [] gateways_only( UsbDevice []devices ){ return filter!("a.dev_type
> == UsbDevType.gateway" )( devices ); }
> 
> unittest{
>     auto devices  = [ UsbDevice( UsbDevType.gateway ), UsbDevice(
> UsbDevType.indifferent ), UsbDevice( UsbDevType.hub_dub_7 ) ];
>     auto gateways = gateways_only( devices );
>     foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
> }

The formatting of your code is very bad.
This works:


import std.algorithm, std.conv, std.stdio;

enum UsbDevType: uint {
    indifferent = 0,
    parent_of_checked = 1,
    hub_dub_7 = 0x2001f103,
    spider_hub = 0x05e30608,
    gateway = 0x11A03232
}

struct UsbDevice {
    UsbDevType dev_type;

    string toString() {
        return to!string(dev_type);
    }
}

auto gateways_only(UsbDevice[] devices) {
    return filter!((a){ return a.dev_type == UsbDevType.gateway; })(devices);
}

void main() {
    auto devices = [UsbDevice(UsbDevType.gateway),
                    UsbDevice(UsbDevType.indifferent),
                    UsbDevice( UsbDevType.hub_dub_7)];

    auto gateways = gateways_only(devices);
    foreach (UsbDevice dev; gateways)
        writeln(dev.toString());
}


Currently string-defined functions that you give to filter, map, etc, can't use symbol names defined elsewhere, like UsbDevType. So you need to use a lambda template, as I have done here, or a proper delegate.
Comment 6 SomeDude 2012-04-22 15:49:42 UTC
I haven't checked the original code, but bearophile's code gives on 2.059:

PS E:\DigitalMars\dmd2\samples> rdmd bug.d
gateway
Comment 7 bearophile_hugs 2012-04-24 18:55:55 UTC
This bug report, and the code examples, are rather messy.

This code can't work because Phobos filter() returns a range, so if you want a UsbDevice[] you need to attach an ".array()" at the end.

UsbDevice [] gateways_only( UsbDevice []devices ){ return filter!("a.dev_type
== UsbDevType.gateway" )( devices ); }


And because of the way "string lambdas" are defined, they can't work well here. But we have the lambda syntax now.

So code like this works:


import std.algorithm, std.conv, std.stdio, std.array;

enum UsbDevType: uint { indifferent = 0, parent_of_checked = 1, hub_dub_7 =
0x2001f103, spider_hub = 0x05e30608, gateway = 0x11A03232 }
struct UsbDevice { //{{{
    UsbDevType dev_type;
    // not essential here ...
    string toString(){ return to!string( dev_type ); }
}

UsbDevice [] gateways_only( UsbDevice []devices ){ return filter!(a => a.dev_type
== UsbDevType.gateway)( devices ).array(); }

void main() {
    auto devices  = [ UsbDevice( UsbDevType.gateway ), UsbDevice(
UsbDevType.indifferent ), UsbDevice( UsbDevType.hub_dub_7 ) ];
    auto gateways = gateways_only( devices );
    foreach( UsbDevice dev; gateways ) writeln( dev.toString() );
}


So there is no bug in DMD/Phobos here, closed as INVALID.