Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
1

A question for scripters: Do you use recursion and, if so, what for?

Guide ,
Jan 09, 2022 Jan 09, 2022

A short while ago I used recursion to search for pathItems in nested groupItems in the selection collection.  The only other time I can think of where I tried recursion was to loop through sublayers, which was a long time ago (since I don't use sublayers). This made me think about recursion, which I was never comfortable with and may want to explore further.  It made me wonder if there are any other uses for it in AI scripting. So my question is: Do you use recursion and, if so, what for?  (Please note that I'm talking about scripting with JavaScript.)  

 

Thanks in advance.

 

TOPICS
Scripting
891
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 4 Correct answers

Community Expert , Jan 09, 2022 Jan 09, 2022

Hi, I use it for both scenarios you mention, to dig items inside groups/compoundPaths/subLayers.

 

In general I use recursion when I need to go thru items in a container, but the container has other containers as well.

 

Aside from the examples above, recursion is needed to get files in folders and subfolders

Translate
Community Expert , Jan 09, 2022 Jan 09, 2022

Hi @femkeblanco, I use recursion when traversing structures that are self-similar at different levels. I think the example you gave is probably the most common one—traversing those parts of the object model that exhibit self-similarity: a pageItem (a groupItem) can contain other pageItems, even groupItems, to an arbitrary depth. Each level looks identical to the others, except for the root (which has no parent) and a leaf (which has no children).

So if you notice self-similarity at different "lev

...
Translate
Valorous Hero , Jan 09, 2022 Jan 09, 2022

Recursion was frightening to me at first because I saw an example at the very beginning which somehow returned a value form the recursive function. But soon after I saw another example where they pushed a value to a variable outside of the recursive function, and that cleared it up.
Like everyone said, the essence of such a function is a mechanism that can launch itself on an item, so if that item can have nested properties which can be in turn treated with the same function, this function will r

...
Translate
Enthusiast , Jan 10, 2022 Jan 10, 2022

A lot of great answers here with reasons why you should but just to cover all aspects, why you shouldn't:

 

  • Recursive functions only implicitly stop execution which can cause unexpected behavior if using sync and async code simultaneously or when using async recursion (admittedly not relevant for JSX scripting)
  • Recursion is exponentially harder to debug and understand the full boundaries of while reading either for someone else or your future self a few months from now
  • Recursion is exponentially mor
...
Translate
Adobe
Community Expert ,
Jan 09, 2022 Jan 09, 2022

Hi, I use it for both scenarios you mention, to dig items inside groups/compoundPaths/subLayers.

 

In general I use recursion when I need to go thru items in a container, but the container has other containers as well.

 

Aside from the examples above, recursion is needed to get files in folders and subfolders

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 09, 2022 Jan 09, 2022

Yes same. And when I have to use recursion with the file system it freaks me out that I might have the logic wrong and mess things up badly! I think the File and Folder objects handle the recursion for most operations now days which is great. 
- Mark

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 09, 2022 Jan 09, 2022

Hi @femkeblanco, I use recursion when traversing structures that are self-similar at different levels. I think the example you gave is probably the most common one—traversing those parts of the object model that exhibit self-similarity: a pageItem (a groupItem) can contain other pageItems, even groupItems, to an arbitrary depth. Each level looks identical to the others, except for the root (which has no parent) and a leaf (which has no children).

So if you notice self-similarity at different "levels" in any structure, and you need to comprehend that structure somehow, recursion might be appropriate.

To contrast, if you want to find the root document of a page item, a simple loop is adequate, something like: while (item.parent.typename != 'Document') item = item.parent because in this case you are only traversing one branch of the tree. So recursion could be useful in cases where you want to easily traverse multiple branches of a tree structure, eg. finding all bottom-level page items of a groupItem. Because the groupItem could itself contain mutiple groupItems you are needing to traverse multiple branches to find the leaves (the bottom-level page items of each branch). To be honest I don't really know how to do this without recursion.

I am interested in this topic too, and my use of recursion in scripting is probably just scratching the surface! Thanks for the question.  🙂 

- Mark

 

Edit: typo: root which has *no* parent.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Valorous Hero ,
Jan 09, 2022 Jan 09, 2022

Recursion was frightening to me at first because I saw an example at the very beginning which somehow returned a value form the recursive function. But soon after I saw another example where they pushed a value to a variable outside of the recursive function, and that cleared it up.
Like everyone said, the essence of such a function is a mechanism that can launch itself on an item, so if that item can have nested properties which can be in turn treated with the same function, this function will run on them all and their children, to "infinity".

 

  • mainly used to run a method on a data structure whose amount of nested items is unknown and could be any amount, and the item of interest this method is concerned about could be located at any level of nesting, so it's got to be prepared to run through them all.


To construct a recursive function, one must think of a function that can take in some input and launch itself on it. Most common generic situation is handling of folders and files. If you think of a file or folder object as a "node" which can be either a file or folder, a recursive function can get an input of a folder and run through its children to do something which discriminates between whether a child is a folder or a file object. If the object is a folder, the same function is launched on that folder, but if it's a file then something else happens that takes care of the file.
Here is an example where you may have a folder structure and at some folder there might be a text file named a certain something. Supposing the goal is to obtain the file "test.txt" from a structure which looks like this:

Folder "root"
  -Folder "folder_1"
      -File "abc.txt"
        -Folder "nested_folder_1"
            -Folder "nested_folder_1_1"
            -File "test.txt"
  -Folder "folder_2"

You may want to make some function that you want to pass the Folder object "root" and a string to get any file name to and get the File object "test.txt" from. Keep in mind that you don't know what this structure is at run-time, so it could be all switched around.
This function would look something like:

function getMyTextFile (startFolder, fileName) {
    // What goes here?
}

What goes in the comment? I found the easiest way to get an item from a nested structure of items is to create a function-scoped variable to add things to at the top of the method and then create an inner function that is the actual recursive function.

function getMyTextFile (startFolder, fileName) {
    var foundFile;
    function folderSearch (folderOrFile) {
        if (foundFile != undefined) {
            return; // stop inefficient traversing in case the file was already found by previous run of this function.
        }
        if (folderOrFile instanceof Folder) {
            var allFiles = folderOrFile.getFiles();
            Array.from(allFiles).forEach(function (m) { // these methods are accomplished by using ES3 polyfills found online
                folderSearch(m); // send another instance of this function on its way to work on this 'node'.
            });
        } else { // This is a file object, do the part which compares the file name to the fileName input.
            if (decodeURI(fileOrFolder.name) == fileName) { // compare the names...
                foundFile = fileOrFolder; // BINGO, we found the file.
                // Now this function should no longer run due to the condition at the very top.
            }
        }
    }
    folderSearch(startFolder); // launches the recursive method and it will reach all branches of the node tree.
    return foundFile; // return the function-scoped result variable, if it wasn't set from within the recursive method, it will return undefined. (you can also initialize this to null or false, or anything else you wish as default return data).
}


Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Jan 10, 2022 Jan 10, 2022

Thanks all for the thoughtful answers.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jan 10, 2022 Jan 10, 2022

A lot of great answers here with reasons why you should but just to cover all aspects, why you shouldn't:

 

  • Recursive functions only implicitly stop execution which can cause unexpected behavior if using sync and async code simultaneously or when using async recursion (admittedly not relevant for JSX scripting)
  • Recursion is exponentially harder to debug and understand the full boundaries of while reading either for someone else or your future self a few months from now
  • Recursion is exponentially more error and bug-prone
  • Recursion is exponentially slower because it adds to the callstack per lookup and descendant, resulting in several redundant function calls and loops

 

The only time recursion should be used (at least for me in my own code) is when necessary: we're working with nestable objects or dynamic user-generated content and we cannot account for the complexity of depth/nesting, we're not using a rigid structure. This could be pageItem contents or folder/files contents as noted or it could be an HTML DOM where recursion is necessary to ensure accurate non-shallow results, but it could also be completely gratuitous and a way to shoot yourself in the foot multiple times if you try implementing recursion in cases when unneeded.

 

For practice, there's no harm in playing with recursion liberally no matter what the case is just to refine your own skills and understanding. However for production since recursion can be such a double-edged sword, you have to consider the fact that adding it can be the source of several near-future patches and bugs (from unexpected parameters fed into your recursive function args) or that using it in a document with thousands of entries might take 10x longer to do the same thing as a shallow lookup.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Jan 11, 2022 Jan 11, 2022
LATEST

Thanks for the advice. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines