Skip to content

HasLength() is the default iteratorsize for all custom iterators? Even if they don't define length? (Breaks Collect) #15977

Closed

Description

I was confused as to why my custom iterator, was failing to collect

Consider the MWE:

type Foo
    values::Vector{}
end

function Base.start(f::Foo)
    return 1
end
function Base.next(f::Foo, state)
    f.values[state], state+1
end
function Base.done(f::Foo, state)
    state>length(f.values)
end

Running with a for loop works fine:

for f in Foo([1,2,3])
    print(f)
end
> 123

Collecting Breaks:

collect(Foo([1,2,3]))
>LoadError: MethodError: no method matching length(::Foo)
while loading In[26], in expression starting on line 1

This is true -- there is not method to find the length of a ::Foo
So why is it being ask?

Because

Base.iteratorsize(Foo([1,2,3]))
>Base.HasLength()

It thinks it has a length.

I think it is coming from:

iteratorsize(::Type) = HasLength() # HasLength is the default

The workaround is to add to my definition

Base.iteratorsize(::Foo) = Base.SizeUnknown()

But I feel like this should be being inferred, by the face that neither size(::Foo) or Length(::Foo) are defined?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

docsThis change adds or pertains to documentation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions