I've used types before but don't know what an opaque type is. I've seen it mentioned as well. Is it better to expose an opaque type than a type alias?
1 Answers
Let’s answer this question by first looking at type aliases:
A type alias is fully transparent. This means that any other module importing it will have full access to its inner workings. Let’s say we’ve got a User
module exposing a User
type:
module User exposing User
type alias User =
{ userName : String
, age : Int
}
Anyone importing User
can manipulate the data, e.g. newUser = { oldUser | age = 25 }
. Or do someUser = User "Bill" 27
. These manipulations are fine when you have control over the context that they exist in.
However, if User
is part of a library then every change to the User
type is a breaking change to people that use the library. For example, if an email
field is added to User
, then the constructor example (someUser = User "Bill" 27
) will give a compiler error.
Even inside of a project codebase, a type alias can provide too much information to other modules which leads to code that is difficult to maintain and evolve. Perhaps a User
changes drastically at some point and has a completely new set of properties. This would require changes wherever the code manipulates User
s.
Opaque types are valuable because they avoid these issues. Here’s an opaque version of User
:
module User exposing User
type User =
User
{ userName : String
, age : Int
}
With this version, other modules cannot access or manipulate the data directly. Often, this means you will make and expose some getter and functions:
initUser : String -> Int -> User
userName : User -> String
age : User -> String
setAge : Int -> User -> User
This is more work, but it has advantages:
- Other modules only care about the
User
functions and don’t need to know what data is in the type - The type can be updated without breaking code outside the containing module
Much of this explanation comes from @wintvelt: elmlang.slack.com
-
Here's some more discussion for authors of libraries and packages about the value: http://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret – Nathan Nov 24 '16 at 20:57
-
Thank for sharing this explanation. Because about half of it is an exact copy of an answer I posted earlier over on Slack ([here](https://elmlang.slack.com/archives/design-patterns/p1480011953000265)), a mention or link would have been nice. – wintvelt Nov 25 '16 at 19:06
-
1Hey @wintvelt: Sorry! I thought it was a really good answer that would be helpful living in a more permanent place. I added a reference to your SO account. Maybe an SO mod could add you as an author? – Nathan Nov 26 '16 at 15:02
-
Thanks for the mention. Appreciate it. Common practice in such cases is - I think - to add at least a link to your source (link is already in my comment :). – wintvelt Nov 26 '16 at 15:14