# Safe unsafe operations in Elm

**URL:** <https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659>\
**Category:** Show and Tell\
**Created:** [April 27, 2020, 10:17am UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659 "2020-04-27T10:17:50Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jfmengels](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jfmengels/32/3124_2.png) [@jfmengels](https://discourse.elm-lang.org/u/jfmengels)\
**Post date:** [April 27, 2020, 10:17am UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/1 "2020-04-27T10:17:50Z")

</div>

Hi everyone!

I wrote a blog post how you can simplify your code and have more guarantees using the “safe unsafe” pattern.

I think it is a pretty good overview of how you can build [`elm-review`](https://package.elm-lang.org/packages/jfmengels/elm-review/latest/) rules, as we go from a simple rule to a reasonably complex one.

So if you are interested in either having more guarantees or learning more about `elm-review`, check out the blog post: is: [https://jfmengels.net/safe-unsafe-operations-in-elm/](https://jfmengels.net/safe-unsafe-operations-in-elm/)

Let me know what you think about this!  
There is an #elm-review Slack channel if you want to learn more about the tool 🙂

---

<div class="post-metadata">

**Author:** ![joshuakb2](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/joshuakb2/32/2811_2.png) [@joshuakb2](https://discourse.elm-lang.org/u/joshuakb2)\
**Post date:** [April 28, 2020, 6:25am UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/2 "2020-04-28T06:25:11Z")

</div>

Hey! I’ve never heard of elm-review, and I have to say I’m impressed with what it can accomplish.

This regex situation is a great example of the awkwardness of being safe when you can just look at the code and easily reason that it is correct, and the correctness of the code is fundamentally determinable at compile time, but the compiler doesn’t know how to make that judgment.

I’ll definitely look into this further and maybe this module will find its way into one of my projects.

---

<div class="post-metadata">

**Author:** ![SergKam](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/sergkam/32/1081_2.png) [@SergKam](https://discourse.elm-lang.org/u/SergKam)\
**Post date:** [April 29, 2020, 10:21am UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/3 "2020-04-29T10:21:39Z")

</div>

Nice trick! Can be used in a lot of places.  
I also had similar issues when trying to parse express.js like routes from string literals “/user/:id”  
It will be helpful to validate them at compile(review) time as well.  
It would be awesome for developer to be able to extend elm compiler itself with custom rules like this.

---

<div class="post-metadata">

**Author:** ![jackwilsdon](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jackwilsdon/32/2812_2.png) [@jackwilsdon](https://discourse.elm-lang.org/u/jackwilsdon)\
**Post date:** [April 29, 2020, 4:21pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/4 "2020-04-29T16:21:30Z")

</div>

Yep, I can see this being very useful for creating `Url` instances from a constant string too - good stuff @jfmengels!

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 30, 2020, 2:58pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/5 "2020-04-30T14:58:56Z")

</div>

Enjoyed the article.

Instead of doing this:

```elm
fromLiteral : String -> Regex
fromLiteral string =
    case Regex.fromString string of
        Just regex ->
            regex

        Nothing ->
            fromLiteral string

```

I have been tending to do:

```elm
type Error =
    IllegalRegex String 

fromLiteral : String -> Result Error Regex
fromLiteral string =
    case Regex.fromString string of
        Just regex ->
            Ok regex

        Nothing ->
            IllegalRegex string |> Err

```

and propagate the error up the call stack, possibly turning it into a common string format, or mapping it into broader error types as it goes, until I get it to a “catch all” point in my top-level `update` function. Then I log it as a bug for development to fix. Disadvantage of this is; its a pain to propagate errors everywhere; and its a shame to introduce something that acts like a runtime error into the program. However, if I avoid ever using `Result.withDefault` (which masks errors), then it does at least force my programs to always report these kinds of errors.

If you think about it, `Result.withDefault` is a bit like ignoring errors with `catch (Exception e) {}` in Java, which is nasty.

I like what you are proposing though, its kind of like a secondary and more advanced type checker for Elm isn’t it? Nice if you have a rule like this ready to go - I guess the downside of this approach is having to write more rules for other situations.

Another example might be a type that is restricted to certain values:

```elm
type Percent =  
    Percent Float
   
percent : Float -> Percent

```

and a rule for calling the percent function that only allows literal values from 0.0 to 100.0.

If the values are not being obtained from static code, but are being decoded from HTTP API calls, or user input in the UI. Then the `Result` approach is likely better (but its not necessarily a bug in that case).

A further downside is having to restrict to literal values - I know certain math operations will give me a valid result, but the review rules may not be so smart. The general case is getting into thoerem proving.

---

<div class="post-metadata">

**Author:** ![jfmengels](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jfmengels/32/3124_2.png) [@jfmengels](https://discourse.elm-lang.org/u/jfmengels)\
**Post date:** [April 30, 2020, 4:25pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/6 "2020-04-30T16:25:07Z")

</div>

> [@rupert](#):
>
> If you think about it, `Result.withDefault` is a bit like ignoring errors with `catch (Exception e) {}` in Java, which is nasty.

Absolutely. I think you should handle the error in the closest possible place in the call stack.

I tend to use the recursive pattern when I am sure of something but could not make it impossible with data or API modeling, but I cringe every time I use it (which is not that often thankfully).

I think your way of handling it is quite nice, especially wrapping it in a custom type that will give more information about the error. But as you said, it’s painful to use.

> its kind of like a secondary and more advanced type checker for Elm isn’t it?

Yes. The point is giving you more guarantees than what the Elm compiler does. In my mind, if you see [compiler as assistants](https://elm-lang.org/news/compilers-as-assistants), then `elm-review` is another assistant. It’s like having two people look over your shoulder to help you out.

> I guess the downside of this approach is having to write more rules for other situations.

I haven’t written about it in the article, but I believe that you can make a single rule that would handle multiple usecases. In the rule I wrote, I have already made it kind of generic by making the target names variables, and the target function check can just be a boolean.

What I’m saying is: You could make the rule work for several functions. You could hardcode, or even take as the rule’s arguments (by changing `rule` to `rule : List TargetFunctions -> Rule`), a list of target functions that could look like

```elm
type alias TargetFunctions =
  { name : String
  , moduleName : String -- Or List String
  , goodUseCheck : String -> Bool
  , errorMessage : String
  , errorDetails : String
  }

```

Then you’d loop over this list to handle all the functions. You’d need it to be more configurable if you want to target functions that work with number literals (like your `percent` example), List literals or more than one functions. But the idea is the same.

> If the values are not being obtained from static code… Then the `Result` approach is likely better

Definitely. I can’t stress this enough: If **it’s possible to have false negatives** (not reporting something that will be unsuccessful), then **don’t use this technique** and especially **don’t create an unsafe function**.

> A further downside is having to restrict to literal values - I know certain math operations will give me a valid result, but the review rules may not be so smart.

I wouldn’t call it a downside, since that means you need to resort to normal/unreviewed Elm, where you have less guarantees. The “safe unsafe” pattern just makes things simpler when you know things will be correct. Outside those boundaries, you’ll have to go back to Elm code that can fail, but which is the Elm code you know and love.

I think as more rules get built, we’ll end up with more and better tools, with type inference and computing of expressions (`1 + 2` =\> `3`). They may be tedious and CPU intensive, but they could make way for more and nicer rules.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 30, 2020, 7:31pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/7 "2020-04-30T19:31:58Z")

</div>

> [@jfmengels](#):
>
> I think you should handle the error in the closest possible place in the call stack.

Yes, if it is possible to recover from it, as that way you are nearest to the context in which it occured and therefore most likely to be able to make sense of it with respect to how you recover. In that case using `Result.withDefault` might be an acceptable way to recover.

The errors that I classify as bugs work more like runtime exceptions - they should just be passed up the stack to a top-level handler which has the responsibility to make a best effort to report them to the technical team for fixing. Its really just this class of errors that could be masked by `Result.withDefault`.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 30, 2020, 7:34pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/8 "2020-04-30T19:34:36Z")

</div>

> [@jfmengels](#):
>
> The “safe unsafe” pattern just makes things simpler when you know things will be correct.

Right. That is the annoying case isn’t it? just want to do something very simple that you know is correct yet its type is `Maybe` (or `Result`). 👍

---

<div class="post-metadata">

**Author:** ![ceddlyburge](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ceddlyburge/32/2316_2.png) [@ceddlyburge](https://discourse.elm-lang.org/u/ceddlyburge)\
**Post date:** [May 3, 2020, 1:45pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/9 "2020-05-03T13:45:25Z")

</div>

Just read the blog post, this is great 🙂

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [May 13, 2020, 1:45pm UTC](https://discourse.elm-lang.org/t/safe-unsafe-operations-in-elm/5659/10 "2020-05-13T13:45:26Z")

</div>

Closed on May 13, 2020, 1:45pm UTC

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
