Skip to content

Forbid division operations that can result in unexpected values or runtime exceptions

License

Notifications You must be signed in to change notification settings

VKFisher/elm-review-no-unsafe-division

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

elm-review-no-unsafe-division

This package provides an elm-review rule that forbids most usages of the native division functions and operators (/, //, modBy and remainderBy), while still allowing the trivially correct cases where the divisor is a non-zero literal.

Rationale

When the divisor is 0, the native division functions and operators produce results that can lead to undesired behavior.

The / operator can produce values like NaN and Infinity

0 / 0 -> NaN : Float
2 / 0 -> Infinity : Float
-2 / 0 -> -Infinity : Float

The // operator produces 0, which is a somewhat arbitrary result that might lead to domain logic errors

2 // 0 -> 0 : Int

The modBy function throws a runtime exception

modBy 0 2 -> "Error: Cannot perform mod 0. Division by zero error."

And the remainderBy function produces a NaN with type Int, of all things

remainderBy 0 2 -> NaN : Int

Using safe alternatives from the Basics.Extra package forces us to handle these cases explicitly, which reduces the possibility of errors.

Configuration

module ReviewConfig exposing (config)

import NoUnsafeDivision
import Review.Rule exposing (Rule)

config : List Rule
config =
    [ NoUnsafeDivision.rule
    ]

Behavior

Rejects

Division operations where the divisor is a zero literal

a : Float
a = 1 / 0

b : Float
b = (/) 1 0

c : Int
c = 1 // 0

d : Int
d = (//) 1 0

e : Int
e = modBy 0 1

f : Int
e = remainderBy 0 1

Division operations where the divisor is a non-literal value

a : Float
a = 1 / x

b : Float
b = (/) 1 x

c : Int
c = 1 // y

d : Int
d = (//) 1 y

e : Int
e = modBy y 1

f : Int
f = remainderBy y 1

Partial applications of modBy and remainderBy where the divisor is a zero literal or a non-literal value

a : Int -> Int
a = modBy 0

b : Int -> Int
b = remainderBy 0

c : Int -> Int
c = modBy x

d : Int -> Int
d = remainderBy x

Partial applications of (/) and (//) in prefix form

a : Float -> Float
a = (/) 1

b : Int -> Int
b = (//) 1

c : Float -> Float
c = (/) x

d : Int -> Int
d = (//) y

Usages without application

a : Float -> Float -> Float
a = (/)

b : Int -> Int -> Int
b = remainderBy

c : a -> Int -> Int -> Int
c = always modBy

Accepts

Division operations where the divisor is a non-zero literal

a : Float
a = 1 / 0.3

b : Float
b = (/) 1 1.6

c : Int
c = 1 // 3

d : Int
d = (//) 1 2

e : Int
e = modBy 4 1

f : Int
e = remainderBy 2 1

Partial applications of modBy and remainderBy where the divisor is a non-zero literal

a : Int -> Int
a = modBy 3

b : Int -> Int
b = remainderBy 2

Thanks

@jfmengels - for the amazing tool that is elm-review

@VladimirLogachev - for mentorship and advice

About

Forbid division operations that can result in unexpected values or runtime exceptions

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages