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

Time to even the odds

1 Like

Haha, nice findings. I just had that issue today though, it took me a lot of time to figure out what went wrong especially when I missed the !, maybe clippy should bold that.

I don't think that bolding alone is enough !. (Did you notice that the ! was bolded?) I believe that Clippy should lint whenever there is no space separating the ! from whatever follows.

1 Like
macro_rules! nonempty {
    ($e:expr) => (!$e.is_empty());
}

fn main() {
    let mut trashcan = vec!["Java"];
    if nonempty!(trashcan) {
        trashcan.clear();
        println!("problem solved");
    }
}

No need to litter std with redundant methods.

1 Like

While true, this argument can be made for many convenience functions. Most functions on Option are four liners.

The point is that nonempty functionality is just one ! away, and embedding negation into the method name is bad style anyway. I feel that Rust has become so good and fixed so many rough edges over time, that knights no longer can find any dragons to fight, so they start chasing lizards in the backyard instead.

10 Likes

Create a macros in cases where there should be a standard library method is similar to the invention of the bike when instead of using the method from std, everyone draws their own "funny" and "correct" macros. But this is a trash that clogs the code and makes its reading even worse than !

2 Likes

Clearly many people perceive a problem here or this thread would not be so long. Those of us who prefer to use a postfix .not() in some form will simply choose to do so. What we need to make such a choice effective is an allow-by-default lint for the prefix ! operator, so that we can spot instances of its use in other people's code and perhaps our own.

4 Likes

@Tom-Phinney clippy is a great testing ground for lints like this. And it's not terribly hard to write a lint for it. :slight_smile:

1 Like

I like the postfix (.not()) thing, but, I'd also prefer an "unlesss" flow-control keyword to better handle negative logic.

if !vec.empty() {
...
}

becomes either:

if vec.empty().not() {
...
}

or, with new flow-control keyword:

unless vec.empty() {
...
}

that being said, if 'not' were simply a keyword that is an alias for the "!" unary, boolean operator, then we could has:

if not vec.empty() {
...
}

If I had to choose between unless vec.empty() or ifnot vec.empty()

I would choose something that doesn't have a Ruby heritage :slight_smile:

2 Likes

I am not opposed to the not() method, but I would like it to be exported by default when I write new code that to avoid annoying errors like this

error[E0599]: no method named `not` found for type `bool` in the current scope
 --> src/main.rs:5:21
  |
5 |     if string.is_empty().not() {
  |                     ^^^
  |
  = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope, perhaps add a `use` for it:
  |
2 | use std::ops::Not;
  |

An RFC for unless was considered by the language team (and rejected): https://github.com/rust-lang/rfcs/pull/2384

3 Likes

ifn't :stuck_out_tongue_winking_eye:

There's definitely a case for ops::Not in the prelude here, as well as a restriction lint for clippy. But really, the benefit comes from not writing !long.chain().of().methods() but using a temporary binding. In this case, it's well worth the extra name for clarity. I'd say the pedantic/restriction lint for clippy should be on using ! to negate complex expressions.

1 Like

Well, I was going to suggest the following:

if some.long.chain.of.things.that.results.in.a.boolan.value BORAT! {
...
}

I often use explicit false Yoda style for negative boolean checks.

if false == booly_function(param, the_thing) {
...
}

Sometimes just ordinary !negation looks OK, but somehow explicit false in beginning seems more readable when quickly scanning code.

7 Likes

To be clear, !is_empty() has bothered me since day one. I come from Go, where it's standard to submit to lints regardless of whether you agree or disagree. I never cared enough about this issue to personally create a topic, but I'm willing to chime in now that I see one. I disagree about the rest of the paragraph as well.

To the rest of this thread: I personally find a postfix not() more confusing than everything else in this thread (even the original leading !). While direct negation happens in some languages, English today is largely not written with direct negation (another quick overview here). I know Rust caters to a world audience, but the stdlib is English and settling on a confusingly worded postfix not would IMO be overall worse.

However, I know in Rust there's more than ten ways to do anything, and ultimately any resolution here is fine to me.

1 Like

unless far predates Ruby. There's a Perl of wisdom for ya'.

1 Like

What about implementing is_containing() as opposite to is_empty() ?

I'd prefer is_not_empty(), which has less rightward drift and does not get into the semantics of "contain", which often is inappropriate. Having a set or list or slice be "non-empty" does not imply what it contains, but "is_containing" anticipates that a contained subset is about to be specified.

Edit: Corrected typo "left" -> "less"

1 Like