Is there a function for the inverse of `ismissing()`

Hi all,

Is there a function that returns the inverse of `ismissing()`?

Obviously, I can use `ismissing(foo) == false` but it seems not elegant.

Thanks!

`!ismissing`?

4 Likes

`!ismissing()`
Or, generally, for any function `foo` that returns a boolean value, `!foo` is a valid function that returns the inverse value.

itâ€™s not because `!ismissing()` is a separately defined function though, this is defined in Julia Base:

``````!(f::Function) = (x...)->!f(x...)
``````
4 Likes

To be clear, if you do `!ismissing(foo)`, this just calls `ismissing(foo)` and then negates the result with `!`

If you use `!ismissing` with no function call `(...)`, then Julia uses the higher-order function @jling mentioned, which yields a function that is the antonym of `ismissing`. This is useful for passing to other functions, e.g. for calling `filter(!ismissing, somearray)` to extract the non-missing elements.

13 Likes

So the answer is that there is no inverse function to `ismissing()`. But there are plenty of ways to generate the behaviour that such function would have.

1 Like

anonymous functions are compiled too, so you lose no performance

1 Like

this usually have a different meaning btw, an inverse function of `f()`, letâ€™s call it `g()`, should have the property `g(f(x)) == x`, which is impossible for `ismissing` for obvious reason.

thereâ€™s nothing mystical about built-in functions, you can see the source code:

``````ismissing(x) = x === missing
``````

you can define your:

``````isnotmissing(x) = x!== missing
``````

if you really wantâ€¦

3 Likes

(Yes, I would call what @drarnau wants the â€śantonymâ€ť of `ismissing`.)

4 Likes

Fwiw I would like for this to exist. The `!` makes broadcasting ugly. `.!ismissing.(x)`. But its purely aesthetic so it can live somewhere else.

`@. !ismissing(x)` isnâ€™t so bad, especially since you probably will have other function calls too. (I feel like `@.` is under-used.)

3 Likes

It canâ€™t be used in a function call without more parentheses is one issue.

Actually that might be a nice 2.0 breaking change, make

``````foo(@mymacro a, b)
``````

have `@mymacro` only apply to `a`.

`@. \$foo(!ismissing(x), b)` should work, though I donâ€™t know that it is better than `foo(.!ismissing.(x), b)`. But I agree that macro calls inside function arguments are a bit annoying because of the parens.

I have defined the following function for my Jupyter notebooks:

``````broadwrap(f) = function (args...) broadcast(f, args...) end
``````

But the name could be smaller or a single symbol. This function returns the broadcasted version of a function and I find it useful for some of the `DataFrame` manipulation functions, which ask for a function working over a whole column as an argument.

This is what `ByRow` does. It was written to do this exact operation, right?

In DataFramesMeta there is `@rtransform`, `@rselect`, `@rsubset`, etc. for row-wise operations.

No, it seems like they have some distinctions:

The wrapped function is called exactly once for each element. This differs from map and broadcast, which assume for some types of source vectors (e.g. SparseVector) that the wrapped function is pure, allowing them to call the function only once for multiple equal values. When using such types, for maximal performance with pure functions which are relatively costly, use x â†’ map(f, x) instead of ByRow(f).

But it may be the case that I created `broadwrap` either by ignorance of `ByRow` or before it existed; nonetheless, I am not sure if there is an advantage of using a more purpose-specific solution as I may end up using `broadwrap` for one or another thing that does not relate to `DataFrames.jl` (this is just its main use).

I would consider that a relatively niche difference. Itâ€™s also quite useful for data analysis, for example if you have a PooledArray and a function like `f(x) = x + rand()`.

But you are right that `ByRow` lives in DataFrames.jl. Maybe it should live somewhere else. But Iâ€™m not sure where.

The practical problem with this is that, unlike dot calls, it wonâ€™t fuse.

Yesâ€¦ but the goal of `broadwrap` is to create a `function`/`closure`/`callable` to be passed as an argument, there is a way to guarantee loop fusion when you are passing a function as argument?