The rules for the string built-ins (Feel.Analysis.Images, D-161, step C): contains, ends with, lower case,
matches, replace, split, starts with, string join, string length, substring, substring after,
substring before and upper case.
A rule gives the whole type of the result, Null included, from the types of the arguments. Each argument is read for the
strings (or the numbers) it can be, whether it can be null, and whether it can be something that the function turns down
with null: a value of another kind, or a list, which is its element if it has one and null if it has not (section
10.3.2.9.4). Then the result is found in one of three ways, from the exact to the kind:
- The function is run on the strings of a finite set. A set of strings that is a list (
{"a", "b"}) gives the values of an argument, and the function itself (Feel.Builtin.call/3, so that nothing of it is written twice) is called on every combination of the values of the arguments.string length(s)for{"a", "b", "c"}isnumber = 1,upper case(s)for{"a", "b"}is{"A", "B"},matches(s, "a(")isNull, since the pattern is not one. A product of more than 64 combinations is not run. The run has a small budget, as an analysis has to stay cheap whatever the model has written (a regular expression of 10,000 steps, a result of 100,000 bytes): a call that passes it ends the run and has no value, and then the signatures give the type, as they do for a call on constants that the analysis cannot evaluate (D-80). - The kind, with what is known. For every string, or a set with an interval in it (which has as many strings as
there are), or a product that is too large, the result is the kind of the function:
string length(s)is a number in[0..max],contains(s, m)isboolean. What the other arguments say is used: every string has the empty string in each place, socontains(s, "")istrueandsubstring before(s, "")is""; a set of strings that has not the empty string has at least one character, so its length is in[1..max]; and the patterns, the replacements and the flags that are a finite set are read once (Feel.Runtime.Regex), somatches(s, "a+")isboolean, andreplace(s, "a*", "b")isNull. substringruns the function on the string and on the integers that the numbers can be. A start is cut off at its fraction, and a start or a length is out of range past either end of the string, so the integers that make a difference are those within one of the ends and the first beyond them: a set of numbers as wide asnumberis a few calls.
string join is read by the kinds of its list: its elements are strings or null (which are left out), and a string is a
list of one string.
What is null
Null is in the type only if some arguments make the run give it. That is a null argument and an argument of another
kind, but for the arguments that are left out when they are null (the flags of matches and replace, the delimiter of
string join, and the length of substring), and what the function itself turns down:
| Function | null for |
|---|---|
substring | a start of 0 or past either end of the string; a length under 1 or past what is left |
matches | a pattern or flags that are not in the dialect of XPath |
replace | the same, a pattern that matches the empty string, a replacement with a $ or a \ that means nothing |
split | the same, but the empty string has no parts, whatever the pattern is |
string join | an element of the list that is neither a string nor null |
| the others | nothing |
What is broader than exact
The type is a superset where it cannot be exact, and never smaller. Where the set of strings has an interval or the product
is too large, the strings of the result are string (upper case(s) is not every string, but no set says which) and the
booleans are boolean (contains(s, "a") for a s that is only the strings from "a" to "a" is true). The shortest
string of a set with an interval that has not the empty string is taken to have one character, which it has but for a set
such as ["ab".."ac"]; and a pattern, a replacement or flags that are such a set are taken to have a string that the
function turns down, which is so unless the set is all of one class. The lists of string join have no length in their
type, so the result of one is string. More than 8 different lists as the results of split are one list of their parts,
and more than 2,048 calls of substring are string.