Should Antiforms Be Legal in MAP! (Keys, Values?)

In the pre-isotopic era, there was a concept that MAP! would not allow you to store nulls. Because null was the signal of not being in a map. Assigning a key null was a way of removing items from that map.

>> m: to map! [x 20]
== &[map! [
    x 20
]]

>> m.x
== 20

>> m.y
; null

>> m.x: null
; null

>> m
== &[map! [
]]

Additionally, NULL was not allowed as a key.

How Should This Change In The Isotopic Era?

We still have the case that mapping to null (or void, that causes null retrieval?) would conflate with testing for presence or absence in the map.

I'll make the point that not allowing you to store antiforms as keys or values isn't a fundamental problem, because you can LIFT a value to put it in, and then UNLIFT it when taking it out.

Disallowing Widens The Gap With Objects

There have been questions about what the difference is between maps and objects, and this would be another: objects must be able to have members that are antiforms: action isotopes that can run implicitly, okay and null and other word antiforms, and I'm presuming splices and other stable forms as well.

It would mean a map has more in common with a block...more easily being converted to or from it.

I don't know right now whether to allow or disallow. So for starters I am going ahead with the premise that antiforms can't be stored in maps, as either keys or values. We'll see how it goes. If it is relaxed, it will be relaxed only for the values...in order to have parity with objects.

1 Like

In order to align with the rest of the system, "removing" keys from the map is done by assigning them VOID.

Accessing a key that is not in a map (or removed from it) requires you to use TRY if you want a null out of it:

 >> map.foo: void

 >> map.foo
 ** Error: ...

 >> try map.foo
 == ~null~  ; anti

If you want to know if the map has the key present, there's HAS to answer that question:

 >> has map 'foo
 == ~null~

Having seen how it goes: one of the big places that MAP! is used right now is in UPARSE, as the combinator map. And it's a thorn to have to LIFT the DATATYPE! instances just to put them into or out of the map.

But the DATATYPE! is being used as a key. I think it should be able to do it.

However, I don't think this should work:

>> m: to map! []

>> m.(null): 10
== 10

>> m.(null)
== 10

You lose the safety of catching nulls. I think we could probably avoid problems by ruling out LOGIC! antiforms in the key slot, and allow other stable antiform types (maybe not trash, but they might have use cases too).

But letting you map TO things like null, or trash, or whatever would make MAP! more similar to OBJECT!. You could possibly even use the maps for binding.

I Think I'm Gonna Do It...

The contortions that are necessary to make a mapping from a datatype to other things are annoying.

I can imagine applications of mapping to antiform actions as opposed to non-antiform frames, and it's more direct if you're allowed to do it vs having to meta everything going in and out.

Really, UPARSE is a kind of calibration exercise where if I look at something like having to lift things to use them as keys or values, I can say "that feels like make-work, and it makes the source look bad, when it would look nice otherwise..."