Handling MATCH and "Falsey" Types

MATCH has a fundamental safety issue:

>> match [<opt> integer!] 3
== 3

>> match [<opt> integer!] "notaninteger"
; null

>> match [<opt> integer!] null
== ???

This returns "heavy null". Once upon a time, heavy null was not auto-decayed when passed to functions like IF:

>> if (match [<opt> integer!] null) [print "Yes it matched!"]
** Error: IF does not accept heavy null without a ^META condition

But it came to be that for general ergonomics, heavy nulls had to decay to plain nulls when passed to normal parameters. Otherwise, they would be too invasive.

So for now, a "passing null" is conflated with a "didn't pass" signal. It will work with THEN, but be incorrect with IF.

So What To Do About MATCH and its bretheren?

Seems the alternative options are:

  1. Don't worry about it. If you write match [logic!] 1 = 2 you get back a ~false~ isotope and should you write an expression like if (match [logic!] 1 = 2) [print "Match!] you get what you deserve.

  2. Use a different isotope. Let's say that match [<opt>] null is simply ~matched~ (isotope). It wouldn't have the decaying property, but would have the invalidness property of not being logic testable

  3. Have a MATCH/FALSEY variant. Let plain match on a falsey thing trigger an error and if you write if match/falsey ... then you clearly do know what you're doing so it becomes like case (1).

  4. Make all conditional arguments take ^META arguments for their conditions. This would put the responsibility for checking for isotopes on them, and they'd uniquely disallow them before UNMETA'ing them and then testing for truth/falsehood.

Option (4) is too taxing...impacting not just the interface to IF but the implementation of CASE and any conditional construct.

(3) punts the ball down the road a bit, but might not suit Chris.

Option 5. Adjust (DID ...) as isotope-tolerant (NOT NULL? ...)

Another answer...

If you find yourself in a situation where isotopes are giving you a problem, switch to did match (or decay match, if you're trying to get the value and not test it as a condition)

I wouldn't reach for this by default. You're fine most of the time... if your MATCH doesn't contain [<opt> logic! blank!]. It's only these quirky edge cases where it's better to let the isotopes give you a localized and clear error than wind up on a wild goose chase for why the program is acting strangely.

Beginners might be cautious and write things like did match or did parse all over the place, if they're scared of missing a case. But there's no need to write if did match integer! value, because you're testing for a value that can't possibly be false...it's an integer! or null. Experts would use it sparingly, in cases like if match typeset value, in case the typeset gets expanded into things including falsey values, when you're not fully cognizant of that happening.

This broadens the service of DID across the board, to do what it was originally intended to do: transform functions that return non-LOGIC! values and NULL as soft failure to give logic results. It can handle historical edge cases with an elegant touch, without burdening code that knows itself well enough to not hit those cases.


... and if blank! becomes truthy as per your other post there’s one less case to worry about.

1 Like

Yup, good point.

Changing DEFAULT to not consider BLANK! is an obvious enough improvement to go ahead and do it--the truthy/falsey status notwithstanding.

I think we can get all the same errors for catching people who don't know what they're doing... but without the isotopic runaround:

Just say MATCH doesn't match NULL at all (have it error on null input)...but then make it follow the VOID-in-NULL-outconvention.

So if you want a NULL => NULL conflation, then instead of writing this:

match [<opt> integer! text!] var-might-be-null

You write this:

match [integer! text!] maybe var-might-be-null

On the other hand, if you are doing something like an if match where all you want to know is if it was in the set, you can reify it and test on blank:

 if match [blank! integer! text!] reify var-might-be-null [...]

With blank being truthy, that gets you the answer you want.