Advanced Elm Validated Data
Transcript from the "Validated Data" Lesson
>> Richard Feldman: Okay, so let's look at a couple of examples of opaque types in practice and the guarantees they can give us. So this is one from rtfeldman/elm-validate. This is a form Validation library. And it's got this module called Validate and it exposes two values that we care about for the purposes of this example.
[00:00:16] One is called Validator, the other is called Valid. So Validator essentially describe some validation that is going to perform on some piece of the data. So you might say, for example, I've got a Validator for my form type and it's going to validate that there's field called user name which is not blank.
[00:00:31] There's an email address field that's got an at symbol in it, and maybe there is password which matches the confirm password field, something like that. The type Valid, I'm gonna show you the implementation detail of it, is extremely boring. It's not quite as bad as the email one we saw in the previous slide, but it's extremely, extremely boring.
[00:00:49] It's type Valid a = Valid a. So in other words, it's just a wrapper around whatever. It's a wrapper that adds no additional information. All it does is wrap the thing that you give it. However, it turns out it's actually got a [LAUGH] surprisingly useful purpose. So we also expose a function called fromValid, which means if you give me a valid thing, I will just give you back the thing inside of itself, sort of unwrap it, and give it back to you.
[00:01:14] Which again would be pretty boring except for there is only one way to get one of these valid values. So notice that we have not exposed the valid variance, just the type itself. So it is okay to other modules. And the only way to get one is by calling this function called Validate.
[00:01:31] So Validate takes a Validator which you've constructed elsewhere. So Validator has two type parameters, one is the error type so you can give it a custom error type if you want, and then the subject. Then it takes the subject, and it returns a result with either a list of errors if the validation failed.
[00:01:48] In which case it says hey, here are all the things that went wrong. Or it gives you back the subject wrapped in a Valid. So this is the only way to obtain one of these Valid wrappers is to call Validate passing whatever your particular subject is. Once you've got one of those you can unwrap it, but the only way to get one in the first place is to call Validate.
[00:02:07] Why might that be useful? Well, imagine we wanted to write a function like this. SubmitForm takes a valid form and returns an HTTP request that ends up giving you a user. So this might be a sign-up form or something like that. So what's cool about this is if I write this type, I know that the only way that I'm going to be able to submit the form is if it's been validated first.
[00:02:29] So this tiny simple, unremarkable wrapper that has essentially no logic inside of it, just by virtue of its existing guarantees that I can't forget to validate my form before submitting it. That has to happen. So the submit form function just by adding the six characters on the front it gives us guarantee that it's no longer possible to forget to take care of form validation.
[00:02:51] So essentially the whole purpose of this type is only to be opaque. If this type were not opaque, then that guarantee would go out the window. I could no longer add this to my form and say, yes, this ensures that I remember to validate it. Because it's entirely possible that somewhere in my code I just said, [SOUND] forget it, I'll instantiate this thing.
[00:03:09] Or maybe somebody who is new to the team and didn't realize what it was supposed to be marking said I don't know how I'm supposed to get a Valid Form. I'll just go ahead and construct one cuz that thing's in scope. If somebody new to the team did try to do that, they would find that it wouldn't compile just like our email example from earlier.
[00:03:24] They'd go hunting through the documentation. Eventually they would say, the only way I can actually get one of these is I have to call Validate, etc. So this is going to be the first in a long series of examples of things of the form. It's better to make it so that it won't compile if you don't remember to do the thing than it is to document hey, everyone, please do the thing and everyone always remember that perfectly forever.
[00:03:44] Nice thing about the compiler is it always remembers.