Can we let getter? setter? property? macro always return a non-nil bool value?

Here use getter for example, official doc said:


getter?

Defines query getter methods for each of the given arguments.

Writing:

class Person
  getter? happy
end

Is the same as writing:

class Person
  def happy?
    @happy
  end
end

AFAIK, is not overloadable in Crystal, is it possible make getter? macro generated method always non-nil ?

e.g, instead above, this macro generate a method like following:

class Person
  def happy?
    !!@happy
   end
end

Although, nil is falsey in Crystal, but, i prefer when i saw a method suffix with a ?, i expect it should always return really boolean value.

I’m pretty sure I remember seeing an issue/PR comment about this but can’t seem to find it now…

1 Like

Why do you need this? What you are asking for seems to fall under the realm of “custom behavior” which is something that can already be done in the way you describe, just with 2 extra lines. Generally the ? at the end of a method in ruby means “truthy value returned”, which generally hints it will either be either (true or false) or (some object or nil), exclusively returning one set or the other per method, but not the same for ALL methods.

a = [1,2,3,4]
puts a[3]?.class #=> Int32
puts a[9]?.class #=> Nil

There are lots of instances of this exact paradigm in Crystal and Ruby. Since Crystal and Ruby both support a conditional expression structure that supports using truthy values, this is preferable to making something that ONLY will return true or false given a context.

a = [1,2,3,4]
puts "I run" if a[3]? 
puts "I don't" if a[9]?
1 Like

I believe the issue in question is Can't define a default value with getter! · Issue #7968 · crystal-lang/crystal · GitHub (the referenced issues are also a good read). Asterite’s comment summarises the issue:

But for me it’s misleading. property! means if it’s not set then it will raise. If property! allows a default value then it will never raise. And at that point you better use property. Because if a user reads property! in the source code they will think “This can raise” when in fact it’ll never happen.

2 Likes

I’m fairly certain this isn’t the issue he’s having, he wants either getter? to always provide a non-nil value (breaking truthy valuation for ? methods), or a version of getter? that provides a true-false value only. The ! he’s talking about is the unary negative which can’t be overwritten in any way since it’s a psuedomethod.

I found it. It’s Autocasting from `Bool?` to `Bool` · Issue #12704 · crystal-lang/crystal · GitHub.

1 Like

What is the use-case for this? I get why you might want to collapse the union type since it might be “more correct” on the backend but at the same time the only time I can think of where we might need something like this is using []? on a collection of Bool, but the idea behind that method is to return the object or nil if it doesn’t exist so knowing if it’s nil or not is an enhancement on the information we receive, but doesn’t change the behavior into something that has three different states in a conditional context. I would imagine this would mess with ORM stuff where someone tries to store a Bool but the ORM returns Bool? since the Bool might not exist.

I change my mind, consider my proposal is not a big deal anyway.

because a nilable property, e.g.

property foo : Bool? = nil

I think it can always be change to follow code safety, now foo is non-nil.

property? foo : Bool = false

Of course, you should change self.foo to self.foo? where the foo is used.

1 Like

Okay, fine, I take back my words, change a type from nilable to non-nil not safe, and it’s often impossible in many situation, and broken application.