ICU API Proposal: MF2 Function Composition

3 views
Skip to first unread message

Steven Loomis

unread,
Jun 24, 2026, 8:14:02 PM (9 days ago) Jun 24
to icu-d...@unicode.org

Dear ICU team & users,

I would like to propose the following API for: ICU 79

Please provide feedback by: next Wednesday, 2024-07-01

Designated API reviewer: Mihai ⦅U⦆ Niță

Ticket: https://unicode-org.atlassian.net/browse/ICU-23424

Doc Link: https://docs.google.com/document/d/1MsXcCEggqTGRDcyO2l3Hv88ZPoQL0hhKUEKXhJfvaRQ/edit?usp=drivesdk


These two functions are needed for being able to compose functions, that is, to create new functions that are based on the existing functions.


/** Returns a MFFunctionRegistry containing the default functions. The contained function pointers are owned by the registry. */

static MFFunctionRegistry MessageFormatter::getStandardFunctionRegistry(UErrorCode& status);


/** Returns a new FunctionContext that has a locale set of ‘loc’. To be used by a custom function to change the locale and sub-call another function. */

FunctionContext FunctionContext::withLocale(const Locale& loc);

Steven Loomis

unread,
Jun 29, 2026, 8:43:40 PM (4 days ago) Jun 29
to Steven Loomis, icu-d...@unicode.org
I have updated the proposal (and have a PR) as follows. Three APIs are now proposed.
As a reminder, overriding standard functions is a separate concern that is not addressed in this proposal nor in the PR.


PR: https://github.com/unicode-org/icu/pull/4054


These functions are needed for being able to compose functions, that is, to create new functions that are based on the existing, standard functions. This example shows changing the locale in the context.  Another example could be modifying or transforming the output of one function (such as a script transliteration).



      class FunctionContext {


     /**

            * Returns the original called function name from this context.

            *

            * @return The function name, as registered, used for this function

            *

            * @internal ICU 79 technology preview

            * @deprecated This API is for technology preview only.

            */

           U_I18N_API const FunctionName& getCalledFunctionName() const;


           /**

            * Returns a new context with the specified locale.

            *

            * @return a new locale

            *

            * @internal ICU 79 technology preview

            * @deprecated This API is for technology preview only.

            */

           U_I18N_API FunctionContext withLocale(const Locale& loc) const;


           /**

            * Returns a pointer to a standard function.

            * This function may only be used within the implementation of call()

            * The returned pointer is invalid once this FunctionContext goes out of scope.

            * A U_INVALID_PARAMETER is setif the requested function is not one of

            * the standard functions.

            *

            * @param name the name of the standard function, such as "datetime" or "number"

            * @return pointer to the standard function, or nullptr

            *

            * @internal ICU 79 technology preview

            * @deprecated This API is for technology preview only.

            */

           U_I18N_API Function *getStandardFunction(const FunctionName &name,

                                                    UErrorCode &errorCode);


Example Use:


In this example, the function given below is registered as _date and _number
The call() Implementation retrieves the name, removes the underscore, and then delegates to the standard function (such as date or number). 


If overriding the standard functions are allowed, then the underscore would not be needed.


A user of these functions could opt to set the locale via a function argument or option, that is beyond the scope of this example.


LocalPointer<FunctionValue> LocaleOverrideFunction::call(const FunctionContext &context,

                                                const FunctionValue &arg,

                                                const FunctionOptions &opts,

                                                UErrorCode &errorCode) {

   const FunctionName& myFunction = context.getCalledFunctionName();

   const FunctionName& stdFunction = myFunction.tempSubString(1); // _date -> date

   Function *delegateFunction =

       context.getStandardFunction(stdFunction, errorCode);

   if (U_FAILURE(errorCode)) {

       return LocalPointer<FunctionValue>();

   }

   // create a new context, with our updated locale

   FunctionContext myContext = context.withLocale(overrideLocale);

   // call the delegated function

   return delegateFunction->call(myContext, arg, opts, errorCode);

}




--
Steven R. Loomis
Code Hive Tx, LLC



--
You received this message because you are subscribed to the Google Groups "icu-design" group.
To unsubscribe from this group and stop receiving emails from it, send an email to icu-design+...@unicode.org.
To view this discussion visit https://groups.google.com/a/unicode.org/d/msgid/icu-design/4F44BFDB-D643-4ABE-8B80-9B15F5B3EEDF%40unicode.org.
For more options, visit https://groups.google.com/a/unicode.org/d/optout.

--
You received this message because you are subscribed to the Google Groups "ICU - Team" group.
To unsubscribe from this group and stop receiving emails from it, send an email to icu-team+u...@unicode.org.
To view this discussion visit https://groups.google.com/a/unicode.org/d/msgid/icu-team/4F44BFDB-D643-4ABE-8B80-9B15F5B3EEDF%40unicode.org.

Rich Gillam

unread,
Jun 30, 2026, 4:03:54 PM (3 days ago) Jun 30
to Steven Loomis, icu-d...@unicode.org
I haven’t been following the MF2 work closely at all, so take anything I say with a grain of salt, but this proposal seems reasonable to me.

—Rich

Reply all
Reply to author
Forward
0 new messages