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.