// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-scope.html
\meta {keywords} {qmltopic}
\title Scope and Naming Resolution
\brief overview of scope and naming resolution
\ingroup explanations-programminglanguages

QML property bindings, inline functions, and imported JavaScript files all
run in a JavaScript scope.  Scope controls which variables an expression can
access, and which variable takes precedence when two or more names conflict.

As JavaScript's built-in scope mechanism is very simple, QML enhances it to fit
more naturally with the QML language extensions.

\section1 JavaScript Scope

QML's scope extensions do not interfere with JavaScript's natural scoping.
JavaScript programmers can reuse their existing knowledge when programming
functions, property bindings or imported JavaScript files in QML.

In the following example, the \c {addConstant()} method will add 13 to the
parameter passed just as the programmer would expect irrespective of the
value of the QML object's \c a and \c b properties.

\qml
QtObject {
    property int a: 3
    property int b: 9

    function addConstant(b) {
        var a = 13;
        return b + a;
    }
}
\endqml

That QML respects JavaScript's normal scoping rules even applies in bindings.
This totally evil, abomination of a binding will assign 12 to the QML object's
\c a property.

\qml
QtObject {
    property int a

    a: { var a = 12; a; }
}
\endqml

Every JavaScript expression, function or file in QML has its own unique
variable object.  Local variables declared in one will never conflict
with local variables declared in another.

\section1 Type Names and Imported JavaScript Files

\l {QML Documents} include import statements that define the type names
and JavaScript files visible to the document.  In addition to their use in the
QML declaration itself, type names are used by JavaScript code when accessing
\l {Attached Properties and Attached Signal Handlers}{attached properties} and enumeration values.

The effect of an import applies to every property binding, and JavaScript
function in the QML document, even those in nested inline components.  The
following example shows a simple QML file that accesses some enumeration
values and calls an imported JavaScript function.

\qml
import QtQuick 2.0
import "code.js" as Code

ListView {
    snapMode: ListView.SnapToItem

    delegate: Component {
        Text {
            elide: Text.ElideMiddle
            text: "A really, really long string that will require eliding."
            color: Code.defaultColor()
        }
    }
}
\endqml

\section1 Binding Scope Object

An object which has a \l{Property Binding}{property binding} is known as the
binding's \e{scope object}.  In the following example, the \l Item object is
the binding's scope object.

\qml
Item {
    anchors.left: parent.left
}
\endqml

Bindings have access to the scope object's properties without qualification.
In the previous example, the binding accesses the \l Item's \c parent property
directly, without needing any form of object prefix.  QML introduces a more
structured, object-oriented approach to JavaScript, and consequently does not
require the use of the JavaScript \c this property.

Care must be used when accessing \l {Attached Properties and Attached Signal Handlers}
{attached properties} from bindings due
to their interaction with the scope object.  Conceptually attached properties
exist on \e all objects, even if they only have an effect on a subset of those.
Consequently unqualified attached property reads will always resolve to an
attached property on the scope object, which is not always what the programmer
intended.

For example, the \l PathView type attaches interpolated value properties to
its delegates depending on their position in the path.  As PathView only
meaningfully attaches these properties to the root object in the delegate, any
sub-object that accesses them must explicitly qualify the root object, as shown
below.

\qml
PathView {
    delegate: Component {
        Rectangle {
            id: root
            Image {
                scale: root.PathView.scale
            }
        }
    }
}
\endqml

If the \l Image object omitted the \c root prefix, it would inadvertently access
the unset \c {PathView.scale} attached property on itself.

\section1 Component Scope

Each QML component in a QML document defines a logical scope.  Each document
has at least one root component, but can also have other inline sub-components.
The component scope is the union of the object ids within the component and the
component's root object's properties.

\code
Item {
    property string title

    Text {
        id: titletype
        text: "<b>" + title + "</b>"
        font.pixelSize: 22
        anchors.top: parent.top
    }

    Text {
        text: titletype.text
        font.pixelSize: 18
        anchors.bottom: parent.bottom
    }
}
\endcode

The example above shows a simple QML component that displays a rich text title
string at the top, and a smaller copy of the same text at the bottom.  The first
\c Text type directly accesses the component's \c title property when
forming the text to display.  That the root type's properties are directly
accessible makes it trivial to distribute data throughout the component.

The second \c Text type uses an id to access the first's text directly.  IDs
are specified explicitly by the QML programmer so they always take precedence
over other property names (except for those in the \l {JavaScript Scope}).  For
example, in the unlikely event that the binding's \l {Binding Scope Object}{scope
object}  had a \c titletype property in the previous example, the \c titletype
id would still take precedence.

\section1 Component Instance Hierarchy

In QML, component instances connect their component scopes together to form a
scope hierarchy.  Component instances can directly access the component scopes of
their ancestors.

The easiest way to demonstrate this is with inline sub-components whose component
scopes are implicitly scoped as children of the outer component.

\qml
Item {
    property color defaultColor: "blue"

    ListView {
        delegate: Component {
            Rectangle {
                color: defaultColor
            }
        }
    }
}
\endqml

The component instance hierarchy allows instances of the delegate component
to access the \c defaultColor property of the \c Item type.  Of course,
had the delegate component had a property called \c defaultColor that would
have taken precedence.

The component instance scope hierarchy extends to out-of-line components, too.
In the following example, the \c TitlePage.qml component creates two
\c TitleText instances.  Even though the \c TitleText type is in a separate
file, it still has access to the \c title property when it is used from within
the \c TitlePage.  QML is a dynamically scoped language - depending on where it
is used, the \c title property may resolve differently.

\qml
// TitlePage.qml
import QtQuick 2.0
Item {
    property string title

    TitleText {
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property int size
    text: "<b>" + title + "</b>"
    font.pixelSize: size
}
\endqml

Dynamic scoping is very powerful, but it must be used cautiously to prevent
the behavior of QML code from becoming difficult to predict.  In general it
should only be used in cases where the two components are already tightly
coupled in another way.  When building reusable components, it is preferable
to use property interfaces, like this:

\qml
// TitlePage.qml
import QtQuick 2.0
Item {
    id: root
    property string title

    TitleText {
        title: root.title
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        title: root.title
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property string title
    property int size

    text: "<b>" + title + "</b>"
    font.pixelSize: size
}
\endqml

\section2 Do Not Reference Root Object \c id From Other QML Components

Avoid accessing the \c id of a root object from outside the QML file where
it is defined. \c id values are only valid within the same document, and relying
on them from other components breaks encapsulation and component boundaries.

\code
// Main.qml
import QtQuick

Item {
    id: root
    CustomItem { }
}

// CustomItem.qml
import QtQuick

Rectangle {
    width: root.width
    height: root.height / 2
    color: "red"
}
\endcode

In the above example, \c root is not declared in \c CustomItem.qml. The code still works
because \c CustomItem is instantiated in a context where \c root exists, which is
permitted by QML’s dynamic scoping rules. However, this creates an implicit dependency on
the outer scope, making the component unreliable and harder to reuse when it is loaded
dynamically or used in a different context. This pattern can also lead to subtle bugs.
For example, if another object in the scope chain uses the same \c id, it may shadow the
expected one, resulting in unexpected behaviour.

To make components reliable and reusable, access external state only through
explicit properties, property aliases, or signals. Avoid relying on outer-scope
\c id values.

The following example replaces dynamic scoping with an explicit component API.

\code
// Main.qml
import QtQuick
import QtQuick.Window

Window {
    id: root
    width: 400
    height: 300
    visible: true

    CustomItem {
        width: root.width
        height: root.height
        boxColor: "blue"
    }
}

// CustomItem.qml
import QtQuick

Item {
    id: container
    property alias boxColor: rect.color

    Rectangle {
        id: rect
        width: container.width
        height: container.height / 2
        color: "red"
    }
}
\endcode

Apply the same rule to all internal objects declared with an \c id inside a component.

\code
// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCounter.count);
    }
}
\endcode

In the above example, accessing the \c id \c internalCounter from another QML file causes a
\c ReferenceError because an \c id is document-local and cannot be accessed outside the
QML file in which it is declared.

If an internal object needs to expose state or behaviour, expose it explicitly through properties,
property aliases, or signals.

The following example exposes the internal state through an explicit component API instead of
relying on direct access to a document-local \c id.

\code
// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
    property alias internalCount: internalCounter.count
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCount);
    }
}
\endcode

This helps maintain clear component boundaries and supports better scalability
and testability.

\section1 Overridden Properties

QML permits property names defined in an object declaration to be overridden by properties
declared within another object declaration that extends the first.  For example:

\qml
// Displayable.qml
import QtQuick 2.0
Item {
    property string title
    property string detail

    Text {
        text: "<b>" + title + "</b><br>" + detail
    }

    function getTitle() { return title }
    function setTitle(newTitle) { title = newTitle }
}

// Person.qml
import QtQuick 2.0
Displayable {
    property string title
    property string firstName
    property string lastName

    function fullName()  { return title + " " + firstName + " " + lastName }
}
\endqml

Here, the name \c title is given to both the heading of the output text for Displayable,
and also to the honorific title of the Person object.

An overridden property is resolved according to the scope in which it is referenced.
Inside the scope of the Person component, or from an external scope that refers
to an instance of the Person component, \c title resolves to the property
declared inside Person.qml.  The \c fullName function will refer to the \c title
property declared inside Person.

Inside the Displayable component, however, \c title refers to the property
declared in Displayable.qml.  The getTitle() and setTitle() functions, and the
binding for the \c text property of the Text object will all refer to the \c title
property declared in the Displayable component.

Despite sharing the same name, the two properties are entirely separate.  An
onChanged signal handler for one of the properties will not be triggered by
a change to the other property with the same name.  An alias to either property
will refer to one or the other, but not both.

\section1 JavaScript Global Object

QML disallows type, id and property names that conflict with the properties
on the global object to prevent any confusion.  Programmers can be confident
that \c Math.min(10, 9) will always work as expected!

See \l {JavaScript Host Environment} for more information.

*/
