We copied the nil?
method from Ruby. People coming from Ruby use it and find out it has unexpected behaviour in Crystal. For example:
x = some_nilable_value
if !x.nil?
x.foo # Error, x might be nil
end
The problem is that nil?
doesn't do what we call "type filtering": the compiler doesn't know x
won't be nil
inside the if
. An alternative to the above is this:
x = some_nilable_value
if x
x.foo # OK
end
The above works and is semantically equivalent as long as x
's type doesn't include Bool. In that case, one can do:
x = some_nilable_value
unless x.is_a?(Nil)
x.foo # OK
end
(or if !x.is_a?(Nil)
once and if we implement #1196)
Alternatively, we can make the compiler have .nil?
as equivalent to .is_a?(Nil)
and disallow defining this method, but, as always, I'd like to keep the language simple.
What do you think?
+1 on removing it. I use if x
, or if x = method_call(...)
form. Haven't
used #nil?
so far.
Best Regards,
Oleksii Fedorov,
Programmer,
Software Craftsman (http://manifesto.softwarecraftsmanship.org/),
TDD, Pair-Programming, Microservices, Good Architecture, Ruby, Clojure, Go,
a bit of Web Frontend and more,
Follower of Software Engineering Code of Ethics (
http://www.acm.org/about/se-code),
+49 15757 486 476
On Tue, Mar 29, 2016 at 7:05 PM, Ary Borenszweig [email protected]
wrote:
We copied the nil? method from Ruby. People coming from Ruby use it and
find out it has unexpected behaviour in Crystal. For example:x = some_nilable_valueif !x.nil?
x.foo # Error, x might be nilendThe problem is that nil? doesn't do what we call "type filtering": the
compiler doesn't know x won't be nil inside the if. An alternative to the
above is this:x = some_nilable_valueif x
x.foo # OKendThe above works and is semantically equivalent as long as x's type
doesn't include Bool. In that case, one can do:x = some_nilable_valueunless x.is_a?(Nil)
x.foo # OKend(or if !x.is_a?(Nil) once and if we implement #1196
https://github.com/crystal-lang/crystal/issues/1196)Alternatively, we can make the compiler have .nil? as equivalent to
.is_a?(Nil) and disallow defining this method, but, as always, I'd like
to keep the language simple.What do you think?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
https://github.com/crystal-lang/crystal/issues/2387
I would prefer to keep the .nil?
and I see a bonus to translate it to .is_a?(Nil)
in order to gain the type filtering. Nil is special after all.
I actually prefer to be explicit in if
regarding not nil check. If I don't use .is_a?(Nil)
is because it's too verbose compared to .nil?
.
But I know in my head this goes all way back to avoiding anything but booleans in conditions. But still, I like to be able to be explicit regarding .nil?
@bcardiff The point about nil
being special is true, so maybe having nil?
as a short form of is_a?(Nil)
is good. After all the compiler knows about nil
, for example in if
and while
, and the standard library has not_nil!
and so on. And people coming from Ruby won't be surprised... though their code might result being a bit more verbose than current Crystal code (just doing if x
).
+1 for nil?
=> is_a?(Nil)
Sometimes, _slight_, verbosity is good to clarify intent :-)
I feel like testing for x
being true vs nil?
are not exactly equivalent.
This is where rspec gets its truthy
vs falsey
semantics which are very useful. I found this writeup, which was helpful in understanding the utility. https://gist.github.com/jfarmer/2647362
Based on the comments above and some discussions we had with @waj and @bcardiff we decided that the best thing to do is to make nil?
be the same as is_a?(Nil)
. The reasons are:
Nil
is already "special": the compiler knows about it and many language constructs (if
, while
, &&
) do type filtering around it. It makes sense to make nil?
have a similar behaviour.nil?
is used a lot by Ruby programmers. It's better if nil?
works and does type filtering as one would expect.if x.nil?
and unless x
have a different meaning. The later passes if x
is false
, so it makes sense to have a (short) way to check for nil-ness (is_a?(Nil)
is much longer and involves parentheses).I noticed there was Pointer#nil?
which meant "returns true if the pointer's address is zero". I removed that method because it was misleading. Even though a null pointer is falsey, it's not nil
(it's type is not Nil
). So if you used Pointer#nil?
you have to use now Pointer#null?
. The bad thing is that it's not easy to spot where Pointer#nil?
is used, so you'll have to go one by one and replace them... but this should only affect shards that deal with pointers (most probably C bindings). I prefer to break this now and have nil?
be consistent with its meaning. (I'll write a big note about this in the next release notes/changelog)
I forgot to say, in the next release I'll also make the compiler give an error if you try to define a method named nil?
, is_a?
, responds_to?
or !
. I can't do that right now because nil?
is still defined in the current compiler.
Should the to_s
of and ASTNode or the formatter prefer to use .nil?
syntax over .is_a?(Nil)
?
@bcardiff We could probably make is_a?(Nil)
and nil?
appear as nil?
. In any case if we don't have two different nodes for nil?
and is_a?(Nil)
the to_s
representation will have to always be one of those. And they both work in the same way, so I think it doesn't matter much how we show it.
Most helpful comment
I would prefer to keep the
.nil?
and I see a bonus to translate it to.is_a?(Nil)
in order to gain the type filtering. Nil is special after all.I actually prefer to be explicit in
if
regarding not nil check. If I don't use.is_a?(Nil)
is because it's too verbose compared to.nil?
.But I know in my head this goes all way back to avoiding anything but booleans in conditions. But still, I like to be able to be explicit regarding
.nil?