Feature #12075
closedsome container#nonempty?
Added by naruse (Yui NARUSE) almost 9 years ago. Updated over 2 years ago.
Description
I sometimes write following code.
ary = some_metho_returns_nil_or_empty_container() # nil or "" or [] or {}
if ary && !ary.empty?
# some code
end
But the condition ary && !ary.empty?
is too long and complex.
Though Ruby 2.3 introduces &.
, but this can’t be written as ary&.empty?
.
One idea is add nonempty?
write as ary&.nonempty?
.
akr: nonempty?
is not good name because human is not good at handling
This discussion matches following core classes:
- String
- Array
- Hash
Updated by mrkn (Kenta Murata) almost 9 years ago
How about ary.include_something?
?
Updated by akr (Akira Tanaka) almost 9 years ago
How about "some?".
Updated by sawa (Tsuyoshi Sawada) almost 9 years ago
That is a use case for Rails' blank?
(or present?
).
class Object
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
end
unless ary.blank?
# some code
end
What about incorporating these methods from Rails?
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) almost 9 years ago
+1 for bringing blank? and present? to Ruby core. I often use (a || '').empty? checks for not having to depend on ActiveSupport directly in my Ruby code. I'd love to see them in Ruby core though.
Updated by shyouhei (Shyouhei Urabe) almost 9 years ago
No, the OP wants to detect things that are not empty. This is not what blank? means. Also note that blank? in ActiveSupport has different (far more Rails-centric) semantics than what is described in #3.
Updated by sawa (Tsuyoshi Sawada) almost 9 years ago
Shyouhei Urabe wrote:
No, the OP wants to detect things that are not empty. This is not what blank? means.
Yes, I meant that blank?
is the opposite of what OP wants. present?
is what the OP wants. I replaced if
in the original example with unless
, so it is the same (Or, to retain if
, present?
can be used).
ActiveSupport has different (far more Rails-centric) semantics than what is described in #3.
I see.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) almost 9 years ago
The implementation doesn't have to be the same as the one implemented by ActiveSupport. I think it would be fine to simply check for nil? and empty?. But I'd like to keep the names present? and blank? anyway.
Updated by shevegen (Robert A. Heiler) almost 9 years ago
Perhaps the name .contains? might be good?
Although, .include? sort of is more or less synonymous with .contains? so perhaps this is not a good choice either.
.nonempty? seems a bit long, .non_empty? would be even longer :)
.empty? is a very good name already, I am not sure if "! .empty?" has a good name, though ruby uses the keyword "not"
already. Could use .notempty? haha sorry, I have no good suggestion for a fitting name for negation either, but I am
totally fine with the idea and functionality of the proposal itself, it's a good one.
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
I have just learned that zsh(1) calls this concept being "full". http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
Updated by sawa (Tsuyoshi Sawada) over 8 years ago
What about introducing NilClass#empty?
:
nil.empty? # => true
The code in question can be written simply as:
unless ary.empty?
# some code
end
If the original proposal is going to be realized, then a new method would have to be added to NilClass
, String
, Array
, and Hash
, but my proposal makes use of the existing method empty?
, and needs to add to only NilClass
, keeping the change minimal.
Even if the original proposal is going to be realized, extending empty?
as above would make it the complete opposite of such method, and would introduce parallelism.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 8 years ago
I like this idea a lot, Tsuyoshi. I'm +1 for introducing nil.empty? as returning true.
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
First, along this line, we'll need negative forms for all predicate methods.
And I think nil.empty?
makes no sense.
Just an idea:
module Kernel
def not(*a)
not a.empty? ? self : __send__(*a)
end
end
ary = nil; ary&.not(:empty?) #=> nil
ary = []; ary&.not(:empty?) #=> false
ary = [nil]; ary&.not(:empty?) #=> true
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
Or
module Kernel
def !(*a)
a.empty? ? super() : !__send__(*a)
end
end
ary = nil; ary&.!:empty? #=> nil
ary = []; ary&.!:empty? #=> false
ary = [nil]; ary&.!:empty? #=> true
Updated by phluid61 (Matthew Kerwin) over 8 years ago
Nobuyoshi Nakada wrote:
First, along this line, we'll need negative forms for all predicate methods.
And I think
nil.empty?
makes no sense.Just an idea:
module Kernel def not(*a) not a.empty? ? self : __send__(*a) end end ary = nil; ary&.not(:empty?) #=> nil ary = []; ary&.not(:empty?) #=> false ary = [nil]; ary&.not(:empty?) #=> true
I like this proposal. I definitely prefer the word 'not' over the symbol '!', because ary&.!:empty?
has too much consecutive punctuation for my eyes.
Would there be value in extending it to accept a block?
module Kernel
def not(*a, &b)
not a.empty? ? self : __send__(*a, &b)
# or even:
#not a.empty? ? (b ? (yield self) : self) : __send__(*a, &b)
end
end
ary = []; ary&.not(:any?){|x|x>0} #=> true
ary = [1]; ary&.not(:any?){|x|x>0} #=> false
Updated by Eregon (Benoit Daloze) over 8 years ago
Nobuyoshi Nakada wrote:
https://github.com/ruby/ruby/compare/trunk...nobu:feature/12075-not
I like it!
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
- Description updated (diff)
Updated by naruse (Yui NARUSE) over 8 years ago
- Status changed from Assigned to Feedback
Array#any?
seems to work usual use cases.
Feedback if another cases are discovered.
Updated by sorah (Sorah Fukumori) about 8 years ago
I know any?
works on some use cases, but I'm positive to have a proposed method because using any?
has a pitfall. We have to guarantee an array doesn't have only false or nil. Also I'm worrying users who started to use any?
for this use case, but doesn't know this pitfall.
I'm positive on Object#not
idea.
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Related to Feature #13395: Add a method to check for not nil added
Updated by nobu (Nobuyoshi Nakada) about 4 years ago
- Related to Feature #17330: Object#non added
Updated by mame (Yusuke Endoh) over 3 years ago
I like Array#some?
and Hash#some?
. It is so frequent to write !ary.empty?
.
I think the main concern is only about empty?
, not other predicate methods. So I'm skeptical about the need of the generalization like ary.not(:empty?)
. I don't like it very much because it is longer and slower than the dedicated method.
Updated by sawa (Tsuyoshi Sawada) over 3 years ago
I want to mention that some of the method names proposed so far would break symmetry.
Note that "empty" is a property of the container, not the elements. When you have a = [1]
, what is questioned whether it is empty or not is a
, but not 1
. Among the words proposed so far, "any" and "some" are not a property of the container, but are a word used together with the elements, e.g., "some element 1". "present" in this respect is also not appropriate because it is a property of the element ("1 is present"), not the container (not "a
is present"). If the method in question is to be defined as the negation of empty?
, then its name should be a property of the container.
Among the words proposed so far, "non-empty", "not empty", and "full" would work. Another word that comes to mind is "occupied", but it may be too long.
Updated by knu (Akinori MUSHA) over 3 years ago
I tend to like ary.size > 0
more than !ary.empty?
because the former literally has a "positive" nuance and therefore it's more readable in many cases. In that sense, the name nonempty?
does not sound ideal to me.
So, I came up with this. What about size?
? It's in the existing vocabulary; FileTest
and File::Stat
have size?
. It presumably originates from the shell script expression [ -s file ]
(test(1)) that tests if a file has a size greater than zero. Those methods return nil
when the size is zero and return the actual size otherwise, but that's an old convention (cf. nonzero?
) and we can just add size?
as a boolean method to Array
/Hash
/String
.
I don't think we should add one to NilClass
nor Object
(Kernel
) in general, but I'm not absolutely sure about what to do with other existing classes with size
: Integer
/MatchData
/Range
etc. 🤔
Updated by p8 (Petrik de Heus) over 3 years ago
What about ary.filled?
?
It nicely pairs with empty and is not too long.
It’s also a property of the container. And unlike full?
, it doesn’t imply there is no more room.
Updated by gotoken (Kentaro Goto) over 3 years ago
Boolean size?
looks good to me. I vote for it.
My first choice was nonempty?
because this is very common word in popular algorithm text books, e.g., Knuth, Cormen, Sedgewick, Tarjan, Aho, Hopcroft, etc.
However some people pointed if array.nonempty?
looks negative and does not improve if !array.empty?
. They don't want to write negative condition there. I can agree that.
filled?
also makes me mind capacity of the container and it is misleading. IMHO.
some?
is cool but we have already any?
. These are very confusing.
not( ... )
is quite general idea, and it seems to need too complicated discussions for this simple feature request. Neither not
method does not meet avoidance of negation.
Updated by sawa (Tsuyoshi Sawada) over 3 years ago
p8 (Petrik de Heus) wrote in #note-25:
What about
ary.filled?
?
It nicely pairs with empty and is not too long.
It’s also a property of the container. And unlikefull?
, it doesn’t imply there is no more room.
I think filled?
is a perfect method name. You nailed it.
Or, if you are going with past participles, perhaps loaded?
may also work.
Updated by duerst (Martin Dürst) over 3 years ago
sawa (Tsuyoshi Sawada) wrote in #note-27:
I think
filled?
is a perfect method name.
I agree with @gotoken (Kentaro Goto) that filled?
is confusing.
Updated by p8 (Petrik de Heus) over 3 years ago
duerst (Martin Dürst) wrote in #note-28:
I agree with @gotoken (Kentaro Goto) that
filled?
is confusing.
Yes, it might be confusing when you have an array like: Array.new(3) # => [nil, nil, nil]
Is it filled or only if all nils are replaced with non-nil data?
It's a bit longer (1 more character than nonempty), but ary.populated?
doesn't have the capacity confusion.
Computers To fill (an empty field or array) with data.
Updated by austin (Austin Ziegler) over 3 years ago
I’m not entirely sure we need a new method for this, because we could always use ary.size.nonzero?
or ary.size.positive?
. It is also possible to tell the difference between an empty vs non-empty array with [nil].any? { true }
and [].any? { true }
. The advantage to #size.nonzero?
or #size.positive?
is that it works on String, Hash, and Array. It might work on a lot of enumerables, but only if they respond to #size
and #size
doesn’t require enumeration. It even works on endless ranges ((3..).size.positive?
).
Of the suggested methods, I think I like #nonempty?
best, and #size?
second-best. I like #some?
least because it is confusing with any?
.
Updated by sawa (Tsuyoshi Sawada) about 3 years ago
Some additional candidates for the method name:
content?
substantial?
Updated by knu (Akinori MUSHA) about 3 years ago
Here's my opinion about the idea that we should just import ActiveSupport's present?
.
ActiveSupport's present?
is defined for all kinds of objects, and Rails application programmers are so much used to calling present?
on any object including what can be evaluated to nil. I think this is probably because present?
predates the &.
operator and I guess when it came out it felt handy to be able to test if an object is neither nil nor empty with just one method call. But today, you don't need that because you can just say array_or_nil&.nonempty?
instead of array_or_nil.present?
. In other words, we wouldn't need non-container objects, namely nil, to respond to a present?
method, and this is one reason not to import present?
. We could just add a new non-emptiness tester method only to container classes.
Secondly, present?
is defined as the opposite of blank?
, and string.present?
is not equivalent to !string.empty?
. So, String would need a different method anyway even if we were to add present?
only to Array and Hash. I can also point out that String#blank?
considers a wider set of characters as "blank" than our stock method String#strip
does, so String#blank?
as it is now might not fit in the core without reconsideration from the I18n point of view.
So, no matter if importing partially or not, I think there would be mass confusion.
Updated by knu (Akinori MUSHA) about 3 years ago
One of the selling points of size?
, aside from the appearance of the name in the existing class File::Stat, is that it explicitly says it would check the size, which means it is essentially equivalent to size > 0
and never like each { true }
that can cause a side effect. Plus, the Enumerator API has a size
property (cf. Enumerator.new(size) { ... }
) defined inside, so Enumereator#size?
would really fit there.
Updated by p8 (Petrik de Heus) about 3 years ago
If size?
will be chosen, should we also add length?
as size
and length
are aliases?
Updated by knu (Akinori MUSHA) about 3 years ago
Probably not, considering that some classes I named earlier, File::Stat and Enumerator, only have #size and no #length.
Adding #length? in itself would be fine, but that'd make you feel awkward not to add #length also. 😅
Updated by sawa (Tsuyoshi Sawada) about 3 years ago
knu (Akinori MUSHA) wrote in #note-33:
[...]
size?
[...] explicitly says it would check the size, which means it is essentially equivalent tosize > 0
While this might make sense in JavaScript, given that 0
is truthy in Ruby, I do not agree with this opinion. Where does > 0
come from? It looks like it appeared from nowhere. I think the most natural definition of such method size?
would be mapping of size
to boolean values (via !!
), which would be true
in Ruby as long as size
is defined (i.e., is numeric), even when it is 0
.
Intuitively, "x.size?" is more likely interpreted as "is the size defined for x?" rather than "is the size of x greater than 0?"
Hence, I think the method name size?
is inappropriate for the suggested feature.
Updated by knu (Akinori MUSHA) about 3 years ago
Intuitively, "x.size?" is more likely interpreted as "is the size defined for x?" rather than "is the size of x greater than 0?"
When one knew size?
always comes with size
, one should see that asking that question does not make much sense, simply because every container instance has a size just like every file has a size, which is assumed by File::Stat#size?
. I already opposed adding a non-emptiness predicate method to Object/Kernel.
Updated by dsisnero (Dominic Sisneros) over 2 years ago
I am assuming you do not want to use each which does correct thing if container is non empty . I assume you want map method that return same type of container. Why not just add a new map method?
Hash#fmap>. Hash
Array#fmap -> Array
Option fmap -> Option
Result fmap -> Result
Bonus, have fmap follow functor laws we can start using it with monads.
fmap id = id
[1,2,3].fmap{|i| i} == [1,2,3]
[1,2,3].map{|x| x2}.map{|x| x3} = [2,4,6].map{_1*3} = [6,12,18]
[1,2,3].map{ |x| 2*(3*x)} [ 6,12,18]
Updated by nobu (Nobuyoshi Nakada) 6 months ago
- Related to Feature #20498: Negated method calls added