Expand/Shrink

routine_id

Definition: integer rid = routine_id(string rtn_name)
Description: Deprecated, since 0.8.2 you can just code my_rtn (without quotes and not followed by '(') instead of routine_id("my_rtn"), although both remain perfectly valid, plus the get_routine_info() as documented below is still independently useful, and finally most of the remarks below about hll_stubs continue to apply.

While this is unlikely to go away any time soon, new code should just use the bare routine name, which the compiler treats as (aka automatically converts into) a constant integer. You may encounter some cases where that does not quite work, such as piecemeal string construction and maybe even the odd forward reference, but even then the recommendation is to refactor those nasty bits away until it does work, purely on the grounds of it’ll doubtless be nicer code.

One subtle point to note is that the compiler has been very finely tuned to deeply understand scopes, and in particular a few nuances related to locality of reference at a specific point in a complex nested include hierarchy (oooh errr, listen to im) that are lost and are frankly impossible to replicate (and obviously never were) in a routine that looks up a name in one dirty great big flat symbol table. If you didn’t get any of that, the key take-home is that it all goes away if you use bare routine names.

Return an integer id number, in fact an index to the symbol table, for a user-defined procedure or function.

The name of the procedure or function is given by the string sequence rtn_name.

-1 is returned if the named routine cannot be found (see Technicalia).
pwa/p2js: Supported, although as of 0.8.2 a bare action_cb is equivalent to routine_id("action_cb"), and is recommended. Be advised that JavaScript is fundamentally a function-scoped language and there are no namespaces or different scopes for different include files.

Since core components are coded without inline assembly in p2js.js there is no need for hll_stubs.

On a related note, Icallback() is in fact a dummy function in pGUI.js which does not attempt to replicate the safety/sanity checks of cbfunc() - of course that is still valuable when developing on the desktop, and of course if you forego testing things first on the desktop and switch to a direct edit/browser mode of development instead, that’s on you.
Comments: The id number can be passed to call_proc() or call_func(), to indirectly call the routine named by rtn_name.
It can also be called directly, as of 0.8.1 routine_ids are first class, and as of 0.8.2 a bare reference to an existing routine name not followed by '(' is treated as if routine_id had been used, see example 1 below.

The routine named by rtn_name must be visible, i.e. callable, at the place where routine_id() is used to get the id number. Indirect calls to the routine can appear earlier in the program than the definition of the routine, but the id number can only be obtained in code that comes after the definition of the routine - see example 2 below.

Once obtained, a valid routine id can be used at any place in the program to call a routine indirectly via call_proc()/call_func(), or now directly.

Some typical uses of routine_id() are:
1. Creating a subroutine that takes another routine as a parameter. (See Example 2 below)
2. Setting up an Object-Oriented system.
3. Defining a call_back(). (See Calling C Functions)

Note that C routines, callable by Phix, also have (non-first-class) routine ids, but from define_c_proc() and define_c_func(), not this.
Auxillary function: {integer maxp, integer minp, string sig[, object name]} = get_routine_info(integer rid, bool bName=true)
Returns the maximum and minimum number of parameters, along with a string representing the signature in roottype format, and optionally the actual name of the routine, except when rid refers to a class method, when -1 is returned (on purpose, since their proper names are kept in builtins\structs.e, and are passed in as text anyway, so you don’t want or need multiple conflicting entries messing up the symtab. You still(/only) get max/min/sig for class methods.)

For instance get_routine_info(apply) yields {3,2,"FOIO","apply"}. Note that invoking this routine with bName=true coerces the run-time into populating the symbol table with actual names, which may make startup a fraction of a second slower when interpreting, especially on larger programs - hopefully not quite enough for anyone to actually notice, but if you don’t need the name there is not a lot of point asking for it.

Under pwa/p2js minp is always 0 and sig is always "" (hardly surprising in a typeless language), but maxp and name are fine, and unlike desktop/Phix there is no associated penalty of populating the symbol table names, so a bName of false is ignored and name is always returned.

Note that p.exw deliberately invokes get_routine_info(-9) to permanently disable it, that is within p.exe itself, since populating the symtab with actual names mid-compilation kinda spanners everything. In other words this routine is not available to the compiler itself, at least for now. In reality, p.exe is already pre-populated, no issue there, however this and "p p" might or might not trigger armageddon, so I’ve played it safe, perhaps for no good reason at all.

Intended for internal use in routines such as apply() to make a more informed choice about precisely how to invoke a routine, but of course it is also available for use at the application level. It is now used (at runtime) in structs.e, to check the validity of any getters and setters it finds before invoking them, and twice in pGUI.e, in the Icallback[i]() routine, and to check the K_ANY callback does not have a time-bomb signature, since I’ve managed to put quite a few of those in myself while translating C code.
hll_stubs: The file builtins/hll_stubs.e (an auto-include, except as noted below) contains hll verions of many builtins implemented in assembly, for use when you need a routine_id. Prior to 0.8.2 you would have had to roll your own such mini-shim(s).

While you should not really care much, the overwhelming majority of routines documented in this help file are implemented as standard hll routines (eg abs), but many what you might call "true builtins" are written in assembly for performance or practical reasons, eg you might struggle to use a hll routine as any part of the mechanism for calling a hll routine, and between them length() and append() are so ubiquitous that just making those two alone always use a hll wrapper could easily make almost everything (including the compiler itself) run three or four times slower2.
It would probably not be helpful (except as noted below) for either you to study or me to document which is which, rather simply you should just assume anything (genuinely useful) should be available, and let me know of anything that ain’t.
Equally you should not get too miffed should a new release "upgrade" an existing hll routine to asm in the name of performance, or (as has happened to find(), match() and repeat() already) "downgraded" in the name of simplicity and sanity or enhanced functionality, although that sort of thing should probably only ever matter when grafting on the "hll_" manually, as described below.
One thing you should not assume is that everything goes through such wrappers, in fact the vast majority won’t.

The compiler automatically substitutes routine_id("length") with routine_id("hll_length") and likewise a bare 'length' with no following '(' with the same implied routine_id.

Note the equivalent existing sq_xxx routines may prove significantly faster, and perhaps easier.
For instance sq_atom(s) and apply(s,atom) both yield exactly the same results, the former however being noticeably quicker. For completeness, I should also note that apply(true,[hll_]atom,{s}) also yields the same results, however apply(true,sq_atom,{s}) yields something subtly different.

Also, if you are dynamically constructing the names passed to routine_id, you may need to graft on the "hll_" part yourself.
The compiler only does so for inline literals and not for anything like "len"&"gth" or apply({"length","integer"},routine_id).
At the last count, there are some 25 such hll_xxx routines, and despite what I said above I suppose you do need to know which is which to figure out which is going to need the hll_prefix, but you can gather that from builtins/hll_stubs.e easily enough, or if you prefer they are all listed alphabetically in the index of phix.chm (and all linking directly to this very section), just type "hll" in the index and they’ll all appear.
Also I would hope obviously this file is only an auto-include in the cases where the compiler has spotted it is needed: if you are having to graft on the "hll_" yourself, then you will probably need to "include hll_stubs.e" explicitly as well.
Example 1:
procedure foo()
    puts(1, "Hello World\n")
end procedure
constant r_foo = routine_id("foo")
call_proc(r_foo, {})    -- same as calling foo()
r_foo()                 -- "", in 0.8.1+
call_proc(foo, {})      -- "", in 0.8.2+
Example 2:
function apply_to_all(sequence s, integer f)
-- apply the specified function to all elements of a sequence
    for i=1 to length(s) do
        s[i] = call_func(f, {s[i]})
    end for
    return s
end function

function add1(atom x)
    return x + 1
end function

?apply_to_all({1, 2, 3}, routine_id("add1"))  -- displays {2,3,4}
?apply({1, 2, 3}, add1)  -- (equivalent in 0.8.2+ - add1 valid & apply builtin)

Note that add1 could be a private function in a completely different file; there is no need for it to be in scope when (actually) called.
Implementation: See builtins\VM\prtnidN.e (an autoinclude) for details of the actual implementation.

Note however that the compiler tries very hard to avoid calling/including that code, if things can be resolved at compile-time.

The get_routine_info() routine is implemented separately, in builtins\get_routine_info.e (another autoinclude)
See Also: call_proc, call_func, apply, call_back, define_c_func, define_c_proc, Calling C Functions
Expand/Shrink