It's been a while since I joined the Elm Slack. During this time, I have seen different folks ask how, and when, to use opaque types. I have also s...
For further actions, you may consider blocking this person and/or reporting abuse
Great explanation of opaque types, thank you!
What do you think of the following additional improvement? The model currently specifies both
titleandbodyasStringtypes. So in theSubmitlogic it's possible to accidentally pass the wrong string, such as Question.titleFromString model.body but then ifbodystill happens to pass the validation fortitleyour view will be wrong but give you no errors. To prevent this, create atype alias TitleString = Stringand then use that in the model instead of plainString. Then Bob will also know that TitleString and BodyString can never be interchanged accidentally. Does that seem like overkill (or have a flaw I'm not seeing)?That's not really a question about opaque types, it's on the general theme of "catch everything at compile time" which is what's great about Elm!
Good question!
The issue is that a
type aliasis just a new name for a type (an alias). Therefore,TitleStringis a just new way to sayString. This means thatQuestion.titleFromString model.bodywould still compile, even when usingTitleStringin yourModelandQuestionAPI. The compiler would seeStringeverywhere.We can use an opaque type! Imagine we define a
Question.TitleFieldmodule with this API:This module ties a a
TitleFieldvalue with its form fieldviewand its validation. Finally, we useTitleFieldin ourModel, usingblankto initialize it,titlefor validation, andviewto render it!composable-form can help you write this:
I'm glad this led back to opaque types. 8-D Using something like
TitleFieldtype is probably too much for the simple example, but a great solution for a site that has to be really robust!hecrj/composable-formlooks great, I'm going to check that out too.As for type aliases... I don't know enough about compiler design to have an informed opinion, but what I described is how I would "want" type aliases to work. I totally understand that after being compiled they're all just
Strings (in this example), but if the coder specifies a different name I think I want a step somewhere that will catch that if the wrong name is used. But yourTitleFieldsolution is better anyway, it provides a lot more than just a new name for a type. 8-)How about to hide 'validation' behind the 'create' method?
What do you think about it?
Then the
createfunction does multiple things. Not desirable. For instance, how would you show validation errors without submitting the form?For instance we have function which get 2 numbers and return sum of them. The first number is odd and the second is even.
Should we create new types for these values (like you did for title and body) because we validate them?
Do we break Single Responsobiliy Principal?
Does it make sence to create separate type if we don't use them in other places?
Opaque types allow to capture guarantees and propagate them. If you only need these guarantees on a specific part of your code and there is no need to propagate them, then it is probably not worth it to create opaque types for them. In other words, not every "validation check" should result in an opaque type.
However, most of the time this is an API design choice. For instance, I would understand this API better than the example you provided:
The advantages here are:
sumerror-free! We can call it multiple times without having to deal with errors:sum (sum odd even) evensumvalue is guaranteed to be anOddnumber.Great post. I was wondering about the use of Http.Error. Why are you using that when creating a Question, it has nothing to do with Http?
Thank you!
As I say here:
We assume that the
Questionneeds to be created remotely in some backend. Although I don't mentionHttpspecifically, the most common strategy is to do this by making a request to an HTTP API.In any case, the error type could be something entirely different. It is not relevant to understand the concepts presented in the post.
Ok, get it. Thanks.