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

Iteration protocol #17

Open
jdpage opened this issue Dec 11, 2017 · 1 comment
Open

Iteration protocol #17

jdpage opened this issue Dec 11, 2017 · 1 comment

Comments

@jdpage
Copy link
Collaborator

jdpage commented Dec 11, 2017

It'd be neat to allow for ... in ... do ... end loops to work on things other than the built-in ranges and arrays. Since we're not object-oriented (and afaik have no aspirations to be so), I'd like to suggest the following protocol for iterable types. For an iterable type foo, define three methods in the same unit (where T and U are arbitrary types):

  • a foo#iter function to create the iterator, one of:

      fun foo#iter(x: &foo) -> T ... endfun
      fun foo#iter(x: foo) -> T ... endfun
    
  • a foo#iter-next function to advance the iterator, one of:

      fun foo#iter-next(x: &foo, i: &mut T) -> bool ... endfun
      fun foo#iter-next(x: foo, i: &mut T) -> bool ... endfun
      fun foo#iter-next(i: &mut T) -> bool ... endfun
    
  • a foo#iter-value function to get the current value of the iterator, one of:

      fun foo#iter-value(x: &foo, i: &T) -> U ... endfun
      fun foo#iter-value(x: &foo, i: T) -> U ... endfun
      fun foo#iter-value(x: foo, i: &T) -> U ... endfun
      fun foo#iter-value(x: foo, i: T) -> U ... endfun
      fun foo#iter-value(i: &T) -> U ... endfun
      fun foo#iter-value(i: T) -> U ... endfun
    

Yes, the # is part of the function name, so I'm suggesting that name for "protocols". Note that we allow some wobbliness in the protocol as to by-value/by-address passing, and whether or not the iterated-upon object is passed in; as long as the compiler can resolve a function from each of the three groups, the object is considered iterable.

An (example, unnecessary) implementation for a struct wrapping an array of u8s (using unreviewed struct syntax):

struct my-u8s
    values: [u8; 10]
endstruct

fun my-u8s#iter(x: &my-u8s) -> u8
    return 255
endfun

fun my-u8s#iter-next(i: &mut u8) -> bool
    @i += 1 --[[ this overflows to 0 on the first call ]]
    return @i < 10
endfun

fun my-u8s#iter-value(x: &my-u8s, i: u8) -> u8
    return x.values[i]
endfun

Given the above, we can write a for ... in ... do ... end loop:

let z: my-u8s = ...
for x: u8 in z do
    ...
endfor

... which would desugar to something like:

let z: my-u8s = ...
let mut _z#iter = my-u8s#iter(&z)
while my-u8s#iter-next(&mut _z#iter) do
    let x: u8 = my-u8s#iter-value(&z, _z#iter)
    ...
end

Additional functions could be defined for mutating iterators (for mut ... in ... do ... end), e.g. a foo#iter-mut-value which returns a mutable pointer.

@jdpage jdpage added the syntax label Dec 11, 2017
@woodrowbarlow
Copy link
Collaborator

woodrowbarlow commented Dec 11, 2017

i think this should stay in the backlog for now. i think it's a lofty idea and it's not something that we have to design-in early-on.

although if you want to go ahead and reserve the # token and add it to the specials, i think that's fine.

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

No branches or pull requests

2 participants