We've run into the same problem at Bluecode and decided to provide an escape hatch with generic parser.
```
def get_env(key, default, parser \\ &string/2, parser_opts \\ []) do
if val = System.get_env(key) do
case parser.(value, opts) do
{:ok, parsed} -> parsed
{:error, reason} -> default
else
default
end
end
```
where parser is a fun `parser(String.t() :: {:ok, term()} | {:error, term()}`
We've found it super powerful because:
a) it is easy to define custom parsers
```
def get_boolean(key, default) when default in [true, false] do
get_env(key, default, &boolean/2, [])
end
def boolean(value, _) do
value = String.to_atom(value)
if value in [true, false] do
{:ok, value}
else
{:error, "not a boolean"}
end
```
The cool part is that the decision how to parse the variable is completely up to implementer of the use case.
You have "0" and "1" in the config? Just match that in the parser.
We are using the final `opts` to pass to parser, e.g. for atom parser, we add `allow: [:value1, :value2]` and then we can reject unknown.
`get_atom(key, default, allow: [:value1, :value2])`
Actually, the library we have is not general purpose. E.g. we do some logging in those get_envs to identify if variable is missing or parsing went wrong and with what error.
We also have a bunch of opinionated things in the library.
E.g. one of the things that bothered us with configs was that it was easy to add something in test to make tests pass and then forget in dev.
We decided to move everything to `runtime.exs` and added a convention that variable `FOO=bar` will be used in both dev and test, unless you override it for test with `TEST_FOO=baz`. Then in dev FOO=bar and in test FOO=baz.
Anyway, my point is: I wouldn't add specific cases like boolean and integer to standard library. This raises a question: why not atoms or modules or pids or all other basic and complex cases. Adding optional parser and parsing options would be very generic and accommodate for any usecase anyone can imagine without burdening standard library with decisions such as "should string "0" be false or not be a boolean at all".