
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/