The Crystal Programming Language Forum


Versus doing things like (which is littered all through my code)

my_var = user_defined_array
my_var = ["default", "array"] if my_var.nil? || my_var.try(&.empty?)
my_var = my_var.not_nil!

The same use case as String:

But where are you using this? Where are the values coming from? Is it a web form submission? JSON? A config file?

NoSQL databases storing JSON configurations mainly, parsing binary network protocols, also web front-ends (these are pretty common input interfaces these days).
i.e. as an example network protocol

Right now it’s writing an application that interacts with Google Calendar API - so lots of JSON
It feels like something that comes up once a day and after looking at the link @jhass shared, the number of pull requests made, it’s probably not just me.

The problem is not one of usecases but one of semantic. What kind of values are considered “present” is quite domain specific and doesn’t have to be the same across domains. In that regard String#presence is already a big stretch for stdlib. I feel it okay pretty much only because it’s not defined for other types but Nil. We can claim a definition within the domain of a “string” rather than the domain of what the string represents in the user code. But this distinction falls apart when we start to add things like Array#presence. What’s the common domain of a string and an array, what’s the common reasoning between their presence definitions?

My link served to link the existing discussions, please don’t just ignore them and start from scratch on the topic.


Seems simple to me.
Something has presence if

  1. it is not nil
  2. it is not empty or blank (blank being a superset of empty)

If you think of an array in C, it’s just a pointer to memory. If there is nothing in the array, size zero, there is nothing present in memory for that array. In C land you literally want this to be null pointer.

A hash has similar semantics to an array when empty - there is nothing present in the hash.

An integer is present no matter its value, it exists and is present as an integer.

So from this I would argue if a thing is not empty then it has something to present, hence presence.
I would also say that things don’t have to be semantically perfect to be useful. A save icon is a floppy disk, no semantic value to a large group of people, but still a useful button

The floppy icon actually made perfect sense when it was introduced, people just learned to associate a particular concept to it as the exisiting association started to become weaker. Introducing a concept with weak associations from the start is a whole different story.

You just delegated the ambiguity to “blank” in your definition. When is an object blank? Why is an all whitespace string blank but an array consisting of just nils not? Or if we follow your C analogy, why is an array of 0x20s not blank?

The answers to these questions are specific to the application domain and not the data structure domain. This is why in the Ruby world these methods continue to live in ActiveSupport, a collection of helpers for a web framework.

Similar to us, they’re open (but still undecided because performance is not a primary concern for Ruby, unlike Crystal) to a String#blank?: /


Strings are typically designed for human consumption. So a string with nothing visible to a human eye is blank to us if it has 1000 characters or none.

However Arrays are for computer consumption. So an array of nils, possibly represented by an array of 0’s in memory has meaning to a computer.

So semantically it makes perfect sense that a string of nothing has no presence but an array of 0’s is present. Ruby has the unfortunate situation of using strings for binary data storage whereas crystal has slices - so we can take this semantic differentiation in our stride.

Finally I point to the literal motto of crystal lang

I don’t see that being brought up as an objection in the Ruby issue tracker entries I linked about this topic, so maybe that’s not their reason for being hesitant about it? ;)

I agree with @jhass. Specially because coding a shard with blank?, present? and present is very easy, maybe just 50 lines of code. Then you can use it in your project, and if that semantic doesn’t fit your domain then you can define them in a different way.


I agree with the idea of making this a shard or even just adding it to your own app. I’ve found that counting an empty array/hash the same as nil is not a good general practice. IME it has always led to sloppy code, where treating the two as equivalent propagates outside the one layer of the app where that equivalence makes sense.


Also agree with @jhass and @jgaskins .
In particular, better avoiding the use of not_nil!, and even .as if possible.
@stakach In my opinion it is cleaner to do

unless my_var && !my_var.empty?
  my_var = ["default", "array"]

# Instead of
my_var = ["default", "array"] if my_var.nil? || my_var.try(&.empty?)
my_var = my_var.not_nil!

Already quite neat without #presence!

I would argue it is less readable. More lines of code, easier to make a mistake and for everyone who hasn’t seen your example has all the opportunities to introduce a less than ideal implementation.

unless my_var && !my_var.empty?
  my_var = ["default", "array"]


my_var = my_var.presence || ["default", "array"]

This may be a futile discussion but I still haven’t seen a very compelling argument not to introduce it.
The linked Ruby issues are mostly discussing Object#blank? whereas Object#presence as I defined it above seems simple enough to get one’s head around

Further, if the more complicated example above is super clear why don’t we use this pattern for strings?
It is more confusing to have a special case for String and nothing else - especially when a function of String is leaking into the implementation of Nil - I makes way more sense to have String and Nil special cases of Object

Although I’m used to Ruby’s presence I think I prefer to keep it in the String? realm only.

But something I think it might work at Object is a #nil_if (or something like that) that will, well, return nil if the block evaluates to true, and self otherwise.

That way patterns like the following can be allowed.

array_expr.nil_if(&.empty) || default_array

That way 0, [] or whatever value is wanted to be treated as blank can be definied per need explicitly.


I actually agree with this, but not for the reason you might think. :slightly_smiling_face:

Is array_expr.nil_if(&.empty?) the same as !array_expr.empty? (except false vs nil)?

Almost. Having Object#nil_if and Nil#nil_if is what will allow you to deal with nil and whatever value matches the block predicate in a neat way IMO.

1 Like

I personally don’t see a compelling reason to introduce it, and I think the burden of proof goes in that direction. Erring on the side of not adding something is much more maintainable than the other way around. I do agree that it seems weird to have this thing in only String that also leaks into Nil, but I still don’t think that’s a strong enough argument to implement it widely in the standard library.

My main hang-up with this is that it makes the code potentially (and barely) more readable for Ruby devs at the expense of readability for people who don’t have that background (like me). Your example,

my_var = my_var.presence || ["default", "array"]`

isn’t very clear to me. If this were introduced (and I hadn’t read this thread), the following inner monologue seems pretty likely to me: ‘“Presence”? What does that mean? That it’s “there”? Well, if it isn’t “there” already, wouldn’t it just be Nil? Why not just use #nil??’ Obviously, “this syntax doesn’t make perfect sense to me” isn’t the most persuasive argument, but my point is that a semantic that you’re used to isn’t necessarily one that most people will find intuitive if they don’t have your background.


I do think this would be very useful. If introduced would we want to remove or deprecate String | Nil#presence ?
Happy to make a pull request

array = ["default"] unless array || !array.empty?
array = ["default] if array.nil_if &.empty?

For me are quite similar. The goal is not always to have the shortest lines available. Here having a new method, extending the API for all objects, does not worth the few chars saved.

1 Like

I think it’s useful if we deprecated the use of String#presence
which would be adding a few chars to that case but providing a generic pattern moving forward

1 Like