Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight extra required methods for iterators #50069

Merged
merged 1 commit into from
Aug 9, 2023

Conversation

cmcaine
Copy link
Contributor

@cmcaine cmcaine commented Jun 5, 2023

A student on exercism read this section and did not realise that they had to define at least one of Base.IteratorSize and length.

I'm not totally happy with this revision, but it does seem a bit clearer to me. Some particular bits that I think could be better:

  • eltype is called a required method, but that's only sorta true because the default definition is probably fine.
  • it's a bit long?
    • Maybe one big table with columns "Must be defined if", "Method", "Default definition", "Brief description" would be better, but it would be quite wide.

Because the visual appearance of the docs isn't totally clear from the markdown, here are before and after images.

Before:

image

After:

image

Another variant option (one big table for all conditionally-required methods):

image

Source for the variant option
There are two methods that are always required:

| Required method        | Brief description                                                                        |
|:---------------------- |:---------------------------------------------------------------------------------------- |
| `iterate(iter)`        | Returns either a tuple of the first item and initial state or [`nothing`](@ref) if empty |
| `iterate(iter, state)` | Returns either a tuple of the next item and next state or `nothing` if no items remain   |

There are several more methods that should be defined in some circumstances. Note that 
because the default definition of `Base.IteratorSize(IterType)` is `Base.HasLength()`, you should define at least one of `Base.IteratorSize(IterType)` and `length(iter)`.

| When should this method be defined?                                            | Method                          | Default definition | Brief description |
|:--- |:--- |:--- |:--- |
| If default is not appropriate                                                  | `Base.IteratorSize(IterType)`   | `Base.HasLength()` | One of `Base.HasLength()`, `Base.HasShape{N}()`, `Base.IsInfinite()`, or `Base.SizeUnknown()` as appropriate                                                                     |
| If `IteratorSize(IterType)` returns `Base.HasLength()` or `Base.HasShape{N}()` | `length(iter)`                  | (*undefined*)      | The number of items, if known                                                                                                                                                    |
| If `IteratorSize(IterType)` returns `Base.HasShape{N}()`                       | `size(iter, [dim])`             | (*undefined*)      | The number of items in each dimension, if known                                                                                                                                  |
| If default is not appropriate                                                  | `Base.IteratorEltype(IterType)` | `Base.HasEltype()` | Either `Base.EltypeUnknown()` or `Base.HasEltype()` as appropriate                                                                                                               |
| If default is not appropriate                                                  | `eltype(IterType)`              | `Any`              | The type of the first entry of the tuple returned by `iterate()`                                                                                                                 |
| If iterator is stateful                                                        | `Base.isdone(iter[, state])`    | `missing`          | Fast-path hint for iterator completion. Should be defined for stateful iterators, or else `isempty(iter)` may call `iterate(iter[, state])` and mutate the iterator. |

A student on exercism read this section and did not realise that they
had to define at least one of `Base.IteratorSize` and `length`.

I'm not totally happy with this revision, but it does seem a bit clearer
to me.
@brenhinkeller brenhinkeller added domain:docs This change adds or pertains to documentation domain:iteration Involves iteration or the iteration protocol labels Aug 5, 2023
@brenhinkeller brenhinkeller added the status:merge me PR is reviewed. Merge when all tests are passing label Aug 6, 2023
@cmcaine
Copy link
Contributor Author

cmcaine commented Aug 7, 2023

I included two variants above. The PR represents the first one (screenshot 2). Since writing the PR I've come to think that the second one (one big table for all conditionally-required methods) is better (screenshot 3).

But now that this has a review and a merge-me tag, it seems rude to change the PR unilaterally. So, whoever comes to merge this, please consider the second variant above (code and screenshot is in the first post).

@LilithHafner
Copy link
Member

This is an improvement, so I'm going to merge it now.

Separately, as a PR author IMO you are always allowed to make unilateral changes to your PR. And, if you still prefer something else over the current state of this PR, feel free to make another one to change this documentation again.

@LilithHafner LilithHafner merged commit 43b2c44 into JuliaLang:master Aug 9, 2023
3 checks passed
@LilithHafner LilithHafner removed the status:merge me PR is reviewed. Merge when all tests are passing label Aug 9, 2023
cmcaine added a commit to cmcaine/julia that referenced this pull request Aug 21, 2023
A few beginner and intermediate Julia programmers shown both versions
thought this one was clearer.

Follows on from JuliaLang#50069
@cmcaine
Copy link
Contributor Author

cmcaine commented Aug 21, 2023

Cool, thanks. Please consider merging my follow-up PR on this topic: #50994

staticfloat pushed a commit that referenced this pull request Aug 22, 2023
A few beginner and intermediate Julia programmers shown both versions
thought this one was clearer.

Follows on from #50069

Two other minor changes:

- includes `Base.isdone` in documenter output so that it can be linked
from the table (this probably should have been done when we originally
included it in the table).
- update the warning on `isempty` about stateful iterators to be a
little less strident, because `isempty` shouldn't cause any bugs for
stateful iterators that correctly implement the documented interface
(and I think I fixed all the stateful iterators in Base quite a while
ago now).

Before:


![image](https://user-images.githubusercontent.com/6000761/243437416-65a0e54e-0dcd-4c79-88e2-087166766eb7.png)

After:


![image](https://github.com/JuliaLang/julia/assets/6000761/fab836ee-4e24-4a3e-a5ca-6ba582e4ccab)

I don't think it matters much, but the lengths of the columns are mostly
determined by the longest `code` span within them, because the code
spans are not wrapped. We can allow the browser to perform word wrapping
within the spans by including `<wbr />` elements or unicode
zero-width-space characters, but I can't get the cross references
(links) to work. This is what I tried:

```md
before

[`Base.IteratorEltype(IterType)`](@ref)

after (encouraging browsers to break the line at the dot):

[<code>Base.<wbr />IteratorEltype(IterType)</code>](@ref Base.IteratorEltype)

Which gives the following error:

┌ Error: reference for 'Base.IteratorEltype' could not be found in src/manual/interfaces.md.
└ @ Documenter.CrossReferences ~/src/julia/doc/deps/packages/Documenter/yf96B/src/Utilities/Utilities.jl:32
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:docs This change adds or pertains to documentation domain:iteration Involves iteration or the iteration protocol
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants