alma icon indicating copy to clipboard operation
alma copied to clipboard

Implement a prefix:<exists> operator

Open masak opened this issue 6 years ago • 5 comments

Assuming a .has method on all containers that can do indexing, a prefix:<exists> macro would make it possible to write

if exists container["foo"] { ... }

rather than

if container.has("foo") { ... }

The ergonomic factor residing in the fact that we can use ordinary indexing to access the element whose existence we want to check. Normally such an access would through a NotFound exception of some kind, so this usage is "macroish".

Very closely resembles #290. Part of why I'm filing this is that I want to shake out the exact required semantics of #214, and having more dependents on solidify might help us understand more what it needs to be.

masak avatar May 21 '18 18:05 masak

Very closely resembles the semantics of #244, which is not a macro. Still, there might be room for both.

masak avatar Jun 02 '18 13:06 masak

What would be an idiomatic way to both delete (#290) an element and check if it exists, um, existed? Without breaking the Single Evaluation Rule?

tl;dr: No, seems not. But we might be able to force it to.

  • exists delete <expr> deletes the <expr> but exists can't do its job, since it's not being fed <expr>. (If this were at runtime, it would be fed none, but since exists is a macro, it gets fed delete <expr>, and it doesn't know what to do with that.) Besides which, the order of the prefixes looks wrong — it looks like we're deleting, then checking existence. So even if it did work, it'd always return false.

  • delete exists <expr> checks the existence of <expr>, but then delete is equally stumped by exists <expr>. You can't delete that; it wants an access path.

All of this means that we won't automatically get exists-delete behavior out of juxtaposing the two. But maybe one could be aware of the other, and do something clever, and we'd get a combined bit of generated code which Does The Right Thing?

(The right thing, to spell it out, being: take the access path, check if the thing exists (and store that in a temporary), delete the thing (which might not exist), and return the stored temporary value. It's like a delete, but instead of returning none, it returns the true or false exists would've returned.)

If that's too tall an order, we could always have a deleteExists prefix. But I'd prefer to do it with the orthogonal components if there is a nice way to do that.

masak avatar May 18 '19 20:05 masak

Coming back to the above musing: there doesn't seem to be a way to do this without making delete and exists suspiciously aware of each other. Or, alternatively, inventing an interface/protocol by which they could communicate with each other without knowing about the details about each other's existence... hm.

But I think it's overkill to introduce such an interface/protocol just for the (fairly uncommon) pairing of delete and exists. I'd even be more fine with encouraging people to declare their own deleteExists macro when the situation calls for it.

Except if there are a lot of other evaluation-tweaking macros in the style of exists and delete. Then I might consider it to be worth it. But I can't think of any. expect/assert (#417) is kind of one, but it doesn't have the access path thing going.

masak avatar Jul 12 '19 12:07 masak

Oh, and just like in #290, we could use safe navigation with exists and make "earlier" missing parts of the path an error. With delete, the behavior was just to give up early; with the vanilla version, return none early; here we'd want to return false early.

masak avatar Jul 12 '19 12:07 masak

Coming back to this issue, and reacting to my earlier confused musings about exists delete and delete exists:

  • Forbid exists delete <expr>. If it worked, and evaluated things in the order we'd expect from prefixes, we'd only get false every time anyway.

  • Make exists <expr> an "honorary access path", so that it somehow transparently passes up the access path in <expr>, so that delete exists <expr> works. Make delete aware of exists, so that it wires itself in that case to call exists and return the boolean. Have delete promise not to re-evaluate the whole access path, in case it has side effects.

masak avatar Jul 15 '22 07:07 masak