Concepts and practices of mezzanines
Paul recently asked: "Carl can you discuss briefly the goals you desire for mezzanines? What your thoughts in particular concerning speed concerns - chaining mezzanines (building mezzanines on top of mezzanines), etc."
In general, mezzanine functions are short helpers -- used to make coding easier but without losing much performance. For example, without FUNC, you would need to write each time:
my-func: make function! [....]
So, a mezz is a light wrapper around other functions, normally natives. However, that's not a requirement. It is fine to use mezz functions in other mezz functions.
There have also been cases where the code of a mezz function would be almost identical to that of a native, so there is little benefit to using a native. For example, if a function is just doing basic insert and append operations, then there is little value in the native, because it has the same overhead requirements... handling arguments, detecting string expansion conditions, building a result value.
An exception to this rule are very high frequency mezzanines. For example, in R3, a few functions like APPEND became natives. For most code, it may make little difference, but it sure "feels" better. (And here I should point out that is the wrong measure for such an action. Instead, we should profile the performance, and make decisions based on that. But, sometimes we like to feel good.)
Another area to address are mezz functions that do not do their job very well. REPLACE is a perfect example. REPLACE as a mezz has the disadvantage that each action it takes on a series must be atomic (it cannot leave the series in some partial state; the series must be valid for each iteration in the loop). But, a native does not have that restriction; it can completely deconstruct a series, operate on it, then rebuild it... and not worry about state. (Well, as long as GC is being carefully controlled during the op.)
But, there are different approaches as well. For example, it is quite possible to rewrite REPLACE as a mezzanine and improve its performance for the /all case by building a temporary output series. In fact, with such a change, I doubt REPLACE as a native would offer much performance over REPLACE as a mezz. The primary overhead is the search and copy of memory segments. That overhead would exist in a native version as well.
And finally, some of this is "art". Meaning that good design requires good balance between the factors involved. There are trade-offs. Sometimes speed is important, other times memory usage, and on top of that, we want to keep most things simple and easy to understand and maintain. After all, that's our main REBOL yell. Not to be forgotten.
Updated 31-May-2023 - Copyright Carl Sassenrath - WWW.REBOL.COM - Edit - Blogger Source Code