diff --git a/changelog.md b/changelog.md index 42d851590926b..4e17ebd333fa7 100644 --- a/changelog.md +++ b/changelog.md @@ -61,7 +61,7 @@ - The options module has been mostly rewritten. Most things should work, but it's no longer possible to compare two ``none`` options. Use ``isNone`` - instead. + instead. The comparator `==` is also gone, use `==?` instead. #### Breaking changes in the compiler diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 98589de2ad3be..df8ea8e3483f7 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -28,12 +28,16 @@ ## option returns an option. ## ## Comparing -## Comparing one option to another like ``some(100) == some(50)`` returns an +## Because of the way Nim treats comparators options uses special names to +## compare values. Every comparator is post-fixed with a question mark. So the +## equality operator becomes ``==?``, less than or equal to becomes ``<=?`` +## and so on. This is also done to help alleviate some of the confusion. +## Comparing one option to another like ``some(100) ==? some(50)`` returns an ## option. In this case they are not equal, so they return a ``none``. Note ## however that it's not possible to compare two ``none`` values like this -## ``none(int) == none(int)`` as it returns a ``none``. In the case that a +## ``none(int) ==? none(int)`` as it returns a ``none``. In the case that a ## comparator passes, the *first* option is returned so -## ``some(100) < some(200)`` returns ``some(100)``. +## ``some(100) = 5) <= 20) == x +## assert ((x >=? some(5)) <=? some(20)) == x ## # This only returns some if x is in the range 5..20 -## # Note that since Nim currently rewrites >= to a <= statement with flipped -## # arguments this currently doesn't work as it returns some(5). ## ## Options can also be used for conditional chaining. Let's use the ``find`` ## procedure we defined above: @@ -186,10 +172,11 @@ ## also be used in if statements: ## ## .. code-block:: nim -## if "hello world".find('w').?min(4) <= 2: +## if ("hello world".find('w').?min(4) <=? some(2)).isSome: ## echo "Never run" # the first statement returns a none option, which when ## # compared to 2 returns another none option. This none option is then -## # evaluated to false. In this case min is still never run. +## # obviously not a some. Note that in this case it would be better to use +## # a `match`. import typetraits import macros @@ -267,10 +254,10 @@ proc get*[T](self: Option[T], otherwise: T): T = otherwise template either*(self, otherwise: untyped): untyped = - ## Wrapper around get with a default, for use as ``either(x, 20)``, if ``x`` - ## is a ``none`` then it will return ``20``, otherwise it will return the - ## value of ``x``. - get(self, otherwise) + ## Similar in function to get, but if ``otherwise`` is a procedure it will not + ## be evaluated if ``self`` is a ``some``. This means that ``otherwise`` can + ## have side effects. + if self.isSome: self.val else: otherwise proc map*[T](self: Option[T], callback: proc (input: T)) = ## Applies a callback to the value in this Option @@ -487,27 +474,29 @@ proc optCmp*[T](self: Option[T], value: Option[T], if self.isSome and value.isSome and cmp(self.val, value.val): return self -template `==`*[T](self: Option[T], value: Option[T]): Option[T] = +proc `==`*[T](self: Option[T], value: Option[T]): bool {.error.} = discard + +template `==?`*[T](self: Option[T], value: Option[T]): Option[T] = ## Wrapper for optCmp with ``==`` as the comparator optCmp(self, value, proc (val1, val2: T): bool = val1 == val2) -template `not`*[T](self: Option[T]): Option[T] = - ## Not always returns a ``none`` as a ``none`` can't implicitly get a value - none[T]() +template `!=?`*[T](self: Option[T], value: Option[T]): Option[T] = + ## Wrapper for optCmp with ``==`` as the comparator + optCmp(self, value, proc (val1, val2: T): bool = val1 != val2) -template `<=`*[T](self: Option[T], value: Option[T]): Option[T] = +template `<=?`*[T](self: Option[T], value: Option[T]): Option[T] = ## Wrapper for optCmp with ``<=`` as the comparator optCmp(self, value, proc (val1, val2: T): bool = val1 <= val2) -template `>=`*[T](self: Option[T], value: Option[T]): Option[T] = +template `>=?`*[T](self: Option[T], value: Option[T]): Option[T] = ## Wrapper for optCmp with ``>=`` as the comparator optCmp(self, value, proc (val1, val2: T): bool = val1 >= val2) -template `>`*[T](self: Option[T], value: Option[T]): Option[T] = +template `>?`*[T](self: Option[T], value: Option[T]): Option[T] = ## Wrapper for optCmp with ``>`` as the comparator optCmp(self, value, proc (val1, val2: T): bool = val1 > val2) -template `<`*[T](self: Option[T], value: Option[T]): Option[T] = +template `