Previous Page
Next Page

14.6. List Coercions

Anything may be coerced to a list . How it is treated depends on what you start with:


A list

The result is identically the same list.


A record

The result is a list of the values from the record:

set R to {name:"Matt", age:51}
R as list -- {"Matt", 51}


Anything else

The result is a list of one item, that item being the thing you started with.

Coercion to a list is very useful for making sure you have a list; if the thing you start with isn't a list, it becomes one, and if it is a list, it is unchanged. Recall, however, that this coercion might not work if the thing you start with belongs to an application, because that application might not implement it (see "Coercion by a Scriptable Application," earlier in this chapter).

Officially you can't coerce a list to a record, but there's a trick for doing it using a second level of evaluation. (Consider the warnings at "Second-Level Evaluation" in Chapter 19 before resorting to this trick; it involves a lot of overhead.) The value of every odd item of the list (which should be a string) becomes the name of a record item, whose value in turn is the corresponding even item of the list:

on listToRecord(L)
    script myScript
        return {«class usrf»:L}
    end script
    return run script myScript
end listToRecord
set R to listToRecord({"name", "haha", "age", 51})
R -- {|name|:"haha", age:51}

To understand the trickery involved here, see "Record" in Chapter 13. Observe that because we are forming a user record, the term name ends up in pipes; it is not the predefined name property, and its value cannot be accessed without pipes around the term name.

A list of one item may be coerced to the datatype of that item, and the result will be that item. Of course, the result can then be coerced to any datatype that it can be coerced to, so you can also coerce a list of one item to that datatype in a single step. For example:

{true} as string -- "true"

That's possible because the list of one boolean is first coerced to a boolean, and a boolean can be coerced to a string.

A list of multiple items may be coerced to a string, provided that every individual item may be coerced to a string. This coercion is performed using the current value of the text item delimiters. (See "String" in Chapter 13.) The rule is that every item of the list is coerced to a string, and the resulting strings are joined into a single string with the text item delimiters value between each pair. The text item delimiters value can be the empty string; this is in fact its default value. If an item of the list is a list, it is coerced to a string by the same rule; so this coercion in effect flattens a list, to any depth, into a single string.

So, assuming the text item delimiters is the empty string:

{"Manny", {"Moe", "Jack"}} as string -- "MannyMoeJack"

Or, assuming the text item delimiters is a comma followed by a space:

{"Manny", {"Moe", "Jack"}} as string -- "Manny, Moe, Jack"

A common technique is to transform a string to a list (using text items or some other element), process the list in some way, and then transform it back to a string by coercion. This technique can help you perform string manipulations, making up somewhat for the fact that AppleScript's native string functionality is so thin. (Also, a list, unlike a string, can be mutated in place, so operating on a list can be faster and more efficient.) As a simple example, here's how to get the containing folder from a Macintosh pathname:

on containingFolder(s)
    set text item delimiters to ":"
    return (items 1 thru -2 of text items of s) as string
end containingFolder
containingFolder("feathers:Users:mattneub:Documents:someDoc")
-- "feathers:Users:mattneub:Documents"

A list can be implicitly coerced to a string. (See Chapter 15 for the situations in which this can occur.) Beware of allowing this to happen without taking into account the current state of the text item delimiters.


A common complaint is that with display dialog you can't display a list as a list (that is, as it would be displayed as a result by the Script Editor). A workaround is to coerce the list to something impossible, such as a record, and capture the resulting error message. This trick is based upon the observation that the error message has somehow performed precisely the coercion you had in mind:

on coerceForDisplay(L)
    try
        L as record
    on error s
        set c to characters of s
        set u to count c
        repeat with i from 1 to u
            if item i of c is "{" then exit repeat
        end repeat
        repeat with j from u to 1 by -1
            if item j of c is "}" then exit repeat
        end repeat
        set text item delimiters to ""
        return (items i thru j of c) as string
    end try
end coerceForDisplay
display dialog coerceForDisplay({"pep", 3, {"Mannie", "Moe", "Jack"}})
-- {"pep", 3, {"Mannie", "Moe", "Jack"}}


Previous Page
Next Page