-
Notifications
You must be signed in to change notification settings - Fork 197
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
Phantom Types (contributors, please take note!) #375
Comments
@rtfeldman Doesn't this commit elm/compiler@5fb82e2 "break" phantom types? type Value a -- `a` is now an unbound type variable error?
= Value String |
according to Evan:
|
rtfeldman
changed the title
Phantom Values (contributors, please take note!)
Phantom Types (contributors, please take note!)
Mar 22, 2018
This was referenced Mar 30, 2018
Closed
@rtfeldman could you add link to the issue at README? Maybe on the top that contributors see it first. |
@owanturist Added to |
Merged
This was referenced Sep 2, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm working on having
Css.Value
use phantom types. (More on what this means below.)If you're using
elm-css
, you may not even notice this change when it comes out (except that you may notice things running faster), but if you're contributing to currentmaster
, this will almost certainly lead to merge conflicts - so watch out! Any large PR will likely need numerous changes once this is finished, and I would strongly recommend opening an issue before making a PR so we can coordinate.You can follow progress on the
phantom-types
branch. This one is gonna take awhile to finish. 😅The Change
On current
master
,Css.Value
is defined like this:On the
phantom-values
branch it's instead defined like this:A union type with a type variable which doesn't appear in any constructors is known as a phantom type. I'm somewhat annoyed that they have such a cool name, because it makes me feel like I should use them more often...when in reality, they are useful under very rare circumstances.
However,
elm-css
happens to be one of them!What the phantom type lets us do is move our compatibility information from runtime values to compile-time values. For example:
This can now become:
The difference is subtle, but impactful. We still get all the same compile-time verification as before, but whereas before we actually had to instantiate all those fields in real objects, the runtime representation of
Value
is now always a singleString
constructor:type Value a = Value String
. All the compatibility checking information now exists at compile time only.If that were the only part of the refactor, though, that wouldn't be a terribly big change. The big change is shifting around how the extensible records work.
Much Nicer Error Messages
Credit to @ianmackenzie for showing me this. Switching around which records are extensible and which ones are not can result in much nicer documentation and compile-time error messages for
elm-css
!For example, let's consider how
color
andrgb
interact.Status Quo
Here's how these are defined right now.
After the Change
Here's how they're defined on the
phantom-values
branch.The first benefit of this is that its type signature is much more useful than before.
What can I pass to the
color
function? Values returned byrgb
,rgba
,hsl
,hsla
, andhex
, just like it says incolor
's type signature. I can instantly go look up the docs for any of those if I want to know what they do.The second benefit is that we get much more helpful error messages. Before, if we tried to do
color (px 10)
here's what we'd get:On the
phantom-values
branch, here's what we get instead:With a small bit of learning, we can get a ton more out of this error message. It's telling us that the value we used was constructed with the
px
function, and that it was expecting a value constructed usinghex
,hsl
,hsla
,rgb
, orrgba
instead.That's way more directly useful than seeing stuff like
lengthOrNumberOrAutoOrNoneOrContent
with the status quo.The Plan
I'm gonna switch everything in the
Css
module to use both phantom types as well as this new style of extensible records vs. non-extensible records.Even though things will fit together the same way when it's done—so glad we have an extensive test suite to guard against regressions!—this is not a direct one-to-one transformation. I can't write a script to automate it. It's just gonna take time. 😄
Since I have to touch so many functions by hand anyway, while I'm at it, I'm also making sure everything has real documentation (too many
{-| -}
docs in the current release), and I'm also knocking out some easy performance optimizations along the way.It's gonna be sweet! 😸
The text was updated successfully, but these errors were encountered: