[erlang-questions] Emulating phantom types maybe
Daniel Abrahamsson
daniel.abrahamsson@REDACTED
Fri Aug 26 07:57:36 CEST 2016
You can achieve something close to what you are after by using opaque
types. Partly re-using your original example:
-module(string_with_case).
-opaque lowercase() :: string().
-opaque uppercase() :: string().
-type anycase() :: lowercase() | uppercase() | string().
-export_type([ lowercase/0
, uppercase/0
]).
-export([ uppercase/1
, lowercase/1
, need_lower/1
, concat/2
]).
-spec lowercase(anycase()) -> lowercase().
lowercase(Str) -> string:to_lower(Str).
-spec uppercase(anycase()) -> uppercase().
uppercase(Str) -> string:to_upper(Str).
-spec need_lower(lowercase()) -> ok.
need_lower(_Lower) -> ok.
-spec concat(anycase(), anycase()) -> string().
concat(A, B) -> A ++ B.
Note that these two (maybe in your eyes valid) examples will NOT pass
dialyzer:
string_with_case:need_lower("example"). % FAILS: Breaks opaqueness of
string_with_case:lowercase().
string_with_case:lowercase("test") ++ "mixing". % FAILS: Breaks opaqueness
of string_with_case:lowercase().
In other words, all operations involving types uppercase() or lowercase()
must take place inside the string_with_case module.
If you need to operate on a lowercase() as if it were a string outside the
string_with_case module, you must provide a to_string function:
-spec to_string(anycase()) -> string().
to_string(X) -> X.
This of course means you would have to call the lowercase/1 or uppercase/1
functions again to convert it back, should you need to
use the "variant/sort specific" functions of string_with_case on the
result. This is however necessary to maintain the guarantees you are trying
to achieve.
//Daniel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20160826/fbcef761/attachment.htm>
More information about the erlang-questions
mailing list