this post was submitted on 08 Dec 2023
619 points (96.4% liked)

Programmer Humor

31793 readers
27 users here now

Post funny things about programming here! (Or just rant about your favourite programming language.)

Rules:

founded 5 years ago
MODERATORS
 
you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 49 points 8 months ago* (last edited 8 months ago) (4 children)

Ruby:

a || b

(no return as last line is returned implicitly, no semicolon)

EDIT: As pointed out in the comments, this is not strictly equivalent, as it will return b if a is false as well as if it's nil (these are the only two falsy values in Ruby).

[–] [email protected] 23 points 8 months ago (3 children)

Python:

return a or b

i like it because it reads like a sentence so it somewhat makes sense

and you can make it more comprehensive if you want to:

return a if a is not None else b

[–] [email protected] 15 points 8 months ago* (last edited 8 months ago)

This diverges from the OP code snippets if a has the value False.

[–] [email protected] 7 points 8 months ago (2 children)

I personally dislike this because when you read "or" you expect some boolean result not a random object :/

[–] [email protected] 5 points 8 months ago

there's always the second option for you

[–] gravitas_deficiency 1 points 8 months ago* (last edited 8 months ago)

In python: Not necessarily.

If you have an arg whose default is something you’re not supposed to bind as a default value in the function sig (e.g. the result of a function call), make it an Optional, default it to None, and then on the first line just do some_arg = some_arg or interesting_function()

[–] [email protected] 1 points 8 months ago (1 children)

For newer python people, they see return a or b and typically think it returns a boolean if either is True. Nope. Returns a if a is truthy and then checks if b is truthy. If neither are truthy, it returns b.

[–] [email protected] 7 points 8 months ago* (last edited 8 months ago) (1 children)

Returns a if a is truthy and then checks if b is truthy. If neither are truthy, it returns b.

Not quite. If a is not truthy, then the expression a or b will always return b.

So, there is never any reason to check the truthiness of b.

you can paste this in your repl to confirm it does not.

class C:
 def __repr__(self): return [k for k, v in globals().items() if v is self][0]
 def __bool__(self):
  print(f"{self}.__bool__() was called")
  return False

a, b = C(), C()
print(f"result: {a or b}")

spoiler output

a.__bool__() was called
result: b

:::

[–] [email protected] 3 points 8 months ago

Ah, good catch.

[–] [email protected] 13 points 8 months ago (1 children)

This doesn't work for booleans because false is not null but also not truthy. One of things I hate about ruby is that it doesn't have a native null coalescing operator.

[–] [email protected] 1 points 8 months ago

Yeah, you're quite correct, it's not exactly equivalent, I just went on auto-pilot because it's used so much for that purpose 🤖

It's much closer to being a true null-coalescing operator than 'OR' operators in other languages though, because there's only two values that are falsy in Ruby: nil and false. Some other languages treat 0 and "" (and no doubt other things), as falsy. So this is probably the reason Ruby has never added a true null-coalescing operator, there's just much fewer cases where there's a difference.

It's going to drive me mad now I've seen it, though 😆 That's usually the case with language features, though, you don't know what you're missing until you see it in some other language!

[–] [email protected] 7 points 8 months ago* (last edited 8 months ago)

Perl has both $a || $b and $a // $b.

The || version is older and has the value of $b if $a is any false value including undef (which is pretty much Perl's null/nil).

The // version has the value of $b iff $a is undef. Other "false" values carry through.

Ruby took both "no return required" and "no final semicolon required" from Perl (if not a few other things), I think, but it seems that // was Perl later borrowing Ruby's || semantics. Interesting.

i.e. 0 || 1 is 1 in Perl but 0 in Ruby. Perl can 0 // 1 instead if the 0, which is a defined value, needs to pass through.

[–] [email protected] 6 points 8 months ago (1 children)
[–] [email protected] 17 points 8 months ago* (last edited 8 months ago) (1 children)

Not strictly equivalent, since || tests for truthiness, not just null.

[–] [email protected] -1 points 8 months ago (1 children)

That's fair, but it's close enough that it functions identically

[–] [email protected] 4 points 8 months ago

Only for the null case. For other cases it doesn't function identically, since it also treats "", 0 and undefined the same as null.