[ruby-core:117077] [Ruby master Feature#20326] Add an `undefined` for use as a default argument.
From:
"zverok (Victor Shepelev) via ruby-core" <ruby-core@...>
Date:
2024-03-07 17:38:34 UTC
List:
ruby-core #117077
Issue #20326 has been updated by zverok (Victor Shepelev).
> Personally, I don't like an API that distinguishes between "nil is passed" and "nothing is passed".
Unfortunately, such APIs are sometimes unavoidable, especially in implementing various generic algorithms (and not business logic).
Take, for example, `Hash#fetch`. `fetch('key')` and `fetch('key', nil)` have different meanings. If such an API is to be implemented in Ruby, there are several options:
* use the "value provided" guard like discussed in this ticket (`default = UNDEFINED` or `default = (default_not_set = true))`;
* use `(*args)` and then check real arguments provided in the method body (by `.count` or some form of pattern matching).
C implementations of the core methods do this constantly (either argument count check, or pattern matching-like `rb_scan_args`), demonstrating the necessity. Maybe having the default way to say "argument was not provided" will help to define cleaner APIs.
Another common case is search algorithms, where the initial value for the `found` local variable is set to some sentinel value and checked after the algorithm (while having `found == nil` might be a legitimate case of "value is found, and it is `nil`"). Alternative, is, again, to have an additional boolean `is_found = false` and when the answer is found, set _two_ local vars.
For these reasons, I think I saw a lot of codebases (including some written by me and my colleagues) going with some kind of `UNDEFINED`/`NOT_SET` constant, which feels like a kind-of hack, but still clearer than alternatives.
That being said, I am not sure I am in favor of having `nil`/`undefined` distinction in Ruby, and never proposed it myself (while considering it several times).
----------------------------------------
Feature #20326: Add an `undefined` for use as a default argument.
https://bugs.ruby-lang.org/issues/20326#change-107151
* Author: shan (Shannon Skipper)
* Status: Feedback
----------------------------------------
Variations around `UNDEFINED = Object.new` are a fairly common pattern to see used as default arguments to distinguish between `nil` and no argument provided. For example, a Ruby implementation of Array#count might look something like:
``` ruby
class Array
UNDEFINED = Object.new
def UNDEFINED.inspect = 'UNDEFINED'
UNDEFINED.freeze
def count(item = UNDEFINED)
if item == UNDEFINED
# ...
end
end
end
```
I'd like to propose adding an `undefined` module function method on Kernel to remove the boilerplate for this fairly common use case. An `__undefined__` method or `__UNDEFINED__` keyword would be alternatives to `undefined`. An `undefined?` helper would also be an optional nicety:
``` ruby
class Array
def count(item = undefined)
if item.undefined?
# ...
end
end
end
```
A Ruby implementation might look like:
``` ruby
module Kernel
UNDEFINED = Object.new
def UNDEFINED.inspect = -'undefined'
UNDEFINED.freeze
private_constant :UNDEFINED
def undefined? = self == UNDEFINED
module_function
def undefined = UNDEFINED
end
```
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/