Why 0 (zero) is truthy?

Insanity and genius lay close by each other. Until now I’ve actually never heard anyone complain that the semantics used in Ruby and Crystal would be harmful. Sure, maybe people have argued for alternatives. But just because they believe them to be better, not because there’s a need to fix erroneous behaviour.

In fact, I think the enhanced semantics of truthiness evaluation in Crystal is a very great feature. If you have a nilable type, that becomes non-nilable in an if var branch.

That’s completely impossible if the conditional expression was required to be of type Bool.

So I don’t think that will change. It’s a great unique feature of Crystal. And it’s well integrated into the core of the language.

7 Likes

Choices. Crystal could fix that “behavior” from Ruby in a simple step as I mentioned. 0 = true is so ugly for my eyes, from the discrete math point, that just this “feature” looks like a aberration I can’t stand. I do understand the “but we are used to it and don’t want to make it work as expected by everyone else outside the Ruby world” view point. :D

I thought about “0” being read from user input, converted to an int, and acting upon it. Then if value would not hold for zero, and nothing would be done.

In the case of the delay example, the delay would be skipped instead of delaying the program by… zero! So in the end it’s the same effect. Same if the program was something like:

initial = 10
puts "How much do you want to add?"
value = readline.to_i
if value
  initial += value
end

In that case the branch won’t hold for zero, but it’s fine! We don’t need to add anything in either case.

So for zero it kind of makes sense that it would be falsey.

I’m actually thinking it would also make sense for an empty collection that you want to process, because processing an empty collection or not doing any processing is equivalent.

That said, I’m sure there are other scenarios where you’d like to make such difference. In the delay example, maybe showing the user what’s in the config file, showing “You have a delay of 0” or “You didn’t specify a delay” and not being able to distinguish the two could be confusing.

initial = 10
puts "How much do you want to add?"
value = readline.strip
if value.length > 0
  initial += value.to_i
end

Maybe we can make a list to see in which languages this is true?

Languages I know where you can do if 0 and that doesn’t hold:

  • C, C++, D, Python, Javascript

Languages I know where if 0 does hold. Here I include languages where if 0 is also a compile-time error, so you actually can’t do this:

  • Ruby
  • Crystal
  • Java
  • Kotlin
  • C#
  • Nim
  • Rust
  • Go
  • Haskell
  • Swift

My opinion: just seeing that Javascript is in that list makes me think that it’s probably a good idea not to do that :-)

8 Likes

I think I’m not understanding you. I’m all for treating a possible dev fail as wrongly using a number var instead of a boolean value as a compiler error, but if it is accepted or cast as boolean, 0 = is false; as taught in discrete math, digital electronics engineering, etc and reflected in many languages as most you listed above.
Forget javascript, that’s another level of aberration.

Oh, I understand now. But, as @straight-shoota said, there’s no way we can change it. The language is already used by many, and this is a fundamental concept, both in Crystal and Ruby, and it’s actually quite powerful.

As I said. I understand the “we are used to it, it would be a radical change”.

But… Many languages evolve, derivatives as Crystal, that drinks from the Ruby fountains, could introduce a new, better behavior, but breaking old code changes. And for that, new and well studied and designed behaviors would be the default, and a compiler option like --ruby-compatibility should be cast for old deprecated code that should be rewritten in the future using the more modern, safer and more standardized approaches a “new future compiler” could demand.

I don’t think there is anything to “fix” for Ruby’s behaviour. It’s sound and safe. Of course there are different options on the spectrum, but I don’t think any of them is necessarily wrong. It’s not a question of habit, but what makes sense for the semantics of a language.

Crystal has already evolved the concept from Ruby by adapting if var to apply type restrictions. That drinks from the Ruby fountain but is new and better in the context of Crystal’s type system.
I’m not sure how well studied and designed this behaviour’s inception was, but the result is very much consistent, modern and safe. It’s well documented and an idiomatic feature much appreciated by Crystal developers.

10 Likes

@Rick.A say we make the change and now conditionals only allow bool values. That means nil is not anymore falsey and as such we need to change all of the

a || b

into

if a.is_nil?
  b
else
  a
end

or

a? a : b

Quite frankly, I prefer the way we do it now. Yes, you need to get used to it if you don’t come from a similar language(*), but the same happens with several good features in other languages.

(*) Let me add Lua to the list of lanugages with falsey elements like Ruby and Crystal.

6 Likes

There’s nothing to “fix”. It’s plainly obvious that you’re presenting your own preference as if it were objectively better (it’s not) and as if you hold the majority opinion (you don’t). The Crystal core team is being far more respectful to you than you are to them in this thread, so maybe return that respect and stop acting like a petulant child.

If treating 0 as falsy really is an “aberration” that you “can’t stand”, then by all means find another language. You’re not going to get your way by throwing thinly veiled insults at the people responsible for the language when they’ve already told you it’s not going to change.

7 Likes

I forgot to thank all of you for the detailed explanations :blush:

Thanks @straight-shoota , @jgaskins , @asterite , @beta-ziliani and all others!

My question was only to understand the technical aspects behind the decision and everything is clear now (I didn’t mean to cause controversy). It’s perfectly fine, reasonable and understandable.

I am learning a lot with Crystal :blush:

2 Likes

Dear person, I’m not disrespectful venting my opinion and presenting valid and proven arguments and facts to add to a discussion ABOUT LANGUAGE DESIGN options, nothing towards any person. YOU (for the first time its now personal), disrespectfully, is not adding anything to the conversation with your silly Ad Hominem.
I already rested my case after the second defense of the current design by Johannes, I still don’t like the current design, but that’s how it will end. No need to extend this conversation. I can be convinced about things in 2 ways: Way-1: Thing x is better because y, and Way-2: Thing x is this way by design, we are aware about the flaws, but we also decided to carry on this way because the community embraced it as is and won’t change it.
I was convinced that argumentation was over by the way-2 many posts ago as I said.
That’s my final answer to this topic unless another ad hominem will be cast again. ;)

1 Like

Yes. That could be one way for a safer code. But for a “more Ruby” way, as I said, Crystal could add relaxation compiler option as I mentioned –ruby-compatibility, or a compiler directive in code, allowing an unsafer “shortcuted” coding as many users used to Ruby probably will prefer.

I needed to reply this due to respect to the community and a direct request for an answer.

My last one here too, just to say that you’re not getting an important point in the message: many of us love it this way. Ruby or not Ruby. So this fall into your Way-1, not Way-2.

3 Likes

I felt like reading an internet forum in early 2000’s in this thread :smile:

3 Likes

Way-2 embraces your exposed argument. Way-1 would win if I were convinced that unsafe shortcuts as default would be the best approach for a language design, but I’m not. So as the “I can be convinced about things in 2 ways” is centered on me, I can say that my arguments were defeated by Way-2, that also carries your pointed view, “the community likes this way and we won’t intend to change it”. Again, I needed to reply again due to direct disagreement of a fact centered on me, kind of modifying my opinions in place of myself (unintentionally, I would say), not to add anything new, or lack of respect about the fantastic work being done, people involved, or whatever. The choices were made, I respect them, the team, and the community.

Do you want truthiness determined by type or by value? If by value it should be converted to a boolean type, imo. This is why I like the zero is truthy paradigm. Should an empty string be falsy?

1 Like

The truthiness of Bool itself is obviously determined by value, and so are instances of Pointer; null pointers are falsey, other pointers are truthy. Pointer(Void).new(0) is falsey.

In this aspect, truthiness in Ruby is completely type-based, since it has FalseClass and no pointers.

4 Likes

I think null is an acceptable falsy value as it might be thought of as the absence of a value of the given type rather than a value of that type.