Issue #13820 has been updated by williamn (William Newbery).


shevegen (Robert A. Heiler) wrote:
> By the way, did you actually propose an actual syntax? The two '?'?

Not really personally set on any given syntax, just `??` and `//` are familiar to me from other programming. Although actually for `??` specifically, I guess the fact Ruby uses it in both methods and ternary causes a conflict rather than just one or the other (`x.nil?? "was nil" : "not nil"`). I wouldn't know if the parser can figure that out or not.

But more the concept that any specific syntax.

> I myself use nil primarily as means to indicate a default, "non-set" value. The
> moment it is set to a boolean, be it false or true, is for me an indication
> that it has been "upgraded" (or set by a user on the commandline etc...)

Hmm, maybe I didn't explain clearly. That is pretty much the pattern I come across repeatedly in Ruby code, and it fails for the `false` value because false is not "upgraded" when people do "x || my_default".

```ruby
"a truthy value" || foo("something else") # The operator also short circuits so the method `foo` will never even get called
false || foo("something else") # Left side is falsy, so evaluate the right side, but is often not the intent
nil || foo("something else") # Nil is also falsy, so evaluate the right side

"a truthy value" ?? foo("something else") # String is true and not nil, so nothing changes here
false ?? foo("something else") # This changes. Left side is not nil, so the right side is never evaluated
nil ?? foo("something else") # Like with `||`, left side is nil so evaluate the right side

# so this "does the right thing", as far as my maybe not great example goes
https = opts[:https] ?? true
```




phluid61 (Matthew Kerwin) wrote:
> In perl I find `$x // $y` useful vs `$x || $y` because sometimes you want to accept `""` and `0` as values.
But not `false`?



While `hash.fetch` is nice, I still see `||` used a lot, in places that maybe wont convert so nice. Also it wont short circuit, in the event the default is not trivial (e.g. with say active record stuff, its easy to have something that goes to the DB without really thinking about it).

```ruby
opts[:foo] || @foo_config || App.config.foo # Occasionally I see 3 or more chained together
hash[:foo] ||= fetch_foo # fetch doesn't assign the value like this does, and it wont short circuit `fetch_foo`
@lazy ||= calc_lazy # Sometimes used with non-hashes
```

But yes your right, they can all be done other ways, and maybe the better answer is to discourage `||` in the first place, but I struggled finding ones as tidy to suggest instead.

```ruby
opts.fetch(:foo, !@foo_config.nil? @foo_config : App.config.foo)
hash[:foo] = fetch_foo if !hash.has_key?(:foo)

@lazy = calc_lazy if @lazy.nil?
@lazy # needed because get nil if the if condition is false

if @lazy.nil?
  @lazy = calc_lazy
end
@lazy
```


----------------------------------------
Feature #13820: Add a nill coalescing operator
https://bugs.ruby-lang.org/issues/13820#change-66209

* Author: williamn (William Newbery)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
It would be nice if Ruby had an operator that only considered `nil` as false, like the null coalescing operators or "Logical Defined-Or operator" (Perl) found in some other languages. Ive seen things like `//` and `//=`m `??` and `??=`, or `?:` used for this.

This would work like `||` and `||=` for short circuiting etc. except that only `nil` is considered a false condition.

While Ruby considers only "false" and "nil" as false, with everything else true ("", [], {}, etc.) I still find occasionally people trip up when using logical or, `||` and `||=` when the value may be false.


```ruby
a = 0     || 55 # = 0 Ruby already considers 0, "", etc. as true (oter languages do differ a lot here)
a = 0     ?? 55 # = 0 So no change here
a = nil   || 55 # = 55, nil is false so right side is evaulated.
a = nil   ?? 55 # = 55, again no change
a = false || 55 # = 55, however false is false for logical or
a = false ?? 55 # = false, but its still a non-nil value
```


For example when doing things like:

```ruby
def lazy
  @lazy ||= compute_this
end


def fetch(id, **opts)
  host  = opts[:host] || default_host
  https = opts[:https] || true
  port  = opts[:port] || (https ? 443 : 80)
  ...
```

Normally the intention is to use a default value or compute an action if no value is provided, which if the value may be false then requires special handling, or sometimes is missed and results in a bug.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>