ENSURE vs. ENFORCE

I noticed that I have two different ways of using the word "Ensure".

The first meaning is "If something hasn't already been done, make sure it gets done." This happens with things like passing a series to a value cell...and anything that gets put into a value cell has to be under the control of the memory manager. That's indicated by a bit set on the series, so Ensure_Series_Managed(series) will check to see if the bit is set, and if so it is a no-op. If it's not set, then some code runs and the bit gets set.

The second meaning is "Check if something has a property...and pass the value thru if it has that property, otherwise trigger a failure and interrupt the operation." This is how it's been used in the ENSURE native, where you give it a datatype and can say something like ensure integer! foo. Inside the C code I can use it the same way, e.g.

REBVAL *v = ENSURE(REB_INTEGER, First_Value_In_Array(array));

I'm not thrilled about having the word mean both things. At first I figured that ENFORCE might be used for the first case...but then it sounds like what it does is more severe. Depending on how you look at it, "forcibly" changing a condition to be true even if it was not might be more "intense" than raising an error...

ENSURE has precedent in design-by-contract, which suggests failure vs. massaging things to be how you want:

https://archive.eiffel.com/doc/online/eiffel50/intro/language/invitation-07.html

That goes along with me thinking I think I like the ENSURE native how it is, so it's the other word I want to change...currently it's only inside the implementation so it's not a big issue. But talking it through in case anyone has ideas.

; could this better suggest that if the array is not managed, it becomes so?
; there is no error, only bringing the argument into compliance.
; also should suggest that the input value is passed through either way.
;
Init_Block(value, Enforce_Array_Managed(array));

Perhaps just "FORCE", instead of "ENFORCE"?

Init_Block(value, Force_Array_Managed(array));

Hmm... I think I like that.

It could be used as a Redbol function in a context where you want to do a TO conversion, but only if something wasn't the type already:

>> blk: [a b]
>> forced: force block! blk
== [a b]
>> append blk 'c
>> forced
== [a b c]  ; kept identity; was passed thru as-is

>> int: 1
>> forced: force block! int
== [1]  ; had to have a new thing made for it to be blocklike

This is the spirit of the kinds of functions I'm talking about...to have a baseline case where they are no-ops, but then take action if the thing they want isn't true enough to pass through a result with that property. Previously I called the above force block! concept "blockify", but this could generalize better and be less of a weird name.

1 Like