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

Rework map and map! #62

Merged
merged 1 commit into from
Jan 20, 2021
Merged

Rework map and map! #62

merged 1 commit into from
Jan 20, 2021

Conversation

timholy
Copy link
Member

@timholy timholy commented Jan 16, 2021

There are several things that are a bit complicated/confusing about
map and map!:

  • the init keyword also affects whether f runs (controlling the initial
    value is not orthogonal to execution, which spells trouble for
    functions with side effects)
  • in contrast with Base.map!, map!(f, dest::Observable, args..)
    does not eagerly update dest---that doesn't happen until one of
    args updates
  • map always yields an Observable{Any}, somewhat in contradiction
    to the behavior of Base.map (see map does not infere type #34)

This redesigns map and map! to address these issues (fixes #34).
It is a breaking change, although I've put in a depwarn for the case
where init was supplied. (The non-deprecated changes are so fundamental
that this may not be useful, however.)

Now:

  • map always runs f on initial creation
  • map! typically runs f on the initial call, but it can be
    suppressed with an update=false keyword
  • map creates an Observable{T} with specific T, but users can
    control output eltype by using map!(f, Observable{S}(), args...)
    instead.

Using the new API, the old map behavior can be obtained with

    map!(f, Observable{Any}(), args...)

or with an init it's

    map!(f, Observable{Any}(init), args...; update=false)

There are several things that are a bit complicated/confusing about
`map` and `map!`:
- the `init` keyword also affects whether `f` runs (controlling the initial
  value is not orthogonal to execution, which spells trouble for
  functions with side effects)
- in contrast with `Base.map!`, `map!(f, dest::Observable, args..)`
  does not eagerly update `dest`---that doesn't happen until one of
  `args` updates
- `map` always yields an `Observable{Any}`, somewhat in contradiction
  to the behavior of `Base.map` (see #34)

This redesigns `map` and `map!` to address these issues (fixes #34).
It is a breaking change, although I've put in a depwarn for the case
where `init` was supplied. (The non-deprecated changes are so fundamental
that this may not be useful, however.)

Now:
- `map` always runs `f` on initial creation
- `map!` typically runs `f` on the initial call, but it can be
  suppressed with an `update=false` keyword
- `map` creates an `Observable{T}` with specific `T`, but users can
  control output `eltype` by using `map!(f, Observable{S}(), args...)`
  instead.

Using the new API, the old `map` behavior can be obtained with
    map!(f, Observable{Any}(), args...)
or with an `init` it's
    map!(f, Observable{Any}(init), args...; update=false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

map does not infere type
1 participant