The is_not_empty() method as more clearly alternative for !is_empty()

Yeah, that might help. Because the first instance of is_empty doesn't say anything about !

4 Likes

Or presumably it could be a structured suggestion, so people can just click the button in their editors? (Doesn't even need to be a fancy editor; even sublime text can apply them these days...)

This is not quite true, since the _else variants take closures, which may not have the precise same ownership semantics as an immediate T; not to mention that for some flavors of _else we can't blindly trust LLVM to perform the obvious inlining.

There is also a degree of "oh, we're already doing a poor job of X so making it worse is negligible" in this argument that can be used to justify just about anything.

You could read it that way, I meant to say that the current design of several parts of the stdlib seems to value convenience over minimalism, so I'm not particularly convinced by saying it should stay minimal.

I don't think that Rust offers some methods that are easily-derived from other methods means it is doing a poor job.

I'd toss my 2 cents in for an unless keyword that is equivalent to if not ().

unless v.emtpy() {
 // ...
 }

But generally I'm happy with !v.empty()

1 Like

Personally, unless is one of the things I dislike most about Ruby. Everytime I run into code using unless I end up having to reread the whole condition multiple times to figure out what it actually means.

15 Likes

Perhaps in some cases it might be convenient.

let hello: String = "Hello".into();
    
if let Some(value) = hello.present() {
     println!("{} World", value);
}

Thoughts out loud, please do not pay attention. source

!v.is_empty() has bothered always bothered me. Negations are hard to keep straight (for me and others), and this simple expression uses two. Because of this, I don't really think the clippy recommendation is clearer, nor do I find it more explicit.

To throw my unqualified opinion into this bikeshed, I prefer is_nonempty or has_content. I find non- easier to understand as part of a whole word, rather "not" negating "is". has_content avoids negations entirely, but I find that the concept of content in a string or slice a bit confusing.

6 Likes

+1 for is_not_empty. 99% of my use of is_empty if !is_empty() and I also forgot the ! a few times. The ! is not super obvious to me when reading code so I would welcome something clearer like is_not_empty() (or has_content or anything else)

Pascal/Ada veterans be like

macro_rules! not { ($ex:expr) => (!$ex) }
1 Like

That's what I was using before ops::Not: https://docs.rs/candy/0.1.5/candy/macro.not.html

I don't think we should do anything here. !foo.is_empty() is good enough, and the advantages of any of the alternatives proposed here are not worth the churn in idioms in the ecosystem, IMO.

If the ! bothers folks that much, then y'all might consider just using foo.len() > 0 and either disable the corresponding Clippy lint, or lobby Clippy to allow it.

19 Likes

I do think we should improve the text of the clippy lint to reduce the likelihood of errors in correction.

12 Likes

While the difference is minimal, and thus doesn't really matter, currently is_empty generates tighter assembly than length checks, for certain containers: https://rust.godbolt.org/z/O2NCT0

7 Likes

I wish I didn't have to import std::ops::Not.

I used to use .not() in my Rust code because it reads so much nicer. But the import is always hurting my ability to reach for it in any random file so I unlearned the habit and taught myself to use the prefix ! instead :frowning:

1 Like

There's also:

if v.is_empty() == false {
...
}

when one does need extra clarity/explicitness.

4 Likes

I personally find the above v.is_empty() == false more confusing than any of the other alternatives. I believe that the underlying problem here is the visual difficulty of noticing the deferred-applicability unary prefix ! operator when it is conjoined (i.e., not space-separated) from whatever follows it. That is particularly the case when the ! operator is applied to a series of field specifiers and method invocations (e.g., !abc.def.ghi().jkl[ix].mno.pqr() vs abc.def.ghi().jkl[ix].mno.pqr().not() ).

8 Likes

I'll add is_null() to the bunch. I use !ptr.is_null() incredibly often, and need to look twice at it every time I read the code.

If Rust was a "clever" language, then every is_ function returning bool would automatically get is_not_ variant :slight_smile:

4 Likes

More clever would have been refraining from copying C's near-invisible negation sigil, however familiar it might have looked.

Alas, this particular ship has sailed...

5 Likes

For readability, I'd rather just hava a lint for bang operators that aren't surrounded by whitespace on both sides. if ! v.is_empty() does the job for me. Whoever wants a .not() can suit themselves, but I just find it verbose.

As for methods like not_empty(), does this mean that every predicate must now have a twin, or shall vectors be special like this? Are we going to have a #[has_opposite] for automatic generation of opposite methods?

I think the bang is hardly the problem there, with the method chain following it being the big issue. Such chains can be broken down (and likely clarified as a bonus) via well-named locals that actually tell us what the abc.def.ghi() part is supposed to do, what .jkl[ix].mno.pqr() is for etc.

However, when I see such chains (barring exceptions like collection handling and fluid APIs), I tend to suspect that the respective code is intruding way down into lower-level abstractions that it should have no direct business with (the aforementioned abstractions not having been written yet might also be another issue that has little to do with the bang). Or am I missing something?

2 Likes