Search Top Index
HELP FOR_FORM Ian Rogers, Adrian Howard, David Young Jan 1994 Revised: John Gibson Jan 1996 For-forms are used to extend the syntax of "for ... endfor" to give more varied forms of looping constructs. The user can add new forms. CONTENTS - (Use <ENTER> g to access required sections) 1 Overview 2 Predefined Extended for Forms 2.1 in_vectorclass and in_vector 2.2 in_string 2.3 in_dstring 2.4 in_subscripted 2.5 with_index 2.6 in_list 2.7 on_list 2.8 in_property 2.9 on_property 2.10 from_repeater 2.11 in_region 2.12 in_array 2.13 equalto and allequalto 3 How to Write Extensions 4 Predefined General Utilities 4.1 Using class_subscr_loop to Define New for-forms 4.2 Using subscr_loop 4.3 Adding with_index Hooks 5 fast_for Details ----------------------------------------------------------------------- 1 Overview ----------------------------------------------------------------------- This provides extensions to the normal looping constructs of the forms for ... in ... do ... endfor for ... on ... endfor and fast_for ... in ... do ... endfast_for fast_for ... on ... do ... endfast_for See HELP * FOR, and REF * FAST_FOR The extended for forms are for varlist type expression-list do ... endfor; fast_for varlist type expression-list do ... endfast_for; where type is a syntax word to indicate an extended for iteration construct. ----------------------------------------------------------------------- 2 Predefined Extended for Forms ----------------------------------------------------------------------- Several frequently required "for ...type" forms are provided. Additional forms can be defined by the user, as described below. Descriptions of the built in forms follow. 2.1 in_vectorclass and in_vector --------------------------------- for var1, var2 ... in_vectorclass vector1, vector2, ... do Each of the variables varN iterates over elements of the corresponding vector vectorN. In the case where there is only one variable and one vector, this is a more efficient replacement for the tortuous for item in vector using_subscriptor subscrv do using_subscriptor does does not allow iteration through multiple vectors simultaneously. Example: vars a,b; for a, b in_vectorclass 'ABC', {ant bat cow} do [^a ^b] => endfor; ** [65 ant] ** [66 bat] ** [67 cow] Notice that in this example there are two vectors of different types: a character vector and a full vector. Any number of vector expressions with any mixture of vector types is permitted (unlike the in_vector construct, defined below). The only constraint on this form is that there must be a class_fast_subscr present in the system for each type of vector used. If something other than a vector type is found, e.g. a list, then an error will result. The number of iterations to be done is determined by the size of the smallest vector. for a, b in_vectorclass {1 2 3 4 5}, {dog bat ant} do [^a ^b]=> endfor; ** [1 dog] ** [2 bat] ** [3 ant] fast_for can also be used. In that case it is assumed that the length of the first vector will determine the number of iterations. This can lead to bizarre results if it is longer than one of the other vectors, e.g. fast_for a, b in_vectorclass {1 2 3 4 5}, {dog bat ant} do [^a ^b]=> endfor; ** [1 dog] ** [2 bat] ** [3 ant] ** [4 <SYSTEM_OBJECT 00000016>] ** [5 <key string>] The in_vector for-form is designed for the special case where all the vectors are of the same type, namely standard Pop-11 full vectors. vars x,y; for x,y in_vector {1 2 3 4}, {a b c} do [^x ^y] => endfor; ** [1 a] ** [2 b] ** [3 c] If one of the expressions after in_vector does not evaluate to a vector then a run-time error will result. Otherwise this case is slightly more efficient (ie. faster) than in_vectorclass. 2.2 in_string -------------- This is designed for the special case where all the vectors are of the same type, namely standard Pop-11 (d)strings. vars x,y; for x,y in_string '1234', 'abc' do [^x ^y] => endfor; ** [49 97] ** [50 98] ** [51 99] If one of the expressions after in_string does not evaluate to a (d)string then a run-time error will result. Otherwise this case is slightly more efficient (ie. faster) than in_vectorclass. 2.3 in_dstring --------------- This is the same as in_string when applied to ordinary strings. When applied to a dstring the full character, include attributes is returned. For example: vars x,y; for x,y in_dstring '1234', '\{b}abc' do [^x ^y] => endfor; ** [49 1048673] ** [50 1048674] ** [51 1048675] See REF * STRINGS for more information on dstrings. 2.4 in_subscripted ------------------- for var1, var2 ... in_subscripted struct1, struct2, ... do For structures that have a class_apply that handles numerical subscripts, and for which the procedure length produces an appropriate result, it is possible to to use the form in_subscripted. This enables simultaneous iteration over vectors and lists, as in: vars a, b, c; for a,b,c in_subscripted {1 2 3 4}, 'abcd', [ant bat cow ] do [^a ^b ^c] => endfor; ** [1 97 ant] ** [2 98 bat] ** [3 99 cow] 2.5 with_index --------------- For any of the above "vector-type" iteration constructs, it is sometimes useful to keep a note of the "current index". Ie. the number of the current slot (its cardinal number). This can be achieved automatically by using with_index in conjunction with any of the above "vector-type" constructs. Eg. vars a, b, v = {x y z} for a with_index b in_vector v do [^a ^b] => endfor; ** [x 1] ** [y 2] ** [z 3] Assigning to the index variable will alter the behaviour of the loop. See below for details of adding with_index hooks to user defined "vector-type" iteration constructs. 2.6 in_list ------------ for var1, var2, ... in_list list1, list2, ... do This construct is exactly equivalent to for var1, var2, ... in list1, list2, ... do which can be thought of as syntactic sugar for the former. Also, using_subscriptor cannot be used with this form vars x, y; for x, y in_list [a b c], [A B C] do [^x ^y] => endfor; ** [a A] ** [b B] ** [c C] The length of the shortest list determines the number of iterations. fast_for can also be used to increase speed with reduced checking. This can lead to unpredictable results if one of this list has a non-list tail. fast_for cannot be used with dynamic lists. 2.7 on_list ------------ for var1, var2, ... on_list list1, list2, ... do This construct is equivalent to for var1, var2, ... on list1, list2, ... do E.g. vars x, y; for x, y on_list [a b c d], [A B C] do [^x ^y] => endfor; ** [[a b c d] [A B C]] ** [[b c d] [B C]] ** [[c d] [C]] Again, the length of the shortest list determines the number of iterations. fast_for can also be used, with the same caveats as for in_list. 2.8 in_property ---------------- for key, val in_property property do This form is used for iterating over key/value pairs in a property (also see HELP * PROPERTIES, REF * APPPROPERTY, * PROPS.) Example vars key, value; vars foo = newproperty([[a 1] [b 2] [c 3]], 3, false, true); for key,value in_property foo do [key = ^key , value = ^value] => endfor ** [key = c , value = 3] ** [key = a , value = 1] ** [key = b , value = 2] The form: for key, val in_property property do .....key....val.... endfor does approximately the same as appproperty( property, procedure(key, val); ....key....val....endprocedure ) However, the "for ... in_property.." version is more efficient as there is no need to call a procedure on each iteration. quitloop and return behave as you would expect for a looping construct. The form fast_for key, val in_property property do .....key....val.... endfor does approximately the same as the following fast_appproperty( property, procedure (key, val); ....key....val....endprocedure ) and has similar dangers and restrictions (i.e. the loop body should not access or update the contents of the property in case a garbage collection has occurred and they had to be re-located). See REF * FAST_APPPROPERTY for more information. In both cases, the order in which the property entries are bound to the two iteration variables is arbitrary. Therefore, only one property at a time is allowed with this form as it is meaningless to consider stepping through two properties in synchrony. 2.9 on_property ---------------- fast_for entry on_property property do This is similar to in_property except that, instead of the key and value being returned, each time round the loop a full property entry is put into entry. This entry is the same as that returned by fast_get_prop_entry (REF * FASTPROCS/fast_get_prop_entry) Example: Say that nums is a property matching keys against numbers and that you want to increment each of these numbers as long as the predicate pred returns true when applied to the key. The following loop will do that: vars e; fast_for e on_property nums do if pred(fast_prop_entry_arg(e)) then fast_prop_entry_value(e) + 1 -> fast_prop_entry_value(e); endif; endfor; The behaviour of this construct is very rude, and therefore there is no slow version. The value of entry is a pointer to the entry cell which is still in the property. Therefore, if the property itself is updated within the loop, the resulting behaviour of the loop will be undefined. 2.10 from_repeater ------------------- for var from_repeater repeater do This construct can be used with the repeaters returned from, eg., discin or incharitem. Each time round the loop var is given the next item returned from the repeater. The loop exits, without executing the body of the loop, when the repeater returns termin. 2.11 in_region --------------- for var in_region list do This can be used in place of nested numerical for loops, even if the depth of nesting is not known at compile-time. See HELP * in_region. 2.12 in_array -------------- for var1, var2, ... in_array array1, array2, ... do This is used for iterating over data in arrays, much as in_vector can be used for iterating over data in vectors. The full form is for var1, var2, ... with_index ivar in_array array1, array2, ... updating_last n in_region list of_dimension d do For details, see HELP * in_array. 2.13 equalto and allequalto ---------------------------- for var equalto pattern [in list] do for var allequalto pattern_list [in list] do The equalto construct iterates over all the elements of list which are equal to the item pattern (i.e. element = pattern). See HELP * equalto. The allequalto construct iterates over all possible lists of elements from list which are equal to the list pattern_list (i.e. element_list = pattern_list). See HELP * allequalto. With both these constructs, list defaults to the value of the variable database if the 'in list' clause is omitted. ----------------------------------------------------------------------- 3 How to Write Extensions ----------------------------------------------------------------------- New extensions can be written using the for_extension define form. Eg. define :for_extension grum(varlist, isfast); ... enddefine; In this example the extension grum has been declared. Ie. the construct: for var1, var2, ... varN grum .... fast_for var1, var2, ... varN grum .... Is now valid. The need for the variables varlist and isfast is described below, though these are ordinary variables and can be given any name. Reading in the rest of the loop construct and deciding what Poplog VM code to plant is then handled by the code that is in the body of the for_extension define form. Autoloading is supported which means that these extensions need not take up space until required. Two arguments are placed on the stack before this code is called: varlist a list of the variables following for or fast_for isfast a boolean which is true if fast_for was used, false otherwise. If isfast is true, code that runs quickly without doing normal checking may be planted. It is up to the user to ensure that such uses involve no serious risks. (See HELP * SLOWPROCS, REF * FASTPROCS for more information on checking and non-checking procedures) For example, at compile time the construct - fast_for item1, item2 grum | struct1, struct2 do - invokes the code with the list [item1 item2] and the boolean value true on the stack, with proglist set to the marked position. It is up to the user to decide whether to make the fast_ version (ie. when isfast is true) do anything different. ----------------------------------------------------------------------- 4 Predefined General Utilities ----------------------------------------------------------------------- Several keywords are catered for without users having to define them, these were described in section 2. Additional predefined facilities are described below. In particular there is a general subscriptor mechanism from which in_vectorclass and in_subscripted etc. are derived. 4.1 Using class_subscr_loop to Define New for-forms ---------------------------------------------------- The forms in_vectorclass and in_subscripted described above are defined as closures of the more general procedure: class_subscr_loop(varlist, isfast, index, subscrpdr); The first two arguments are as before. index is either a word or false. If it is a word then this is taken as the name of the variable to be used as the index counter. This can make the index counter visible to user programs. If it is false then the compiler will use a hidden variable as the counter. subscrpdr is the procedure for getting the class subscripting procedure out of the datakey of the vectorclass in question. Some form of closure of this procedure is all that is needed to form an efficient vector-type iteration construct. The form in_vectorclass can be defined thus: uses class_subscr_loop; define :for_extension in_vectorclass with_nargs 2; class_subscr_loop(false, class_fast_subscr); enddefine; and in_subscripted can be defined: define :for_extension in_subscripted with_nargs 2; class_subscr_loop(false, class_apply); enddefine; These two are probably the only instantiations that make sense for class_subscr_loop. If fast_for is used (isfast is therefore true,) then only the length of the first vector is considered when finding out how many times to iterate, as illustrated previously. 4.2 Using subscr_loop ---------------------- The in_vector form, more efficient than in_vectorclass, is defined using a closure of the more general procedure: subscr_loop(varlist, isfast, index, subscrpdr, checkpdr) The first four arguments are as before. checkpdr is a checking procedure which must mishap if the data to be subscripted is of the wrong class. A consequence of this is that the subscripting procedure subscrpdr can be of the fast variety. A closure of this procedure is all that is needed to form a vector-type iteration construct which is runs slightly faster than the in_vectorclass form. So in_vector could be defined as: uses subscr_loop; define lconstant check_vector(item); lvars item; unless isvector(item) then mishap(item, 1, 'VECTOR NEEDED') endunless enddefine; define :for_extension in_vector with_nargs 2; subscr_loop(false, fast_subscrv, check_vector); enddefine; When isfast is true, the checking procedure does not get run, and there are the same consequences that applied to class_subscr_loop. 4.3 Adding with_index Hooks ---------------------------- The define form with_index_hook can be used to define hooks for the with_index style of vector type iteration. Eg. define :with_index_hook in_vector with_nargs 3; subscr_loop(fast_subscrv, check_vector); enddefine; is used to define the construct: - for vars with_index ivar in_vector | exprs do ... - endfor; Simply the body of the define-form must define a procedure of three arguments: varlist, isfast and index. The functions of these variable are as described above in the description of class_subscr_loop. This procedure will be called with varlist set to the list of loop variables vars, isfast will be set to true or false depending on whether fast_for or for respectively was used to open the construct, and index is set to the index variable ivar. proglist will be set to the marked position. ----------------------------------------------------------------------- 5 fast_for Details ----------------------------------------------------------------------- Using fast_for often gains speed just by switching off checking. Also, for vector-type iteration, the non-fast forms compare the lengths of all the vectors and uses the shortest one to determine the number of iterations required. This comparison is avoided if fast_for is used. Instead only the length of the first vector is examined. The rules that apply to fast_appproperty apply to the fast version of in_property. --- C.all/help/for_form --- Copyright University of Sussex 1996. All rights reserved.