Function That Errors on NULL (But Passes Thru Everything Else)

UPDATE 2025: This post was originally written before the NULL/VOID split. With only one "not-a-reified-thing" (e.g. only one "antiform") then things like APPEND had to choose whether appending them would be an error, or a no-op.

At the moment in 2019, it was a no-op:

 >> append [x y z] select [a 10 b 20] 'c
 == [x y z]

Of course things have changed a lot now, but it still might be the case that you want to ensure something is non-NULL. I've rewritten it using a modern-relevant example using SWITCH for clarity.


We live in a world now where most places don't tolerate NULL, e.g. you can't APPEND it to arrays.

But sometimes you might want to ensure an expression does not produce null...

>> branches: ['x [print "hi"] 'y [print "bye"]]

>> switch 'x branches
hi

>> switch 'y branches
== \~null~\  ; antiform

>> *SOME-NAME* switch 'y branches
** PANIC: *SOME-NAME* received NULL

Solve for SOME-NAME. :thinking:

Once upon a time, this was called ENSURE:

>> ensure select [a 10 b 20] 'c
** Error: e.g. "Couldn't ENSURE you had a value, it was NULL""
** Near: ensure ** select [a 10 ... (blah blah

But that was retaken to be a 2-argument function: a variant of MATCH that triggers an error if the type doesn't match a type or set (e.g. ensure [text! integer!] 1 + 2). It passes the value through if it matches, and raises an error if it does not.

I used that all the time, whereas a single-arity function that checked against NULL seemed less useful.

Still...for the heck of it, I went ahead and made a non-null checker and called it... REALLY. Yes, REALLY.

>> really select [a 10 b 20] 'c
** Error: e.g. "You REALLY wanted a value, but got back NULL"
** Near: really ** select [a 10 ... (blah blah

I didn't like the name, and never used it. Nulls caused enough problems in those days on their own.

Anyway, REALLY isn't going to get used for anything else (at least no time soon) so it's not like it's hurting anything.

The floor is open for thoughts. Short words preferred.

How about affirm ? Could also do where, expect, assume, presume, suppose, must, need.

1 Like

Hmm, MUST is pretty good, hadn't thought of that!

append data must select block item

One thing I've sort of flipped about on is the difference in attitudes between "English can't be a language of relevance in the post-singularity future" vs. "The advent of the Internet and Wikipedia, and English-dominance in programming culture, is hardening the language more firmly than before." Time will tell.

A mixed bag of other options: valid, extant, real, usable, impose

1 Like
viable, must-have, must-be

The construct that has been committed is called MUST

 >> must find "abc" "b"
 == "bc"

 >> must find "abc" "q"
 ** Error: MUST requires argument to not be NULL

But an issue that should make everyone happier is that NULL is becoming accepted fewer places. For instance, APPEND of NULL is an error--not a no-op. You have to OPT it to turn it into a VOID

>> append [a b c] find "abc" "q"
** Script Error: append requires value argument to not be null

>> append [a b c] opt find "abc" "q"
== [a b c]

NULL's emphasis is on being a semi-ornery value that permits word access and is falsey, but isn't really accepted most places...including not being able to be put in blocks. So there should be fewer MUST needed, maybe even more about getting error locality than being necessary to trigger an error ultimately.

2 Likes

So something interesting now is that you only get GHOST! when you don't take a branch.

That means that MUST could apply specifically to that detection: an enforcement that something isn't a ghost:

must switch [...]

In the C sources, I've made Need(T) for any value that can't be NULL, and that fits pretty well there.

But we could say that unlike MUST (which only checks for non-ghost-ness), NEED could be related to voidness/nullness... "I need a value."

x: need switch [...]

This creates a little bit of friction, in the sense that this would be wrong:

pos: must find [...] ...

You'd have to write the less-English-like:

pos: need find [...] ...

That probably mandates that MUST deal with both light null and ghost."

MUST would be about "did you do the thing". NEED would be "did you give a value".

To heighten the distinction, we might even say that NEED is an arity-2 operation that takes the thing you're trying to assign:

need pos: find [...] ...

This could give you a better error message, and maybe also help guide people to the fact that the question is "are you producing a value suitable for assignment."

Because MUST doesn't care about that:

>> must switch 1 + 2 [3 [elide print "Must doesn't error here"]]
Must doesn't error here

>> need x: switch 1 + 2 [3 [elide print "Need wouldn't be happy"]]
** PANIC: NEED non-empty or non-null value to assign to X

I think I like it. That helps people pick between them more easily without getting confused.

1 Like