gampleman / elm-visualization

A data visualization library for Elm

Home Page:http://package.elm-lang.org/packages/gampleman/elm-visualization/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Break out Scale type

gampleman opened this issue · comments

One of things that always bugs me are the types in the Scale module. They:

  • Are very complicated.
  • Possibly unique, in the sense that no other Elm library (afaik) uses types in quite the same way.
  • The documentation even instructs the user to not pay too much attention to the types. This is clearly not idiomatic to Elm.
  • The documentation needs to point out which functions can be used with which types.
  • The errors could be better
  • The library uses type aliases to hide how the types work.

The reason they were designed that way is that I wanted to have a generic Scale type, that could be operated on regardless of what kind of scale there was, yet not all scales support all operations. I knew I definitely didn't want runtime failures (i.e. unnecessary Maybes), hence this design.

One option is trying to figure out some phantom types to simplify this, but I have tried this before and not made much progress.

The other option is to abandon the generic Scale type and simply have a module and type for each kind of scale (i.e. there would be Scale.Continuous, Scale.Sequential, etc). This would make the types straightforward and the internal logic equally so. Each of these would need an adaptor function for Axes (which we already kind of have for band scales). All the above disadvantages would go away, however there are some downsides:

  • No more generic programming. Is this a problem? Do people use Scales generically or is this a concern literally just for Axes?
  • Right now dead code elimination works very efficiently - you ship code only for scales you use. It would be likely that if you used Axes, you would need to ship some code for all scales that supported Axes. There is not a huge amount of code behind every Scale type, so this might be acceptable.
  • There would be no central Scale module, so there is less of a sensible place to introduce the concept as a whole.

Anyway, this issue is just putting down some thoughts. I have not committed to this, I am seeking feedback on these options, so please feel free to offer your opinion.

Perhaps an intermediate option (which could theoretically be shipped in some sort of non-breaking manner even!) would be to keep the current Scale implementation (although I would like to rename it to Scale.Advanced or Scale.Generic) and add a new module for each Scale type.

This module would contain the type alias, the constructor functions, and also aliases to all the supported operations, but this time with the nice function signatures.

So far I think this has the following set of advantages:

  • The individual scale modules make it clear what functions can be used and have sensible type signatures.
  • No more listings of supported operations necessary.
  • Generic programming with Scales is still possible, but hints are given that this is somehow an "advanced" use case rather than the first thing users of the library need to get their head around.
  • I believe the error messages would also improve if the generic module wasn't being used.

The disadvantages:

  • The unconventional implementation still exists (mostly a problem for == or storing in Model/Msg, etc.), it's just more hidden.
  • The large number of modules might look a bit scary...