Does SET/ANY, GET/ANY-thing matter anymore?


#1

One of the reasons I said I did not like /ANY on GET and SET is because it didn't seem a good match for OPT-ness. And ANY is a very common construct. So if people get in the habit of naming their refinements /ANY it would be kind of irritating. One doesn't want to set a bad precedent.

But for reasons that have been reasoned to death, SET-WORD! doesn't error on null assignments, it just unsets the variable. That's firm now. No going back on it for Beta/One. Re-read the post if you need to.

It thus seems to make sense that SET of a WORD! would do what a SET-WORD! would do, and not error. And GET returning a null seems okay, since most routines don't take NULLs as input. If you really want to check something is not null you can do that on the result...e.g. ensure any-value! get word, or the shorter really get word. (Still looking for a better name on that one.)

So there'd seem to be no need for a refinement... except...

...something has to be done about VOID!

VOID! assignments still cause errors on SET-WORD!:

>> x: print "still an error"
** Script Error: x: is VOID!

If you want to write truly generic code (like, say, a READ-EVAL-PRINT-LOOP), you want to really accept not just nulls, but also "ANY"-VALUE!...and that counts void.

So we have a situation where:

  1. This comes up nearly almost never.
  2. "ANY" actually sort of feels like it is sensible for the behavior you're expanding, since it's no longer talking about non-ANY-VALUE!d NULLs.

Hence I may be willing to bring GET/ANY and SET/ANY back, but under the new meaning applying to #[void]. Bear in mind: this is materially quite different, as they no longer pertain to "unset" variables. A #[void] is not unset.

But still, get/any 'some-unset-var will answer UNSET? back. Regular GET would have done so too...but what's the harm?

Question of Nuance: GET on BLOCK! and NULL

Previously this would be an error:

 x: y: null
 get [x y]

There's no way to put nulls into blocks, so anything you do here besides an error is lying.

But circumstances have come to where I am more laid back about distinguishing NULL and BLANK!. BLANK! really is now genuinely the reified form of NULL--including that they are both falsey. I've relaxed the rules on reduce, where it will conflate nulls and blanks rather than error:

>> reduce [if 1 > 2 ["a"] "b" if 3 > 4 ["c"]]
== [_ "b" "c"]

Across the board we are encouraging dialects to think of null and blank as being the same.

So maybe the concept here, would be that if you use regular GET on a BLOCK! your nulls become blanks, but if you do a GET/ANY they become VOID! because you've indicated a willingness to understand voids
Putting #[void] in the slots is putting you in the danger zone :guitar: But if voidifying nulls mixes up with actual voids that were already in the values, you were in the zone of danger already.

Doing any better than this would need generalized quoting. Which is probably the direction advanced code would want to go with this. With the proposed tuple-predicates, you could do transformations of the gotten result:

>> x: 1 y: 2
>> get .negative [x y]
== [-1 -2]

>> x: y: null
>> get .quote [x y]
== [' ']

So it seems the /ANY option should just do the convenient thing, and voiding nulls sounds like a fit, since you are effectively saying voids are fine with you.

Afterthought...should plain GET-WORD! not get voids?

If SET-WORD! won't set voids, it seems that maybe GET-WORD! shouldn't get them. You really aren't supposed to be using them as values or signals or anything.

I think I'd be comfortable saying you had to use a special function to get a void out of a variable.


#2

Had the issues in this post rolling around in my head for a while and I settled on committing the resurrection of GET/ANY and SET/ANY. They relate solely to the handling of #[void].

Decided not to go in this direction. If anyone asks about why GET requires an /ANY refinement to give back a void and a GET-WORD! does not, it's because a GET-WORD! doesn't have anywhere to put the refinement. This means :x a synonym for get/any x and not get x... and x: is a synonym for set 'x and not set/any 'x.

There's going to have to be an asymmetry here somewhere. That one feels like it's probably the right one. Or at least--it's how things were done in the past, and I doubt anything would make a huge difference. Best to leave it.

I threw in the idea of predicates for get .quote, which is good. But going back to this point, why not solve this issue with them with predicates too...just get .try [...]? That avoids the "anything else you say is a lie" problem.

We could make voidify a function that turns nulls to blanks, and then say that's the default predicate. Then if you use some other predicate that doesn't come up with a value, it could actually error in that case.

I think this part is settled

There's still a lot more to worry about with all the semantics of the SET variants and their refinements. I'm kind of tempted to say that the native SET and GET only do as much behavior as the evaluator has for SET-XXX! and GET-XXX! types, and everything else is other functions. That would allow the implementations of the natives to just make a light call into the evaluator and we'd be sure that you always got the same behavior.