While it is possible to create templates without a good understanding of scope, it may be helpful to understand how liquid variables are scoped in order to create truly reusable template or integrate smoothly with code written by other developers.
Put as simply as possible, scope is the context in which any particular object is accessible.
Scopes may be nested similarly to how partial templates may be nested - with a root scope which may contain child scopes, each of which may also contain child scopes.
Any object on a parent scope is accessible in all child scopes unless the child scope has another object by the same name.
Object on a child scope, however, are no longer accessible on the parent scope once the child scope is complete.
Additionally, if an object exists by the same name on both a parent and a child scope, only the object on the child scope will be accessible until the child scope is complete.
Child scopes are created every time you open up a new block tag (eg: {% if %}, {% for %}, {% capture %}, etc...) or include a partial template. The child scope is completed when the block tag is closed (eg: {% endif %}, {% endfor %}, {% endcapture %}, etc...) or the partial template is finished rendering.
The liquid developer documentation should indicate which tags create child scopes (eg: "The case tag creates a new child scope." in the {% case %} documentation).
On the most basic level, if you save objects on a child scope, they will not be available when the child scope is completed. This means that if you attempt to retrieve a value inside an {% if %} statement, it will be unavailable after the matching {% endif %} tag unless you save that value on a parent scope.
On a more advanced level, if you are creating reusable templates that you want to allow other people to use without messing up their templates while still using readable variable names, all you need to do is be careful to save your objects on the child scope and when your template is done rendering it will not have disturbed any of the parent template objects or variables. For example: you could use the variable "start" even if the same variable is used by a parent template, and when your template is done rendering the "start" object would be unchanged inside its scope.
Ahh. Now we get to the point of this discussion. There are three different ways to save objects on the scope which are designed to give you full control over where objects are saved without becoming overly complicated:
There are three ways that variables may be defined and saved to a scope:
When writing templates, the best practice is to utilize var and set wherever possible and reserve assign for cases where it is specifically necessary. By restricting your variables to the scopes where they are used, you make your code more friendly and compatible with code written by other developers who may wish to use the same variable names.
Note that there is currently no way to unset a variable from a scope other than using the assign method to define the variable at the root scope. Setting a variable to null does not remove it from the scope.