From ad278c091560d04f969ea07f170bf70b15852733 Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 09:55:37 +0100 Subject: [PATCH 1/8] added What is an Object content --- .../working-with/objects/what-is-an-object.md | 190 ++++++++++++++++-- data/urls.toml | 3 + 2 files changed, 179 insertions(+), 14 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md index e58c95968..e00081f45 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md @@ -1,44 +1,206 @@ --- title: "What is an Object?" linkTitle: "What is an Object?" -description: "Information regarding what an object is." +description: "Information regarding what an object is, how it relates to data types, and how objects are used in flows." weight: 1 --- # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO: +In C# and {{% ctx %}}, an **object** is a specific instance of a [data type][] at runtime—the actual value stored in a [variable][] or passed through a [block property][]. A **data type** is the definition that describes what kind of value an object can hold and what members (properties, methods, and so on) it exposes. + +Every object in {{% ctx %}} ultimately derives from the [Object][] data type (`System.Object`). That makes `Object` the common base for all other types, from simple scalars such as [Int32][] and [String][] to [collections][collection] and platform types such as [Command][]. + +| Term | Meaning | Example | +| --- | --- | --- | +| Data type | The definition or blueprint | `String`, `List`, `Structure` | +| Object | A runtime instance of a data type | `"Hello"`, a list containing `[1, 2, 3]`, a `Structure` with named fields | + +For how data types are classified (basic, complex, value, and reference), see [What is a Data Type?][]. For casting, equality, and text conversion, see the other pages in this section. + +## Data types and objects + +A data type tells the platform what shape data has. An object is the live data that exists while a [flow][] runs. + +* `Int32` is a data type; the number `42` stored in a variable is an `Int32` object (or more precisely, a boxed or typed value of that type). +* `List` is a data type; the list instance returned from a block is an object of that type. +* [Structure][] is a data type; `{ "Name": "Ada", "Count": 3 }` is a `Structure` object. + +[Variables][] do not have their own data type—they are named containers that hold objects of any supported [data type][]. When a variable is used in a [block property][], {{% ctx %}} checks that the object it currently holds is compatible with the property's expected type. See [Variable Typing][] in [What is a Variable?][]. + +## The Object data type + +The [Object][] data type (`System.Object`, C# alias `object`) is the root type in .NET. Any data type can be used where an `Object` is required, because all types derive from `Object`. + +| | | +| --- | --- | +| **Full name** | `System.Object` | +| **Default value** | `null` | +| **Can be used as** | `Object`, [dynamic][] | + +You will rarely create a bare `Object`. In practice you create and work with more specific types—`String`, `DateTime`, `Dictionary`, and so on—that inherit from `Object`. If needed, an empty object can be created in the [Expression Editor][] with: + +```csharp +new Object() +``` + +For full details, property editor support, and remarks, see the [Object][] data type page. + +### Object vs dynamic + +[Object][] and [dynamic][] behave the same in most situations. The important difference is how you use the value after it has been stored: + +* **`Object`** — if the value must be used as its original type, you must [cast][] it back (for example `(Int32)($)MyObject`). +* **`dynamic`** — member access and operations are resolved at runtime without an explicit cast. + +In flows, `dynamic` is more commonly encountered than `Object` when a block accepts or returns any data type, or when a [heterogenous][] collection (for example `[1, "Text", true]`) is saved to a variable. See [Object Casting][] for implicit and explicit casts. + +### When Object or dynamic appears in flows -- What is the difference between an object and a data type? - - Data Type is the definition, Object is an instance of that definition -- Explain Object Data Type, base foundation of classes +`Object` or `dynamic` is typically used when: + +* An [Input][], [InputOutput][], or [Output][] block property can accept or return any data type. +* A [collection][] holds items of different data types and the result is stored in a variable (for example `List` or `Dictionary`). +* A generic block property such as `TObject` is used—for example on [Copy Object][] or [Convert Object To Text][]. + +Block properties typed as `Object` use the [Expression Editor][] for inputs and the [Variable Editor][] for [InputOutput][] and [Output][] properties. The [Literal Editor][] is not available for `Object` inputs. + +## Value types and reference types + +Objects are either [value types][] or [reference types][], depending on their data type. This affects assignment, copying, and equality. + +| | Value type | Reference type | +| --- | --- | --- | +| Examples | [Int32][], [Boolean][], [DateTime][] | [String][], [List<TItem>][], [Structure][], [Command][] | +| Default | Non-null default (for example `0` for `Int32`) | `null` | +| Assignment via [Set Variable][] | Variables refer to **separate** instances | Variables can refer to the **same** instance | +| Equality | Compared by value | Compared by reference (with nuances in blocks; see [Object Equality][]) | + +When you assign one variable to another with [Set Variable][], a reference type object is shared: changes through either variable affect the same instance. To work with an independent copy, use [Copy Object][], which performs a deep copy (nested objects are copied too). + +Value type objects are always separate instances when assigned; [Copy Object][] can still be used when you need an explicit copy of a value held in a generic or `Object`-typed variable. + +## Working with objects in flows + +### Viewing objects at runtime + +When [debugging a flow][], the [Variables Viewer][] shows variable values. Simple values appear directly in the [Variables List][]; [complex data types][] and [collections][collection] show their type and item count (for example `Dictionary with 2 item(s)`). Select a variable to expand its contents in the [Variable Details Viewer][]. + +Non-collection complex types (for example [Command][] or [FlowException][]) may display as `Instance of Command` in the list until you open the details viewer. + +### Converting and serializing objects + +Objects are often converted to [String][] for logging, messages, or templates: + +* In expressions — `ToString()`, `Convert.ToString()`, [string interpolation][], or `String.Format()`. See [Converting Objects To Text][]. +* In blocks — [Convert Object To Text][] (format templates with `{Property}` placeholders) or JSON blocks such as [Convert Object To Json][] and [Convert Json To Object][]. + +Text conversion behaviour depends on the object's type; some types return a meaningful string, others return the type name unless a format provider or template is used. + +### Comparing objects + +Whether two objects are considered equal depends on whether they are value or reference types and whether comparison happens in C# expressions or in collection blocks. [List][] and [Dictionary][Dictionary<TKey, TItem>] blocks may compare reference types by reference first, then fall back to value equality. See [Object Equality][]. ## Remarks ### Known Limitations -TODO +None ## See Also ### Related Concepts -TODO +* [Object Casting][] +* [Object Equality][] +* [What is a Data Type?][] +* [What is a Variable?][] +* [Converting Objects To Text][] +* [Collections][] ### Related Data Types -TODO +* [Object][] +* [dynamic][] +* [Structure][] +* [List<TItem>][] +* [Dictionary<TKey, TItem>][] ### Related Blocks -TODO +* [Copy Object][] +* [Convert Object To Text][] +* [Convert Object To Json][] +* [Convert Json To Object][] +* [Set Variable][] ### External Documentation -TODO - -[All Blocks]: {{< url path="Cortex.Reference.Blocks.MainDoc" >}} +* [System.Object][MS Object] +* [Using type dynamic][MS dynamic] +* [Value types][MS Value Types] +* [Reference types][MS Reference Types] +* [Equality comparisons][MS Equality] + +[Object Casting]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.MainDoc" >}} +[Object Equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectEquality.MainDoc" >}} +[Converting Objects To Text]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.ConvertingObjectsToText.MainDoc" >}} +[Collections]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} +[collection]: {{< url path="Cortex.Reference.DataTypes.Collections.MainDoc" >}} +[heterogenous]: {{< url path="Cortex.Reference.Glossary.F-J.Heterogenous" >}} + +[What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[value types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.ValueTypes" >}} +[reference types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.ReferenceTypes" >}} +[complex data types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.ComplexDataTypes" >}} + +[What is a Variable?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variable Typing]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variables]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.MainDoc" >}} +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} + +[flow]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Flows.WhatIsAFlow.MainDoc" >}} +[debugging a flow]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Executions.ExecutionsInDevelopment.MainDoc" >}} + +[block property]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.MainDoc" >}} +[Input]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.Input" >}} +[InputOutput]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.InputOutput" >}} +[Output]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.Output" >}} + +[Expression Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.MainDoc" >}} +[Literal Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.LiteralEditor.MainDoc" >}} +[Variable Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.VariableEditor.MainDoc" >}} +[string interpolation]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.InterpolatedStrings" >}} +[cast]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.ExplicitCast" >}} + +[Object]: {{< url path="Cortex.Reference.DataTypes.All.Object.MainDoc" >}} +[dynamic]: {{< url path="Cortex.Reference.DataTypes.All.dynamic.MainDoc" >}} +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[Boolean]: {{< url path="Cortex.Reference.DataTypes.ConditionalLogic.Boolean.MainDoc" >}} +[DateTime]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTime.MainDoc" >}} +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} +[Structure]: {{< url path="Cortex.Reference.DataTypes.Collections.Structure.MainDoc" >}} +[List]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[Dictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Command]: {{< url path="Cortex.Reference.DataTypes.Data.Command.MainDoc" >}} +[FlowException]: {{< url path="Cortex.Reference.Exceptions.Flows.FlowException.MainDoc" >}} + +[Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} +[Convert Object To Text]: {{< url path="Cortex.Reference.Blocks.Objects.ConvertObject.ConvertObjectToText.MainDoc" >}} +[Convert Object To Json]: {{< url path="Cortex.Reference.Blocks.Json.ConvertJson.ConvertObjectToJson.MainDoc" >}} +[Convert Json To Object]: {{< url path="Cortex.Reference.Blocks.Json.ConvertJson.ConvertJsonToObject.MainDoc" >}} +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} + +[Variables Viewer]: {{< url path="Cortex.Guides.UserGuides.UserInterfaces.Gateway.Dev.FlowEditor.RightPanel.ExecutionViewer.VariablesViewer" >}} +[Variables List]: {{< url path="Cortex.Guides.UserGuides.UserInterfaces.Gateway.Dev.FlowEditor.RightPanel.ExecutionViewer.VariablesList" >}} +[Variable Details Viewer]: {{< url path="Cortex.Guides.UserGuides.UserInterfaces.Gateway.Dev.FlowEditor.RightPanel.ExecutionViewer.VariableDetailsViewer" >}} + +[MS Object]: {{< url path="MSDocs.DotNet.Api.System.Object.MainDoc" >}} +[MS dynamic]: {{< url path="MSDocs.DotNet.Api.System.dynamic.MainDoc" >}} +[MS Value Types]: {{< url path="MSDocs.CSharp.ValueTypes" >}} +[MS Reference Types]: {{< url path="MSDocs.CSharp.ReferenceTypes" >}} +[MS Equality]: {{< url path="MSDocs.CSharp.EqualityOperators" >}} diff --git a/data/urls.toml b/data/urls.toml index 7d7c5adc4..ed2d10e5b 100644 --- a/data/urls.toml +++ b/data/urls.toml @@ -1476,6 +1476,9 @@ [Cortex.Reference.Blocks.Microsoft365.Outlook.SendEmail.SendEmailUsingMicrosoft365] MainDoc = "/docs/reference/blocks/microsoft365/outlook/send-email/send-email-using-microsoft365-block" [Cortex.Reference.Blocks.Objects] + [Cortex.Reference.Blocks.Objects.CopyObject] + [Cortex.Reference.Blocks.Objects.CopyObject.CopyObject] + MainDoc = "/docs/reference/blocks/objects/copy-object/copy-object-block-1" [Cortex.Reference.Blocks.Objects.ConvertObject] [Cortex.Reference.Blocks.Objects.ConvertObject.ConvertObjectToText] MainDoc = "/docs/reference/blocks/objects/convert-object/convert-object-to-text-block-1" From f49811e723886c1f3f5f97a40f5e3110b8dcf72d Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 10:17:29 +0100 Subject: [PATCH 2/8] added content to Object Casting --- .../working-with/objects/object-casting.md | 190 ++++++++++++++++-- data/urls.toml | 13 +- 2 files changed, 188 insertions(+), 15 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md index 589b2e011..d0ba53b0f 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md @@ -2,49 +2,215 @@ title: "Object Casting" linkTitle: "Object Casting" description: "Information regarding casting an object to different data types." +weight: 2 --- # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO +**Casting** is the process of converting an [object][] from one [data type][] to another. In {{% ctx %}}, casting happens in [expressions][] (written in the [Expression Editor][]) and when a value is supplied to a [block property][] whose expected type differs from the value's current type. + +There are two kinds of cast: + +| Kind | When it happens | Expression syntax required? | +| --- | --- | --- | +| [Implicit cast][] | The platform converts automatically when no information is lost | No | +| [Explicit cast][] | You instruct the conversion, typically when data may be lost or the conversion is not guaranteed | Yes — `(TargetType)expression` | + +Which conversions are allowed for each [data type][] is documented on that type's reference page. Look in the **Summary** table for **Can be used as** (implicit) and **Can be cast to** (explicit). For expression syntax and examples, see [Casting expressions][] in the Expression Editor documentation. + +For the relationship between [Object][] and [dynamic][] when values are stored without a specific type, see [Object vs dynamic][] below and [What is an Object?][]. ## Implicit Cast -TODO +An **implicit cast** converts one [data type][] to another without requiring expression syntax. {{% ctx %}} performs implicit casts when the conversion is safe — that is, when no information is lost. + +Implicit casts occur in two main places: + +* **Block properties** — when a [variable][] or expression result is passed to a property that expects a wider or compatible type. For example, an [Int32][] value can be used where a [Double][] is required without writing a cast. +* **Expressions** — in some expression contexts, notably [string expressions][], non-[String][] values are implicitly converted to [String][] (for example when concatenating or interpolating text). + +To see which types a [data type][] can be implicitly used as, check **Can be used as** in that type's documentation. Common patterns include: + +* Numeric widening — for example, [Int32][] can be used as [Int64][], [Single][], or [Double][]. +* Upcasting to [Object][] or [dynamic][] — any [data type][] can be used where `Object` or `dynamic` is expected, because all types derive from [Object][]. +* Compatible type conversions — for example, [DateTime][] can be implicitly used as [DateTimeOffset][]. + +In the examples below, assume the variable `($)Int` has been set to `6`. + +| Context | Expression or usage | Result | Notes | +| --- | --- | --- | --- | +| Block property | Pass `($)Int` to a property of type [Double][] | `6.0` | [Int32][] is implicitly cast to [Double][] | +| String concatenation | `($)String1 + " " + ($)Int` where `($)String1` is `"hello"` | `"hello 6"` | `($)Int` is implicitly cast to [String][] | +| String interpolation | `$"{($)String1} {($)Int}"` | `"hello 6"` | Same implicit conversion to [String][] | +| Assignment widening | `Int16` value assigned where [Int32][] is expected | No cast needed | Entire [Int16][] range fits in [Int32][] | + +For further information, see [Implicit Conversions][]. ## Explicit Cast -TODO +An **explicit cast** converts one [data type][] to another when you use cast expression syntax: `(TargetType)expression`. Use an explicit cast when information might be lost, when narrowing a numeric type, or when recovering a more specific type from [Object][] or a base type. + +{{< figure src="/images/set-variable/set-variable-expression-casting.PNG" >}} + +Explicit casts can result in **loss of information** when the target type cannot represent the full value (for example, casting a [Double][] to [Int32][] truncates decimal places). They can also fail at runtime if the value is not compatible with the target type. + +To see which explicit casts are supported for a [data type][], check **Can be cast to** in that type's documentation. The table lists the target type and any value-range restrictions. + +In the examples below, assume the variable `($)Int` has been set to `6`. + +| Expression | Result | Notes | +| --- | --- | --- | +| `(DayOfWeek)($)Int` | `DayOfWeek.Saturday` | [Int32][] cast to an [Enum][]. Name is `"Saturday"`, value is `6` | +| `(Int16)($)Int` | `6` | [Int32][] cast to [Int16][] when the value is within the [Int16][] range | +| `(Int32)1.9` | `1` | [Double][] to [Int32][] — decimal places are lost | +| `(Char)97` | `'a'` | [Int32][] to [Char][] | +| `(Int32)($)ObjectVariable` | Depends on stored value | Recover the original type from an [Object][]-typed [variable][] | +| `(EmailMessagePriority)0` | `EmailMessagePriority.Normal` | Numeric value cast to an [Enum][] member | + +### Casting from Object and dynamic + +When a [variable][] holds a value as [Object][] or was returned from a block as [dynamic][], you may need an explicit cast before using type-specific members or passing the value to a property that expects a concrete type. + +| Variable contents | To use as [Int32][] | Notes | +| --- | --- | --- | +| [Object][] holding an `Int32` | `(Int32)($)MyObject` | Required for [Object][] | +| [dynamic][] holding an `Int32` | `($)MyDynamic` | No cast needed — member access is resolved at runtime | + +This difference is the main practical distinction between [Object][] and [dynamic][] in flows. See [Object vs dynamic][]. + +### Casting enums + +[Enum][] values can be cast to and from their underlying numeric type (typically [Int32][]). Casting a numeric value to an [Enum][] selects the member with that underlying value; casting an [Enum][] to a number returns the underlying value. See [Enum expressions][] and individual [Enum][] data type pages for examples. + +Casting alone cannot convert [String][] to an [Enum][] — use `Enum.Parse` or related methods instead. + +For further information, see [Explicit Conversions][] and [Cast expression (C# Reference)][MS Cast Expression]. ## Object vs dynamic -TODO +[Object][] (`System.Object`) and [dynamic][] are interchangeable for storage: any [data type][] can be assigned to either. The difference appears when you **use** the value afterward. + +| | [Object][] | [dynamic][] | +| --- | --- | --- | +| Member access | Not available until you cast to the actual type | Resolved at runtime without a cast | +| Typical in flows | Less common | More common for generic block [Input][], [Output][], and [InputOutput][] properties | +| Recovering original type | Explicit cast required — e.g. `(Int32)($)MyObject` | Usually not required | + +In practice, blocks that accept or return any [data type][] usually expose [dynamic][]. Exception-handling blocks may return [dynamic][] so you can access exception properties without casting; you can still cast to a specific exception type when you need stricter typing during debugging. + +For full details, see the [Object][] and [dynamic][] data type pages and [What is an Object?][]. ## Remarks +### Where casting happens + +Casting is not limited to the [Expression Editor][]. It also applies when: + +* A [variable][] is bound to a [block property][] whose expected type differs from the variable's current contents (implicit cast when supported). +* An expression is evaluated for an [Input][] property. +* A value is written to an [InputOutput][] or [Output][] property and stored in a [variable][]. + +[Variable typing][] checks that the object a [variable][] holds is compatible with each property. If an unsupported type cannot be implicitly cast, you must explicitly cast or use a conversion method before the flow can run (except for [dynamic][], where compatibility is checked at execution time). + +### Casting vs converting + +Casting changes how a value is **interpreted** as a type. It does not parse or format text. + +| Goal | Approach | Example | +| --- | --- | --- | +| Treat a number as a narrower numeric type | Explicit cast | `(Int16)($)Int` | +| Parse text into a number | Conversion method | `Int32.Parse(($)Text)` or `Convert.ToInt32(($)Text)` | +| Format a value as text | `ToString()`, `Convert.ToString()`, or a text block | See [Converting Objects To Text][] | + +If **Can be cast to** for a [data type][] is `N/A`, that type does not support explicit casts to other types in expressions; use methods such as `Parse`, `Convert`, or platform blocks instead. + +### Invalid casts + +An explicit cast that is not valid for the runtime value causes an error when the expression or block runs (for example, casting a [String][] directly to [Int32][]). Before relying on a cast from [Object][] or [dynamic][], ensure the [variable][] actually contains the type you expect. + +Casting a numeric value to an [Enum][] outside the defined member values can produce a value that does not match a named member. Prefer defined members or validate the result when using numeric casts with enums. + ### Known Limitations -TODO +None ## See Also ### Related Concepts -TODO +* [What is an Object?][] +* [Object Equality][] +* [What is a Data Type?][] +* [What is a Variable?][] +* [Converting Objects To Text][] +* [What is an Enum?][] ### Related Data Types -TODO +* [Object][] +* [dynamic][] +* [Int32][] +* [Double][] +* [String][] ### Related Blocks -TODO +* [Set Variable][] +* [Copy Object][] ### External Documentation -TODO - +* [Casting and type conversions (C# Programming Guide)][MS Casting] +* [Implicit Conversions][] +* [Explicit Conversions][] +* [Cast expression (C# Reference)][MS Cast Expression] + +[Implicit cast]: {{< ref "#implicit-cast" >}} +[Explicit cast]: {{< ref "#explicit-cast" >}} +[Object vs dynamic]: {{< ref "#object-vs-dynamic" >}} + +[object]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[What is an Object?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[Object Equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectEquality.MainDoc" >}} +[Converting Objects To Text]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.ConvertingObjectsToText.MainDoc" >}} +[What is an Enum?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Enums.WhatIsAnEnum.MainDoc" >}} + +[What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} + +[What is a Variable?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variable typing]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} + +[expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.Expressions" >}} +[Expression Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.MainDoc" >}} +[Casting expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.CastingExpressions" >}} +[string expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.StringExpressions" >}} +[Enum expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.EnumExpressions" >}} + +[block property]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.MainDoc" >}} +[Input]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.Input" >}} +[InputOutput]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.InputOutput" >}} +[Output]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.Output" >}} + +[dynamic]: {{< url path="Cortex.Reference.DataTypes.All.dynamic.MainDoc" >}} +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[Int16]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int16.MainDoc" >}} +[Int64]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int64.MainDoc" >}} +[Double]: {{< url path="Cortex.Reference.DataTypes.Numbers.Double.MainDoc" >}} +[Single]: {{< url path="Cortex.Reference.DataTypes.Numbers.Single.MainDoc" >}} +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} +[Char]: {{< url path="Cortex.Reference.DataTypes.Text.Char.MainDoc" >}} +[DateTime]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTime.MainDoc" >}} +[DateTimeOffset]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTimeOffset.MainDoc" >}} +[Enum]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Enums.MainDoc" >}} + +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} +[Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} + +[MS Casting]: {{< url path="MSDocs.CSharp.Casting" >}} +[Implicit Conversions]: {{< url path="MSDocs.CSharp.ImplicitConversions" >}} +[Explicit Conversions]: {{< url path="MSDocs.CSharp.ExplicitConversions" >}} +[MS Cast Expression]: {{< url path="MSDocs.CSharp.CastExpression" >}} diff --git a/data/urls.toml b/data/urls.toml index ed2d10e5b..f93053f3c 100644 --- a/data/urls.toml +++ b/data/urls.toml @@ -1686,13 +1686,16 @@ MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor] MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/" + CastingExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#casting-expressions" + DecompositionExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#decomposition-expressions" + DictionaryLiteral = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#dictionary-literal" + EnumExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#enum-expressions" Expressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#expressions" + IndexExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#index-expressions" InterpolatedStrings = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#interpolated-strings" MethodExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#method-expressions" PropertyExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#property-expressions" - IndexExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#index-expressions" - DecompositionExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#decomposition-expressions" - DictionaryLiteral = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#dictionary-literal" + StringExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#string-expressions" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.LiteralEditor] MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/literal-editor/" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.VariableEditor] @@ -1822,6 +1825,8 @@ SettingUpCertificateCredentialsOutlook = "/docs/reference/concepts/working-with/email/authentication/#setting-up-an-outlook-account-for-oauth-authentication-using-certificate-credentials" [Cortex.Reference.Concepts.WorkingWith.Enums] MainDoc = "/docs/reference/concepts/working-with/enums/" + [Cortex.Reference.Concepts.WorkingWith.Enums.WhatIsAnEnum] + MainDoc = "/docs/reference/concepts/working-with/enums/what-is-an-enum" [Cortex.Reference.Concepts.WorkingWith.FilesAndFolders] MainDoc = "/docs/reference/concepts/working-with/files-and-folders/" [Cortex.Reference.Concepts.WorkingWith.FilesAndFolders.Attributes] @@ -1833,6 +1838,8 @@ [Cortex.Reference.Concepts.WorkingWith.Numbers] MainDoc = "/docs/reference/concepts/working-with/numbers/" [Cortex.Reference.Concepts.WorkingWith.Objects] + [Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject] + MainDoc = "/docs/reference/concepts/working-with/objects/what-is-an-object/" [Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting] MainDoc = "/docs/reference/concepts/working-with/objects/object-casting/" ImplicitCast = "/docs/reference/concepts/working-with/objects/object-casting/#implicit-cast" From 1d64d41f43b9b3be3363ec78d88e1e533dd4b613 Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 10:34:41 +0100 Subject: [PATCH 3/8] added content for object equality --- .../working-with/objects/object-equality.md | 294 ++++++++++++++++-- data/urls.toml | 1 + 2 files changed, 277 insertions(+), 18 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md index 0e22d4aea..846221bf6 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md @@ -2,56 +2,314 @@ title: "Object Equality" linkTitle: "Object Equality" description: "Information regarding object equality, and what defines two objects as equal." +weight: 3 --- # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO +**Object equality** is the rule used to decide whether two [objects][] represent the same thing. In C# and {{% ctx %}}, the answer depends on: + +* Whether the objects are [value types][] or [reference types][] +* Whether comparison happens in a C# [expression][expressions] or in a [List][], [Dictionary][], or [Data Storage][] block +* How the [data type][] implements equality (for example [String][] compares by character content even though it is a reference type) + +There are two main kinds of equality: + +| Kind | Also called | Question answered | +| --- | --- | --- | +| [Value equality][] | Equivalence | Do the objects contain the same value or values? | +| [Reference equality][] | Identity | Do both variables refer to the same instance in memory? | + +For how value and reference types affect assignment and copying, see [What is an Object?][]. For text-specific comparison rules (culture, case, and ordinal), see [Equality][] under Working with Text — that is separate from object equality on this page. + +## Value type vs reference type equality + +Every [object][] is an instance of a [data type][] that is either a [value type][value types] or a [reference type][reference types]. + +| | Value type | Reference type | +| --- | --- | --- | +| Examples | [Int32][], [Boolean][], [DateTime][] | [String][], [List<TItem>][], [Structure][], [Command][] | +| Typical C# `==` behaviour | Compares stored values | Compares references unless the type overrides `==` | +| [ReferenceEquals][] | Always `false` for two distinct variables (each holds a copy) | `true` only when both refer to the same instance | + +The rest of this page explains each kind in more detail, then describes how {{% ctx %}} applies equality in [expressions][] versus [collection blocks][]. + +## Value type equality + +**Value equality** means two objects contain the same value. For [value types][], C# compares the actual data stored in each variable. + +In the [Expression Editor][], you usually test value equality with `==` or `!=`: + +| Scenario | Expression | Result | Notes | +| --- | --- | --- | --- | +| Same values | `($)A == ($)B` where both hold `42` | `true` | [Int32][] values are equal | +| Different values | `($)A == ($)B` where `($)A` is `1` and `($)B` is `2` | `false` | Values differ | +| Default comparison | `($)Flag == true` | Depends on `($)Flag` | [Boolean][] uses value equality | + +When you assign a value type to another [variable][] with [Set Variable][], each variable holds its own copy. Changing one does not change the other. Equality is still based on the values they contain, not on sharing memory. + +[Collection blocks][] use [value equality][] for value-type items and keys — the same rules as C# expressions in practice. + +For general C# guidance, see [Equality comparisons (C#)][MS Equality] and [Value types][MS Value Types]. + +## Reference type equality + +**Reference equality** means two variables refer to the same underlying object instance. **Value equality** for a reference type means two different instances are treated as equal because their contents match — but only if the type defines that behaviour. + +### In C# expressions + +For most reference types, the `==` operator tests [reference equality][] unless the type provides its own definition: + +| Scenario | Expression | Result | Notes | +| --- | --- | --- | --- | +| Same instance | `($)A == ($)B` after `($)B = ($)A` | `true` | Both variables refer to one object | +| Different instances, same content | Two [Structure][] variables each set to `{ "Name": "Ada", "Count": 3 }` | `false` with `==` | Separate instances; reference equality | +| Identity test | `Object.ReferenceEquals(($)A, ($)B)` | `false` for two new [Structure][] instances with identical fields | Explicit [reference equality][] | +| Content test | `($)A.Equals(($)B)` | Depends on type | Uses the type's `Equals` implementation | + +Use [Object.ReferenceEquals][] when you specifically need identity, not equivalence. + +#### Types that compare by value in expressions + +Some reference types override `==` and `Equals` to compare content: + +* **[String][]** — `"hello" == "hello"` is `true` even when the strings are different instances. +* Other .NET types may define their own rules; always check the type documentation when comparing values matters. + +When comparing [String][] values in flows, also consider [text equality][] rules if you use text blocks or comparison types — object equality and text equality are not always interchangeable. + +### Worked example: two Structure instances + +Assume: + +* `($)StructureA` is set to `{ "Product": "Widget", "Qty": 5 }` +* `($)StructureB` is set to `{ "Product": "Widget", "Qty": 5 }` in a separate [Set Variable][] step (a new instance) + +| Context | Comparison | Result | +| --- | --- | --- | +| [Expression Editor][] | `($)StructureA == ($)StructureB` | `false` | +| [Expression Editor][] | `Object.ReferenceEquals(($)StructureA, ($)StructureB)` | `false` | +| [Remove Item With Value][] block | [List][] contains `($)StructureA`; [Value][] is `($)StructureB` | Item is removed — block treats instances as equal | + +This difference is the most common source of confusion when working with reference types in flows. + +For general C# guidance, see [Equality comparisons (C#)][MS Equality] and [Reference types][MS Reference Types]. + +## Comparing objects in expressions -https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons +The [Expression Editor][] supports the standard C# equality and comparison operators. The following table summarises the main approaches: -## Value Type vs Reference Type Equality +| Mechanism | Typical use | Reference types (default) | Value types | +| --- | --- | --- | --- | +| `==` / `!=` | Most comparisons in flows | [Reference equality][] (unless type overrides) | [Value equality][] | +| `.Equals(other)` | When type defines custom equivalence | Depends on type implementation | [Value equality][] | +| `Object.ReferenceEquals(a, b)` | Test same instance | [Reference equality][] | Always `false` for two boxed value-type variables | -TODO: +Comparison expressions such as `($)Int1 == ($)Int2` are documented in [Comparison expressions][] in the Expression Editor reference. For operator details, see [Equality Operators][MS Equality Operators]. -### Value Type Equality +## How {{% ctx %}} compares objects in blocks -TODO: notes about value equality and a worked through example +Many [List][], [Dictionary][], and [Data Storage][] blocks must decide whether an item or key **matches** a value you supply — for example when using [Contains Item With Value][], [Remove Item With Value][], [Get Item With Key][], or [Add Item With Key][]. -### Reference Type Equality +Block matching uses a different rule from bare C# `==` for reference types: -TODO: notes about reference equality and a worked through example +| Context | How equality is determined | +| --- | --- | +| C# syntax in the [Expression Editor][] | [Reference equality][] for reference types and [value equality][] for value types, following standard C# rules (including `==` and `Equals` where applicable). | +| [List][], [Dictionary][], and [Data Storage][] blocks | For reference types, [reference equality][] is tried first; if no matching reference is found, comparison falls back to [value equality][]. For value types, [value equality][] is used. | -## How {{% ctx %}} compares objects for equality +### Why the fallback exists -TODO: notes about how cortex compares and a worked through example +Collection blocks often need to find items that **look the same** even when they are not the same object reference — for example two [Structure][] instances with identical fields, or a search value built in a separate step from the item stored in the list. -Notes:List and Dictionary equality is slightly different to normal equality as it will compare first based on reference and then fall back to value - compared to == .Equals .ReferenceEquals - blocks affected +The fallback applies only in block matching logic. It does not change how `==` behaves in expressions. + +### Dictionary keys and reference-only types + +For typical scalar keys ([String][], [Int32][], [Boolean][], and similar), two keys with the same value are the same key. A [Dictionary][] cannot store duplicate equal keys of those types. + +Some reference types — for example [IList][]<[Int32][]> used as `TKey` — implement equality by reference only in standard C#. That means: + +* The same dictionary can contain multiple entries whose keys **print** the same (for example two separate `[1]` list instances) because they are different references. +* When a block searches with a key you supply, it still applies the block rule: [reference equality][] first, then [value equality][] fallback. A key value of `[1]` can match more than one stored key instance. See [Get Item With Key][] for an example with [Occurrence][]. + +For duplicate keys or values in dictionaries, **which entry is the 1st or 2nd match** follows the underlying .NET implementation and is not documented as stable. Prefer [List][] when order must be predictable. See [Occurrences][]. + +## Blocks that use object equality + +Object equality rules apply wherever a block compares items or keys by value, including: + +### List blocks + +* **By value** — [Contains Item With Value][], [Remove Item With Value][], [Remove Items With Value][], [Set Item With Value][], [Set Items With Value][], [Get Index Of Item With Value][], [Get Indexes Of Items With Value][], [Get Count Of Items With Value][], [Get Count Of Items With Values][] +* **Duplicates** — [Remove Duplicate Items][] (decides whether two items are the same) + +### Dictionary blocks + +* **By key** — [Contains Item With Key][], [Contains Items With Keys][], [Add Item With Key][], [Get Item With Key][], [Get Items With Key][], [Set Item With Key][], [Set Items With Key][], [Remove Item With Key][], [Remove Items With Keys][] +* **By value** — [Contains Dictionary Item With Value][], [Contains Items With Values][], [Contains Item With Key And Value][], [Remove Dictionary Item With Value][], [Remove Items With Values][], [Set Dictionary Item With Value][], [Set Dictionary Items With Value][], [Get Dictionary Count Of Items With Value][], [Get Dictionary Count Of Items With Values][], [Get Counts Of Items With Values][] + +### Data Storage blocks + +[Data Storage][] blocks that read or write by key (for example [Read Data With Key][] and [Write Data With Key][]) use the same key-matching rule as [Dictionary][] blocks. Keys in a [Data Storage Collection][] are [String][] and are case sensitive. + +Individual block pages link here for full matching behaviour. See also [Comparing and matching items][] and [Comparing keys][]. ## Remarks +### Equality vs assignment + +Assigning one [variable][] to another with [Set Variable][] does not make two reference-type objects equal in the sense of [reference equality][] — it makes two variables refer to the **same** instance. Creating a copy with [Copy Object][] produces a new instance that may be [value equal][] to the original but is not reference equal. + +### Floating-point values + +Equality comparisons of [Double][] and [Single][] values can be affected by floating-point precision. Do not rely on `==` alone for decimal fractions without understanding rounding behaviour. See [System.Double][] remarks in the .NET documentation. + +### Null + +Comparing to `null` follows C# rules: for reference types, `== null` tests whether the reference is missing; [value types][] (except [Nullable][] types) cannot be `null` unless wrapped in `Nullable`. + ### Known Limitations -TODO +* Block matching rules apply to [List][], [Dictionary][], and [Data Storage][] blocks as described above. Other blocks may use different comparison logic (for example text blocks use [Comparison Type][] and [Search Options][]). +* Whether [value equality][] fallback succeeds depends on how the [data type][] implements `Equals`. Types that only support [reference equality][] (such as [IList][]<[Int32][]> as a dictionary key) behave differently from types like [Structure][] or [String][]. +* For [Dictionary][] entries with duplicate keys or values, occurrence order is not guaranteed to be stable across platforms or versions. ## See Also ### Related Concepts -TODO +* [What is an Object?][] +* [Object Casting][] +* [What is a Data Type?][] +* [Collections][] +* [Items][] +* [Keys][] +* [Occurrences][] +* [Equality][] (text) ### Related Data Types -TODO +* [Object][] +* [Structure][] +* [String][] +* [List<TItem>][] +* [Dictionary<TKey, TItem>][] +* [Int32][] ### Related Blocks -TODO +* [Remove Item With Value][] +* [Contains Item With Value][] +* [Get Item With Key][] +* [Add Item With Key][] +* [Remove Duplicate Items][] +* [Copy Object][] ### External Documentation -TODO +* [Equality comparisons (C#)][MS Equality] +* [Equality Operators (C# reference)][MS Equality Operators] +* [Value types (C#)][MS Value Types] +* [Reference types (C#)][MS Reference Types] +* [System.Object][MS Object] + +[value equality]: {{< ref "#value-type-equality" >}} +[reference equality]: {{< ref "#reference-type-equality" >}} +[value equal]: {{< ref "#value-type-equality" >}} +[collection blocks]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} +[Comparing and matching items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} +[Comparing keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} +[text equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.Equality.MainDoc" >}} + +[objects]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[What is an Object?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[Object Casting]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.MainDoc" >}} +[Collections]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} +[Items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} +[Keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} +[Occurrences]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Occurrences.MainDoc" >}} +[Occurrence]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Occurrences.MainDoc" >}} +[Equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.Equality.MainDoc" >}} + +[What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[value types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.ValueTypes" >}} +[reference types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.ReferenceTypes" >}} + +[object]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} + +[expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.Expressions" >}} +[Expression Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.MainDoc" >}} +[Comparison expressions]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.MainDoc" >}} +[ReferenceEquals]: {{< url path="MSDocs.DotNet.Api.System.Object.ReferenceEquals" >}} +[Object.ReferenceEquals]: {{< url path="MSDocs.DotNet.Api.System.Object.ReferenceEquals" >}} + +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[Boolean]: {{< url path="Cortex.Reference.DataTypes.ConditionalLogic.Boolean.MainDoc" >}} +[Double]: {{< url path="Cortex.Reference.DataTypes.Numbers.Double.MainDoc" >}} +[Single]: {{< url path="Cortex.Reference.DataTypes.Numbers.Single.MainDoc" >}} +[DateTime]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTime.MainDoc" >}} +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} +[Structure]: {{< url path="Cortex.Reference.DataTypes.Collections.Structure.MainDoc" >}} +[List]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[Dictionary]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Dictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[IList]: {{< url path="Cortex.Reference.DataTypes.Collections.IList.MainDoc" >}} +[Command]: {{< url path="Cortex.Reference.DataTypes.Data.Command.MainDoc" >}} +[Nullable]: {{< url path="Cortex.Reference.DataTypes.Other.Nullable.MainDoc" >}} + +[Data Storage]: {{< url path="Cortex.Reference.Blocks.DataStorage.MainDoc" >}} +[Data Storage Collection]: {{< ref "../collections/what-is-a-collection.md#data-storage-collection" >}} + +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} +[Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} + +[Contains Item With Value]: {{< url path="Cortex.Reference.Blocks.Lists.ContainsItem.ContainsItemWithValue.MainDoc" >}} +[Remove Item With Value]: {{< url path="Cortex.Reference.Blocks.Lists.RemoveItem.RemoveItemWithValue.MainDoc" >}} +[Remove Items With Value]: {{< url path="Cortex.Reference.Blocks.Lists.RemoveItem.RemoveItemsWithValue.MainDoc" >}} +[Set Item With Value]: {{< url path="Cortex.Reference.Blocks.Lists.SetItem.SetItemWithValue.MainDoc" >}} +[Set Items With Value]: {{< url path="Cortex.Reference.Blocks.Lists.SetItem.SetItemsWithValue.MainDoc" >}} +[Get Index Of Item With Value]: {{< url path="Cortex.Reference.Blocks.Lists.GetIndex.GetIndexOfItemWithValue.MainDoc" >}} +[Get Indexes Of Items With Value]: {{< url path="Cortex.Reference.Blocks.Lists.GetIndex.GetIndexesOfItemsWithValue.MainDoc" >}} +[Get Count Of Items With Value]: {{< url path="Cortex.Reference.Blocks.Lists.GetCount.GetCountOfItemsWithValue.MainDoc" >}} +[Get Count Of Items With Values]: {{< url path="Cortex.Reference.Blocks.Lists.GetCount.GetCountOfItemsWithValues.MainDoc" >}} +[Remove Duplicate Items]: {{< url path="Cortex.Reference.Blocks.Lists.RemoveItem.RemoveDuplicateItems.MainDoc" >}} + +[Contains Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.ContainsItem.ContainsItemWithKey.MainDoc" >}} +[Contains Items With Keys]: {{< url path="Cortex.Reference.Blocks.Dictionaries.ContainsItem.ContainsItemsWithKeys.MainDoc" >}} +[Add Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.AddItem.AddItemWithKey.MainDoc" >}} +[Get Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.GetItem.GetItemWithKey.MainDoc" >}} +[Get Items With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.GetItem.GetItemsWithKey.MainDoc" >}} +[Set Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.SetItem.SetItemWithKey.MainDoc" >}} +[Set Items With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.SetItem.SetItemsWithKey.MainDoc" >}} +[Remove Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.RemoveItem.RemoveItemWithKey.MainDoc" >}} +[Remove Items With Keys]: {{< url path="Cortex.Reference.Blocks.Dictionaries.RemoveItem.RemoveItemsWithKeys.MainDoc" >}} +[Contains Dictionary Item With Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.ContainsItem.ContainsItemWithValue.MainDoc" >}} +[Contains Items With Values]: {{< url path="Cortex.Reference.Blocks.Dictionaries.ContainsItem.ContainsItemsWithValues.MainDoc" >}} +[Contains Item With Key And Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.ContainsItem.ContainsItemWithKeyAndValue.MainDoc" >}} +[Remove Dictionary Item With Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.RemoveItem.RemoveItemWithValue.MainDoc" >}} +[Remove Items With Values]: {{< url path="Cortex.Reference.Blocks.Dictionaries.RemoveItem.RemoveItemsWithValues.MainDoc" >}} +[Set Dictionary Item With Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.SetItem.SetItemWithValue.MainDoc" >}} +[Set Dictionary Items With Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.SetItem.SetItemsWithValue.MainDoc" >}} +[Get Dictionary Count Of Items With Value]: {{< url path="Cortex.Reference.Blocks.Dictionaries.GetCount.GetCountOfItemsWithValue.MainDoc" >}} +[Get Dictionary Count Of Items With Values]: {{< url path="Cortex.Reference.Blocks.Dictionaries.GetCount.GetCountsOfItemsWithValues.MainDoc" >}} +[Get Counts Of Items With Values]: {{< url path="Cortex.Reference.Blocks.Dictionaries.GetCount.GetCountsOfItemsWithValues.MainDoc" >}} + +[Read Data With Key]: {{< url path="Cortex.Reference.Blocks.DataStorage.ReadData.ReadDataWithKeyBlock.MainDoc" >}} +[Write Data With Key]: {{< url path="Cortex.Reference.Blocks.DataStorage.WriteData.WriteDataWithKeyBlock.MainDoc" >}} + +[Value]: {{< url path="Cortex.Reference.Blocks.Lists.RemoveItem.RemoveItemWithValue.MainDoc" >}} +[Comparison Type]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.Equality.ComparisonTypes.MainDoc" >}} +[Search Options]: {{< url path="Cortex.Reference.DataTypes.Text.SearchOptions.MainDoc" >}} + +[MS Equality]: {{< url path="MSDocs.CSharp.EqualityOperators" >}} +[MS Equality Operators]: {{< url path="MSDocs.CSharp.EqualityOperators" >}} +[MS Value Types]: {{< url path="MSDocs.CSharp.ValueTypes" >}} +[MS Reference Types]: {{< url path="MSDocs.CSharp.ReferenceTypes" >}} +[MS Object]: {{< url path="MSDocs.DotNet.Api.System.Object.MainDoc" >}} +[System.Double]: {{< url path="MSDocs.DotNet.Api.System.Double.MainDoc" >}} diff --git a/data/urls.toml b/data/urls.toml index f93053f3c..d551ca674 100644 --- a/data/urls.toml +++ b/data/urls.toml @@ -3023,6 +3023,7 @@ PathTooLongException = "https://learn.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception" [MSDocs.DotNet.Api.System.Object] MainDoc = "https://learn.microsoft.com/en-us/dotnet/api/system.object" + ReferenceEquals = "https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals" ToString = "https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring" [MSDocs.DotNet.Api.System.PriorityQueue] MainDoc = "https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.priorityqueue-2" From a3bbf01b85baee034017ab8d52b667c99369509b Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 10:39:58 +0100 Subject: [PATCH 4/8] fixed up some URL errors --- .../working-with/objects/object-casting.md | 24 +++++++++---------- .../working-with/objects/object-equality.md | 16 ++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md index d0ba53b0f..e4dacfffe 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-casting.md @@ -20,7 +20,7 @@ There are two kinds of cast: Which conversions are allowed for each [data type][] is documented on that type's reference page. Look in the **Summary** table for **Can be used as** (implicit) and **Can be cast to** (explicit). For expression syntax and examples, see [Casting expressions][] in the Expression Editor documentation. -For the relationship between [Object][] and [dynamic][] when values are stored without a specific type, see [Object vs dynamic][] below and [What is an Object?][]. +For the relationship between [Object][object] and [dynamic][] when values are stored without a specific type, see [Object vs dynamic][] below and [What is an Object?][]. ## Implicit Cast @@ -34,7 +34,7 @@ Implicit casts occur in two main places: To see which types a [data type][] can be implicitly used as, check **Can be used as** in that type's documentation. Common patterns include: * Numeric widening — for example, [Int32][] can be used as [Int64][], [Single][], or [Double][]. -* Upcasting to [Object][] or [dynamic][] — any [data type][] can be used where `Object` or `dynamic` is expected, because all types derive from [Object][]. +* Upcasting to [Object][object] or [dynamic][] — any [data type][] can be used where `Object` or `dynamic` is expected, because all types derive from [Object][object]. * Compatible type conversions — for example, [DateTime][] can be implicitly used as [DateTimeOffset][]. In the examples below, assume the variable `($)Int` has been set to `6`. @@ -50,7 +50,7 @@ For further information, see [Implicit Conversions][]. ## Explicit Cast -An **explicit cast** converts one [data type][] to another when you use cast expression syntax: `(TargetType)expression`. Use an explicit cast when information might be lost, when narrowing a numeric type, or when recovering a more specific type from [Object][] or a base type. +An **explicit cast** converts one [data type][] to another when you use cast expression syntax: `(TargetType)expression`. Use an explicit cast when information might be lost, when narrowing a numeric type, or when recovering a more specific type from [Object][object] or a base type. {{< figure src="/images/set-variable/set-variable-expression-casting.PNG" >}} @@ -66,19 +66,19 @@ In the examples below, assume the variable `($)Int` has been set to `6`. | `(Int16)($)Int` | `6` | [Int32][] cast to [Int16][] when the value is within the [Int16][] range | | `(Int32)1.9` | `1` | [Double][] to [Int32][] — decimal places are lost | | `(Char)97` | `'a'` | [Int32][] to [Char][] | -| `(Int32)($)ObjectVariable` | Depends on stored value | Recover the original type from an [Object][]-typed [variable][] | +| `(Int32)($)ObjectVariable` | Depends on stored value | Recover the original type from an [Object][object]-typed [variable][] | | `(EmailMessagePriority)0` | `EmailMessagePriority.Normal` | Numeric value cast to an [Enum][] member | ### Casting from Object and dynamic -When a [variable][] holds a value as [Object][] or was returned from a block as [dynamic][], you may need an explicit cast before using type-specific members or passing the value to a property that expects a concrete type. +When a [variable][] holds a value as [Object][object] or was returned from a block as [dynamic][], you may need an explicit cast before using type-specific members or passing the value to a property that expects a concrete type. | Variable contents | To use as [Int32][] | Notes | | --- | --- | --- | -| [Object][] holding an `Int32` | `(Int32)($)MyObject` | Required for [Object][] | +| [Object][object] holding an `Int32` | `(Int32)($)MyObject` | Required for [Object][object] | | [dynamic][] holding an `Int32` | `($)MyDynamic` | No cast needed — member access is resolved at runtime | -This difference is the main practical distinction between [Object][] and [dynamic][] in flows. See [Object vs dynamic][]. +This difference is the main practical distinction between [Object][object] and [dynamic][] in flows. See [Object vs dynamic][]. ### Casting enums @@ -90,9 +90,9 @@ For further information, see [Explicit Conversions][] and [Cast expression (C# R ## Object vs dynamic -[Object][] (`System.Object`) and [dynamic][] are interchangeable for storage: any [data type][] can be assigned to either. The difference appears when you **use** the value afterward. +[Object][object] (`System.Object`) and [dynamic][] are interchangeable for storage: any [data type][] can be assigned to either. The difference appears when you **use** the value afterward. -| | [Object][] | [dynamic][] | +| | [Object][object] | [dynamic][] | | --- | --- | --- | | Member access | Not available until you cast to the actual type | Resolved at runtime without a cast | | Typical in flows | Less common | More common for generic block [Input][], [Output][], and [InputOutput][] properties | @@ -100,7 +100,7 @@ For further information, see [Explicit Conversions][] and [Cast expression (C# R In practice, blocks that accept or return any [data type][] usually expose [dynamic][]. Exception-handling blocks may return [dynamic][] so you can access exception properties without casting; you can still cast to a specific exception type when you need stricter typing during debugging. -For full details, see the [Object][] and [dynamic][] data type pages and [What is an Object?][]. +For full details, see the [Object][object] and [dynamic][] data type pages and [What is an Object?][]. ## Remarks @@ -128,7 +128,7 @@ If **Can be cast to** for a [data type][] is `N/A`, that type does not support e ### Invalid casts -An explicit cast that is not valid for the runtime value causes an error when the expression or block runs (for example, casting a [String][] directly to [Int32][]). Before relying on a cast from [Object][] or [dynamic][], ensure the [variable][] actually contains the type you expect. +An explicit cast that is not valid for the runtime value causes an error when the expression or block runs (for example, casting a [String][] directly to [Int32][]). Before relying on a cast from [Object][object] or [dynamic][], ensure the [variable][] actually contains the type you expect. Casting a numeric value to an [Enum][] outside the defined member values can produce a value that does not match a named member. Prefer defined members or validate the result when using numeric casts with enums. @@ -149,7 +149,7 @@ None ### Related Data Types -* [Object][] +* [Object][object] * [dynamic][] * [Int32][] * [Double][] diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md index 846221bf6..e07d9b412 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/object-equality.md @@ -19,8 +19,8 @@ There are two main kinds of equality: | Kind | Also called | Question answered | | --- | --- | --- | -| [Value equality][] | Equivalence | Do the objects contain the same value or values? | -| [Reference equality][] | Identity | Do both variables refer to the same instance in memory? | +| [Value equality][value equality] | Equivalence | Do the objects contain the same value or values? | +| [Reference equality][reference equality] | Identity | Do both variables refer to the same instance in memory? | For how value and reference types affect assignment and copying, see [What is an Object?][]. For text-specific comparison rules (culture, case, and ordinal), see [Equality][] under Working with Text — that is separate from object equality on this page. @@ -50,7 +50,7 @@ In the [Expression Editor][], you usually test value equality with `==` or `!=`: When you assign a value type to another [variable][] with [Set Variable][], each variable holds its own copy. Changing one does not change the other. Equality is still based on the values they contain, not on sharing memory. -[Collection blocks][] use [value equality][] for value-type items and keys — the same rules as C# expressions in practice. +[Collection blocks][collection blocks] use [value equality][] for value-type items and keys — the same rules as C# expressions in practice. For general C# guidance, see [Equality comparisons (C#)][MS Equality] and [Value types][MS Value Types]. @@ -103,9 +103,9 @@ The [Expression Editor][] supports the standard C# equality and comparison opera | Mechanism | Typical use | Reference types (default) | Value types | | --- | --- | --- | --- | -| `==` / `!=` | Most comparisons in flows | [Reference equality][] (unless type overrides) | [Value equality][] | -| `.Equals(other)` | When type defines custom equivalence | Depends on type implementation | [Value equality][] | -| `Object.ReferenceEquals(a, b)` | Test same instance | [Reference equality][] | Always `false` for two boxed value-type variables | +| `==` / `!=` | Most comparisons in flows | [Reference equality][reference equality] (unless type overrides) | [Value equality][value equality] | +| `.Equals(other)` | When type defines custom equivalence | Depends on type implementation | [Value equality][value equality] | +| `Object.ReferenceEquals(a, b)` | Test same instance | [Reference equality][reference equality] | Always `false` for two boxed value-type variables | Comparison expressions such as `($)Int1 == ($)Int2` are documented in [Comparison expressions][] in the Expression Editor reference. For operator details, see [Equality Operators][MS Equality Operators]. @@ -117,7 +117,7 @@ Block matching uses a different rule from bare C# `==` for reference types: | Context | How equality is determined | | --- | --- | -| C# syntax in the [Expression Editor][] | [Reference equality][] for reference types and [value equality][] for value types, following standard C# rules (including `==` and `Equals` where applicable). | +| C# syntax in the [Expression Editor][] | [Reference equality][reference equality] for reference types and [value equality][] for value types, following standard C# rules (including `==` and `Equals` where applicable). | | [List][], [Dictionary][], and [Data Storage][] blocks | For reference types, [reference equality][] is tried first; if no matching reference is found, comparison falls back to [value equality][]. For value types, [value equality][] is used. | ### Why the fallback exists @@ -192,7 +192,7 @@ Comparing to `null` follows C# rules: for reference types, `== null` tests wheth ### Related Data Types -* [Object][] +* [Object][object] * [Structure][] * [String][] * [List<TItem>][] From e664a7ee48c24422b5822e915e872cb5836373de Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 11:03:27 +0100 Subject: [PATCH 5/8] added content for fundamentals > Data Types > What is a Data Type --- .../data-types/what-is-a-data-type.md | 257 +++++++++++++++--- 1 file changed, 214 insertions(+), 43 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md index 147403d92..e69a9b4b1 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md @@ -7,89 +7,260 @@ weight: 1 # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO: +A **data type** defines what kind of value a [block property][] can accept and what members (properties, methods, and so on) an [object][] of that type exposes. {{% ctx %}} is built on C# and .NET, so its data types follow the same rules as C# for assignment, defaults, nullability, and equality. + +Data types in {{% ctx %}} are commonly described in two ways: + +| Classification | Question answered | Examples | +| --- | --- | --- | +| [Value type][] or [reference type][] | How is the value stored and copied? | [Int32][] (value), [String][] (reference) | +| [Basic data type][] or [complex data type][] | How is the value shown in the UI and how complex is its structure? | [Boolean][] (basic), [List<TItem>][] (complex) | -- Overview of a data type -- Difference between Value (value types cannot be null, and have a default value that is not null e.g. int is `0`) and Reference Data Types (reference types can be null and have a null default value) -- Difference between Basic and Complex Data Types +These classifications are independent. For example, [String][] is a [basic data type][] but also a [reference type][]. + +For how a data type relates to a live value at runtime, see [What is an Object?][]. For how variables hold data without having their own type, see [What is a Variable?][]. ## Value Types -TODO: +A **value type** stores its data directly. When you assign a value type from one [variable][] to another, each variable holds its own copy of the value. + +In C# and {{% ctx %}}: + +* Value types **cannot** be `null` unless they are wrapped in [Nullable<T>][]. +* Each value type has a **default value** that is not `null` (for example `0` for [Int32][], `false` for [Boolean][], `0001-01-01T00:00:00` for [DateTime][]). +* Equality compares the stored values, not memory addresses. See [Object Equality][]. -- Explain what a value type is, and how it can be used -- Check Set Variable block and how Value Types work within the block - - Setting a new variable to an already existing value type will cause them to be separate instances of the value -- The Copy Object block can be used to make a copy of a value type (value types always have a different reference) +### Using value types in flows + +When a [Set Variable][] block sets one variable to the value of another variable that holds a value type, the variables refer to **separate instances**. Updating one variable does not change the other. + +```csharp +($)CountA = 10 +($)CountB = ($)CountA // ($)CountB is a separate copy +``` + +If `($)CountB` is later set to `20`, `($)CountA` remains `10`. + +[Copy Object][] can also be used to copy a value type. For value types, assignment already produces a separate instance; [Copy Object][] is more useful when the value is held in an [Object][]- or [dynamic][]-typed variable or inside a [collection][]. + +For general C# guidance, see [Value types (C#)][MS Value Types] and [Default values of C# types][MS Default Values]. ## Reference Types -TODO: +A **reference type** stores a reference (pointer) to an object in memory, not the object's data itself. Multiple variables can refer to the **same** instance. + +In C# and {{% ctx %}}: -- Explain what a reference type is, and how it can be used -- This is referenced by the Set Variable block - - Set Variable block is used to set ($)List[0] - - When adding `($)Reference` to `($)List`, the actual reference is added (not a copy) - - Setting value of `($)List1` to `($)List2` will cause them to have the same reference. Changes to `($)List1` are reflected in `($)List2` -- The Copy Object block can be used to make a copy of a type with a different reference +* Reference types **can** be `null` (no instance). +* The default value for a reference type is `null`. +* Equality usually compares references unless the type overrides `==` or `Equals` (for example [String][] compares by character content). See [Object Equality][]. + +### Using reference types in flows + +When a [Set Variable][] block sets one variable to another variable that holds a reference type, both variables refer to the **same instance**. Changes made through either variable affect the shared object. + +For example, if `($)List1` contains `[1, 2, 3]` and [Set Variable][] sets `($)List2` to `($)List1`: + +* Adding an item to `($)List1` also changes `($)List2`. +* Setting `($)List1[0]` updates the item seen through `($)List2`. + +The same sharing applies when adding a reference to a [List][] — the list stores the actual reference, not a copy of the object. + +To work with an independent copy of a reference type, use [Copy Object][]. It performs a **deep copy**: nested objects inside the copy are also duplicated, so changes to the copy do not affect the original. + +For general C# guidance, see [Reference types (C#)][MS Reference Types]. ## Basic Data Types -TODO: +A **basic data type** is a simple scalar type whose value can be shown directly in the [Variables List][] when [debugging a flow][]. For example, an [Int32][] shows as `42` and a [String][] shows surrounded by double quotes (for example `"MyString"`). + +Basic data types are typically used for single values such as numbers, text, dates, and logical flags. They do not contain nested items or platform-specific behaviour on their own. + +The following table lists common basic data types and whether each is a [value type][] or [reference type][] in C#. For full details on any type, see [All Data Types][Data Types]. -- Explain what a basic data type is -- Table of Basic Data Types - - Columns - Data Type Name, Value/Reference Type - - Strings are a basic data type but are also a reference type. +| Data type | Value or reference | Default value | Notes | +| --- | --- | --- | --- | +| [Boolean][] | Value | `false` | | +| [Char][] | Value | `'\0'` | | +| [Int16][] | Value | `0` | | +| [Int32][] | Value | `0` | Often referred to as Integer in examples | +| [Int64][] | Value | `0` | | +| [Single][] | Value | `0` | | +| [Double][] | Value | `0` | | +| [DateTime][] | Value | `0001-01-01T00:00:00` | | +| [DateTimeOffset][] | Value | `0001-01-01T00:00:00+00:00` | | +| [TimeSpan][] | Value | Zero interval | | +| [Guid][] | Value | `00000000-0000-0000-0000-000000000000` | | +| [String][] | Reference | `null` | Basic type, but stored as a reference type in .NET | +| [Nullable<T>][] | Value | `null` when `T` is a value type | Wraps a value type so it can be `null` | + +Other built-in C# value types (such as enums and structs) follow the same value-type rules. See [Built-in types (C#)][MS Builtin Types]. ## Complex Data Types -TODO: +A **complex data type** is a type whose structure is not a single scalar value. In {{% ctx %}}, complex data types include [collections][], platform and domain types, and the general-purpose [Object][] and [dynamic][] types. + +When a variable holds a complex data type that is not a [collection][], the [Variables List][] may show a summary such as `Instance of Command` until you open the [Variable Details Viewer][]. [Collections][Collections] show their type and item count (for example `Dictionary with 2 item(s)`). -- Explain what a complex data type is and what makes a data type complex -- Includes Complex and Collections (Lists, Dictionaries, structures, etc) -- Object -- Dynamic -- Object vs Dynamic +### Collections + +[Collections][] group multiple items. Common collection data types include: + +* [List<TItem>][] — ordered items +* [Dictionary<TKey, TItem>][] — key/item pairs +* [Structure][] — key/item pairs with [String][] keys (a {{% ctx %}}-specific type) +* [Array][], [IList<TItem>][], [IEnumerable<TItem>][] — other collection interfaces and types + +Collections are [reference types][]. Assigning one collection variable to another with [Set Variable][] shares the same instance unless you use [Copy Object][]. + +For how to work with items and keys, see [Collections][] in Working with Collections. + +### Platform and domain types + +Complex data types also include types that represent platform concepts or integrations, for example: + +* [Command][] — database commands +* [FlowException][] — flow exceptions +* HTTP, email, file, and session types under [All Data Types][Data Types] + +These types are [reference types][] and usually display as `Instance of ` in the [Variables List][]. + +### Object and dynamic + +[Object][] (`System.Object`) is the root type in .NET; every other data type derives from it. [dynamic][] behaves like [Object][] but does not require an explicit [cast][] when you use the stored value as its original type. + +| | [Object][] | [dynamic][] | +| --- | --- | --- | +| Default value | `null` | `null` | +| Category | Complex (general-purpose) | Complex (general-purpose) | +| Typical use | Block properties that accept any type | Heterogeneous [collections][] (for example `[1, "Text", true]`) | +| Casting required | Yes, to use as a specific type | No | + +`dynamic` is more commonly encountered than bare `Object` in flows. See [Object vs dynamic][] in [What is an Object?][] and the [Object][] and [dynamic][] data type pages. ## Remarks +### Value types, reference types, and null + +[Value types][] cannot be `null` unless wrapped in [Nullable<T>][]. [Reference types][] can be `null`. A [Set Variable][] block with no [Value][] sets the target variable to `null`. + +For more detail, see [Null and Nullable Types][]. + ### Known Limitations -TODO +* The [Nullable<T>][] data type page is not yet complete; behaviour follows standard C# nullable value type rules. +* [Variables][] do not have their own data type. Compatibility is checked when a variable is used in a [block property][]; [dynamic][] values are checked at runtime instead of design time. See [Variable Typing][]. +* Whether two complex objects are equal depends on context (expressions versus [collection blocks][]). See [Object Equality][]. ## See Also ### Related Concepts -TODO +* [What is an Object?][] +* [What is a Variable?][] +* [Null and Nullable Types][] +* [Generics][] +* [Object Equality][] +* [Object Casting][] +* [Collections][] ### Related Data Types -- [All Data Types][Data Type] +* [All Data Types][Data Types] +* [Object][] +* [dynamic][] +* [String][] +* [Int32][] +* [List<TItem>][] +* [Structure][] ### Related Blocks -- [All Blocks][] +* [Set Variable][] +* [Copy Object][] +* [All Blocks][] ### External Documentation -TODO: +* [Value types (C#)][MS Value Types] +* [Reference types (C#)][MS Reference Types] +* [Built-in types (C#)][MS Builtin Types] +* [Default values of C# types (C#)][MS Default Values] + +[Object vs dynamic]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} + +[value type]: {{< ref "#value-types" >}} +[value types]: {{< ref "#value-types" >}} + +[reference type]: {{< ref "#reference-types" >}} +[reference types]: {{< ref "#reference-types" >}} + +[basic data type]: {{< ref "#basic-data-types" >}} + +[complex data type]: {{< ref "#complex-data-types" >}} + +[What is an Object?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[object]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[Object Equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectEquality.MainDoc" >}} +[Object Casting]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.MainDoc" >}} +[cast]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.ExplicitCast" >}} +[collection blocks]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} +[Collections]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} +[collection]: {{< url path="Cortex.Reference.DataTypes.Collections.MainDoc" >}} + +[What is a Variable?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variables]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.MainDoc" >}} +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variable Typing]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} + +[Null and Nullable Types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.NullAndNullableTypes.MainDoc" >}} +[Generics]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.Generics.MainDoc" >}} -- [Value Types][] -- [Reference Types][] -- [Builtin Types][] -- [Default Values][] +[block property]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.MainDoc" >}} +[Value]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} -[Reference Types]: {{< url path="MSDocs.CSharp.ReferenceTypes" >}} -[Value Types]: {{< url path="MSDocs.CSharp.ValueTypes" >}} -[Builtin Types]: {{< url path="MSDocs.CSharp.BuiltinTypes" >}} -[Default Values]: {{< url path="MSDocs.CSharp.DefaultValues" >}} +[debugging a flow]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Executions.ExecutionsInDevelopment.MainDoc" >}} +[Variables List]: {{< url path="Cortex.Guides.UserGuides.UserInterfaces.Gateway.Dev.FlowEditor.RightPanel.ExecutionViewer.VariablesList" >}} +[Variable Details Viewer]: {{< url path="Cortex.Guides.UserGuides.UserInterfaces.Gateway.Dev.FlowEditor.RightPanel.ExecutionViewer.VariableDetailsViewer" >}} +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} +[Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} [All Blocks]: {{< url path="Cortex.Reference.Blocks.MainDoc" >}} -[Data Type]: {{< url path="Cortex.Reference.DataTypes.MainDoc" >}} +[Data Types]: {{< url path="Cortex.Reference.DataTypes.MainDoc" >}} + +[dynamic]: {{< url path="Cortex.Reference.DataTypes.All.dynamic.MainDoc" >}} + +[Boolean]: {{< url path="Cortex.Reference.DataTypes.ConditionalLogic.Boolean.MainDoc" >}} +[Char]: {{< url path="Cortex.Reference.DataTypes.Text.Char.MainDoc" >}} +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} + +[Int16]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int16.MainDoc" >}} +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[Int64]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int64.MainDoc" >}} +[Single]: {{< url path="Cortex.Reference.DataTypes.Numbers.Single.MainDoc" >}} +[Double]: {{< url path="Cortex.Reference.DataTypes.Numbers.Double.MainDoc" >}} + +[DateTime]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTime.MainDoc" >}} +[DateTimeOffset]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTimeOffset.MainDoc" >}} +[TimeSpan]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.TimeSpan.MainDoc" >}} +[Guid]: {{< url path="Cortex.Reference.DataTypes.Other.Guid.MainDoc" >}} +[Nullable<T>]: {{< url path="Cortex.Reference.DataTypes.Other.Nullable.MainDoc" >}} + +[List]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[Dictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Structure]: {{< url path="Cortex.Reference.DataTypes.Collections.Structure.MainDoc" >}} +[Array]: {{< url path="Cortex.Reference.DataTypes.Collections.Array.MainDoc" >}} +[IList<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.IList.MainDoc" >}} +[IEnumerable<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.IEnumerable_TItem.MainDoc" >}} + +[Command]: {{< url path="Cortex.Reference.DataTypes.Data.Command.MainDoc" >}} +[FlowException]: {{< url path="Cortex.Reference.Exceptions.Flows.FlowException.MainDoc" >}} + +[MS Value Types]: {{< url path="MSDocs.CSharp.ValueTypes" >}} +[MS Reference Types]: {{< url path="MSDocs.CSharp.ReferenceTypes" >}} +[MS Builtin Types]: {{< url path="MSDocs.CSharp.BuiltinTypes" >}} +[MS Default Values]: {{< url path="MSDocs.CSharp.DefaultValues" >}} From 166f8b4ec0e35996db6d70639791dfb96371aeaa Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 11:37:27 +0100 Subject: [PATCH 6/8] added data type generics documentation --- .../fundamentals/data-types/generics.md | 217 +++++++++++++++++- 1 file changed, 208 insertions(+), 9 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md index eee267f88..2fe1dde3f 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md @@ -1,38 +1,237 @@ --- title: "Generics" linkTitle: "Generics" -description: "Information regarding generic data types." +description: "Information regarding generic data types and type parameters such as TItem, TKey, and TValue." weight: 100 --- # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO +A **generic** data type is a type definition that includes one or more **type parameters**—placeholders for actual data types that you supply when you create or use the type. Generics let the same type definition work with many different data types while keeping compile-time type checking. + +{{% ctx %}} is built on C# and .NET, so its generic types follow the same rules as C#. You specify type arguments inside angle brackets to create a **constructed type**. For example, `List` is a list whose items are [Int32][], and `Dictionary` is a dictionary with [String][] keys and [dynamic][] items. + +| Term | Meaning | Example | +| --- | --- | --- | +| Generic type definition | A type with type parameters (a template) | `List`, `Dictionary` | +| Type parameter | Placeholder in the definition | `TItem`, `TKey`, `TValue` | +| Type argument | Concrete type you supply | `Int32`, `String`, `dynamic` | +| Constructed type | Generic type with type arguments filled in | `List`, `Dictionary` | + +For how data types are classified more broadly, see [What is a Data Type?][]. For how generic collections use type parameters for [items][] and [keys][], see [What is a Collection?][]. + +## Generic types in {{% ctx %}} + +Many {{% ctx %}} data types are generic. Common examples include: + +| Data type | Type parameters | Role | +| --- | --- | --- | +| [List<TItem>][] | `TItem` | Data type of each item in the list | +| [Dictionary<TKey, TItem>][] | `TKey`, `TItem` | Data type of each key and each item | +| [QueueWithPriority<TItem, TPriority>][] | `TItem`, `TPriority` | Data type of each queued item and its priority value | +| [IList<TItem>][], [IEnumerable<TItem>][], [IDictionary<TKey, TItem>][] | Same as implementing types | Collection interfaces accepted by block properties | +| [Nullable<T>][] | `T` | Wraps a [value type][] so it can be `null` | +| [IComparer<TPriority>][] | `TPriority` | Compares priority values in a [QueueWithPriority<TItem, TPriority>][] | + +Each type parameter must be replaced with a concrete [data type][] before the type can be used. `List` by itself is not a complete type; `List` or `List` is. + +### Type parameters in documentation + +Throughout {{% ctx %}} documentation, type parameters appear in data type names, block property tables, and exception messages. The name is a convention that describes the parameter's role—not a separate data type you can reference on its own. + +| Name | Typical meaning | Where it appears | +| --- | --- | --- | +| `TItem` | Item stored in a collection | [List][] blocks, [Dictionary][] blocks, [Queue][] blocks | +| `TKey` | Key in a key/item collection | [Dictionary][] blocks, [Dictionary<TKey, TItem>][] | +| `TValue` | Any value passed to a block property | [Set Variable][], [If Null][] blocks, [Format Text][] blocks | +| `TPriority` | Priority value in a priority queue | [QueueWithPriority<TItem, TPriority>][], [Queue][] blocks | +| `TResult` | Result returned from a task | [Wait For Task][], [Cancel Task][] blocks | +| `TTask` | Task type being operated on | Task blocks | +| `TConnectionDetails` | Connection details for a data source | [Execute Data Command][] block | +| `TObject` | Any object being converted or copied | [Convert Object To Text][], [Copy Object][] blocks | + +When a block property is shown as `IList` or `TValue`, read the type parameter as “the actual data type in your flow at runtime”. For example, a [List][] block whose `List` property is `IList` accepts any list whose item type matches the items you pass in. + +## Specifying type arguments + +### In the Expression Editor + +When you create a generic type in an expression, provide type arguments inside angle brackets: + +```csharp +new List() { 1, 2, 3 } +new Dictionary() { { "Key", "Value" } } +new QueueWithPriority() +``` + +Literal syntax can **infer** type arguments from the values you write: + +| Expression | Constructed type | Notes | +| --- | --- | --- | +| `[1, 2, 3]` | `List` | All items are integers | +| `["Some Text", true, 1]` | `List` | Mixed item types | +| `[]` | `List` | Empty list with no type context | +| `new List() { "A", "B" }` | `List` | Explicit type argument | + +See [Create a List<TItem>][] and [Create a Dictionary<TKey, TItem>][] on the data type pages for more examples. + +### At block properties + +Block properties declare the expected constructed type or a compatible generic interface. For example: + +* A property typed as [IList<TItem>][] accepts `List`, `List`, or any other `List` where `TItem` matches the items you supply. +* [Set Variable][] accepts any [TValue][]; the variable holds whatever type you assign. + +When you connect a [variable][] to a block property, {{% ctx %}} checks that the variable's current type is compatible with the property's expected type (including generic type arguments). Values stored as [dynamic][] are checked at runtime instead of design time. See [Variable Typing][]. + +## Homogenous and heterogenous types + +Whether a generic collection holds one item type or many depends on the type arguments you choose: + +| Type argument | Collection behaviour | Term | +| --- | --- | --- | +| A single specific type (for example `Int32`, `String`) | Every item must be that type | [Homogenous][] | +| [Object][] or [dynamic][] | Items may have different data types | [Heterogenous][] | + +Examples: + +* `List` — [homogenous][]; every item is an [Int32][]. +* `List` — [heterogenous][]; items may mix numbers, text, and other types. +* `Dictionary` — [homogenous][] keys and items. +* `Dictionary` — [homogenous][] [String][] keys; [heterogenous][] items. + +For more detail, see [Items][] and the [Generics glossary entry][Generics glossary]. + +## Generic blocks + +Some {{% ctx %}} blocks are themselves generic. Their .NET type name includes a backtick and a number that indicates how many type parameters the block has—for example ``SetVariableBlock`1`` (one type parameter) in the [Set Variable][] namespace line. + +Generic blocks use type parameters on properties so one block definition works with any compatible data type. The type parameter name in the documentation (such as [TValue][] on [Set Variable][]) describes that role; at runtime it is always a concrete type such as `String` or `List`. + +## Covariance and interface compatibility + +Some generic interfaces allow a constructed type to be used where a less specific type argument is expected. Data type pages document this under **Can be used as** in the Summary table. + +For example, [List<TItem>][] documents that `List` can be used as `IEnumerable` because [Int32][] derives from [Object][]—this is called **covariance**. Similar rules apply to [IEnumerable<TItem>][] and related interfaces. + +Always check the **Can be used as** and **Can be cast to** rows on the specific [data type][] page when passing a generic value to a block property or expression. ## Remarks +### Nullable<T> as a generic type + +[Nullable<T>][] is a generic [value type][] that wraps another value type so it can hold `null`. For example, `Nullable` (written in C# as `Int32?`) can be `null` or an integer. See [Null and Nullable Types][]. + +### Open generic types + +An **open generic type** is a generic definition that still has unfilled type parameters (for example `List<>` or `Dictionary<,>` in some C# contexts). In {{% ctx %}} flows you normally work with **closed** constructed types such as `List`—every type parameter has a concrete type argument. + ### Known Limitations -TODO +* You use generic types provided by .NET and {{% ctx %}}; you cannot define new generic classes or interfaces in a flow. +* Not every data type is valid for every type parameter. For example, [Dictionary<TKey, TItem>][] supports only certain types for `TKey`; see that type's Known Limitations section. +* When `TKey` is not [String][], dictionary keys may display as their `ToString()` representation in Gateway rather than as their native type. +* Generic type parameter names in documentation (`TItem`, `TKey`, and so on) are labels for clarity. They are not data types you can assign to a variable or use in an expression on their own. ## See Also ### Related Concepts -TODO +* [What is a Data Type?][] +* [Null and Nullable Types][] +* [What is a Collection?][] +* [Items][] +* [Keys][] +* [Object Casting][] ### Related Data Types -TODO +* [List<TItem>][] +* [Dictionary<TKey, TItem>][] +* [Structure][] +* [QueueWithPriority<TItem, TPriority>][] +* [IList<TItem>][] +* [IEnumerable<TItem>][] +* [IDictionary<TKey, TItem>][] +* [Nullable<T>][] +* [dynamic][] ### Related Blocks -TODO +* [Set Variable][] +* [List][] blocks (for example [Add Item At End][]) +* [Dictionary][] blocks (for example [Add Item With Key][]) +* [Queue][] blocks (for example [Enqueue Item][]) ### External Documentation -TODO +* [C# documentation][MS C#] +* [System.Collections.Generic.List<TItem>][MS List] +* [System.Collections.Generic.Dictionary<TKey, TItem>][MS Dictionary] +* [System.Collections.Generic.IEnumerable<TItem>][MS IEnumerable] + +[generic type parameter]: {{< ref "#type-parameters-in-documentation" >}} + +[data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[Null and Nullable Types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.NullAndNullableTypes.MainDoc" >}} +[What is a Collection?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.WhatIsACollection.MainDoc" >}} +[Items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} +[items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} +[Keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} +[keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} +[Object Casting]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.MainDoc" >}} + +[value type]: {{< ref "what-is-a-data-type.md#value-types" >}} +[value types]: {{< ref "what-is-a-data-type.md#value-types" >}} + +[homogenous]: {{< url path="Cortex.Reference.Glossary.F-J.Homogenous" >}} +[heterogenous]: {{< url path="Cortex.Reference.Glossary.F-J.Heterogenous" >}} +[Generics glossary]: {{< ref "../../../Glossary/f-j.md#generics" >}} + +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variable Typing]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} + +[List]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[Dictionary]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Dictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Structure]: {{< url path="Cortex.Reference.DataTypes.Collections.Structure.MainDoc" >}} +[Queue]: {{< url path="Cortex.Reference.DataTypes.Collections.QueueWithPriority.MainDoc" >}} +[QueueWithPriority<TItem, TPriority>]: {{< url path="Cortex.Reference.DataTypes.Collections.QueueWithPriority.MainDoc" >}} +[IList<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.IList.MainDoc" >}} +[IEnumerable<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.IEnumerable_TItem.MainDoc" >}} +[IDictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.IDictionary.MainDoc" >}} +[Nullable<T>]: {{< url path="Cortex.Reference.DataTypes.Other.Nullable.MainDoc" >}} +[IComparer<TPriority>]: {{< url path="Cortex.Reference.DataTypes.Collections.IComparer.MainDoc" >}} +[dynamic]: {{< url path="Cortex.Reference.DataTypes.All.dynamic.MainDoc" >}} +[Object]: {{< url path="Cortex.Reference.DataTypes.All.Object.MainDoc" >}} + +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} + +[Create a List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.CreateNew" >}} +[Create a Dictionary<TKey, TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.CreateNew" >}} + +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} +[If Null]: {{< ref "../../../Blocks/decisions/if/if-null-exit-right-block-1.md" >}} +[Format Text]: {{< url path="Cortex.Reference.Blocks.Text.FormatText.FormatTextWithValue.MainDoc" >}} +[Wait For Task]: {{< url path="Cortex.Reference.Blocks.Tasks.WaitForTask.WaitForTask.MainDoc" >}} +[Cancel Task]: {{< url path="Cortex.Reference.Blocks.Tasks.CancelTask.CancelTaskBlock.MainDoc" >}} +[Execute Data Command]: {{< url path="Cortex.Reference.Blocks.Data.ExecuteDataCommand.ExecuteDataCommand.MainDoc" >}} +[Convert Object To Text]: {{< url path="Cortex.Reference.Blocks.Objects.ConvertObject.ConvertObjectToText.MainDoc" >}} +[Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} + +[TValue]: {{< ref "#type-parameters-in-documentation" >}} +[TPriority]: {{< ref "#type-parameters-in-documentation" >}} + +[Add Item At End]: {{< url path="Cortex.Reference.Blocks.Lists.AddItem.AddItemAtEnd.MainDoc" >}} +[Add Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.AddItem.AddItemWithKey.MainDoc" >}} +[Enqueue Item]: {{< url path="Cortex.Reference.Blocks.Queues.EnqueueItem.EnqueueItemBlock.MainDoc" >}} + +[MS C#]: {{< url path="MSDocs.CSharp.MainDoc" >}} +[MS List]: {{< url path="MSDocs.DotNet.Api.System.Collections.Generic.List" >}} +[MS Dictionary]: {{< url path="MSDocs.DotNet.Api.System.Collections.Generic.Dictionary" >}} +[MS IEnumerable]: {{< url path="MSDocs.DotNet.Api.System.Collections.Generic.IEnumerable_TItem" >}} From 4f022434c18a027b98b47f154c627167e6c1da3f Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 11:57:10 +0100 Subject: [PATCH 7/8] added null and nullable data type documentation --- .../data-types/null-and-nullable-types.md | 243 +++++++++++++++++- 1 file changed, 233 insertions(+), 10 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md index ce35d9b02..04e83ed14 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md @@ -7,40 +7,263 @@ weight: 200 # {{% param title %}} -{{< workinprogress >}} - ## Summary -TODO +In C# and {{% ctx %}}, **`null`** means that a variable or property does not refer to an object instance, or that a nullable value type has no value. Whether a value can be `null` depends on its [data type][]: + +| Category | Can be `null`? | Default when unset | Examples | +| --- | --- | --- | --- | +| [Reference type][reference type] | Yes | `null` | [String][], [List<TItem>][], [Object][], [dynamic][] | +| [Value type][value type] | No (unless wrapped) | A non-null default (for example `0`, `false`) | [Int32][], [Boolean][], [DateTime][] | +| [Nullable<T>][] | Yes (when `T` is a value type) | `null` | `Nullable` (written in C# as `Int32?`) | + +{{% ctx %}} follows standard C# and .NET rules for assignment, defaults, and null checks. For how value and reference types differ more broadly, see [What is a Data Type?][]. For how [Nullable<T>][] fits into generic types, see [Generics][]. ## Null -TODO +**`null`** is a literal that represents the absence of a value. It is not an empty string, zero, or `false` — it means no instance exists. + +### Which types can be null? + +[Reference types][reference type] can always be assigned `null`. That includes [String][] (even though it is a [basic data type][]), [collections][], [Object][], [dynamic][], and platform types such as [Command][]. + +[Value types][value type] cannot be `null` on their own. An [Int32][] variable always holds a number; if you never assign one, it holds the default `0`, not `null`. To represent "no value" for a value type, wrap it in [Nullable<T>][]. + +| Value | Data type | Is `null`? | Notes | +| --- | --- | --- | --- | +| `null` | [String][] | Yes | No text instance | +| `""` | [String][] | No | Empty string is a valid instance | +| `0` | [Int32][] | No | Default numeric value | +| `null` | [Nullable<Int32>][] / `Int32?` | Yes | Nullable value type with no value | +| `null` | [List<TItem>][] | Yes | No list instance | +| `null` | [Object][] / [dynamic][] | Yes | No object instance | + +For the difference between `null` and empty text (`""`), see [Empty Text and Whitespace][] and the [Is Text Null][] block. Empty text is not `null`. + +### Setting a variable to null + +A [Set Variable][] block sets the target [variable][] to `null` when: + +* The [Value][] property is left empty (no value), or +* The [Value][] is explicitly `null`. + +This applies to any [TValue][] the block accepts. See the [Null Value][] remark on the [Set Variable][] block page. + +```csharp +($)Name = null // reference type set to null +($)OptionalCount = null // Nullable set to null +``` + +### Checking for null + +You can test whether a value is `null` in several ways: + +| Approach | When to use | +| --- | --- | +| [If Null Exit Right][] / [If Null Exit Bottom][] | Branch the flow when a [TValue][] is or is not `null` | +| [Is Text Null][] | Test whether a [String][] is `null` (not empty or whitespace) | +| [Is Text Null Or Empty][] | Test whether text is `null` or `""` | +| Expression: `($)Value == null` or `($)Value != null` | General null check in the [Expression Editor][] | + +In C# expressions, `== null` on a reference type tests whether the reference is missing. On [Nullable<T>][], it tests whether the nullable value has no value (`HasValue` is `false`). See [Object Equality][] for how null interacts with equality comparisons. + +The [If Null][] blocks require a **nullable** [TValue][] — a type that allows `null`. If you pass a non-nullable [value type][] (for example a literal `42` of type [Int32][]), the block throws [PropertyNotNullableException][] at run time. + +### When null is not allowed + +Many block properties require a non-null value. If you pass `null` where it is not permitted, {{% ctx %}} throws [PropertyNullException][]. + +Examples include: + +* [List][] properties when the list instance itself must exist (for example [Add Item At End][]) +* Path or connection properties on file, data, or HTTP blocks +* Required object references such as a [Command][] on [Execute Data Command][] + +Some properties accept collections but reject `null` **items** inside them. In that case, [PropertyContainsNullItemException][] or [InvalidPropertyValueException][] may be thrown instead. See [Null items in collections][]. ## Nullable Types -TODO +A **nullable type** is a type that allows `null`. In {{% ctx %}} documentation, "nullable" usually means one of the following: + +* Any [reference type][] (for example [String][], [List<TItem>][]) +* A [Nullable<T>][] constructed type where `T` is a [value type][] (for example `Nullable`) + +Plain [value types][] such as [Int32][] and [Boolean][] are **non-nullable** — they cannot hold `null`. + +### Nullable<T> + +[Nullable<T>][] (`System.Nullable`) is a generic [value type][] that wraps another value type so it can represent either a value or `null`. It is documented as a [generic type][] with type parameter `T`. + +In C# you can write the shorthand form with `?`: + +| Long form | Shorthand | Meaning | +| --- | --- | --- | +| `Nullable` | `Int32?` | Optional integer | +| `Nullable` | `Boolean?` | Optional true/false | +| `Nullable` | `DateTime?` | Optional date and time | + +When a nullable value type holds a value, it behaves like the underlying type for most operations. When it is `null`: + +* Comparing to `null` with `==` returns `true`. +* Accessing `.Value` throws an exception in C# (there is no underlying value). +* The `HasValue` property is `false`. + +```csharp +($)Count = (Int32?)null // no value +($)Count = (Int32?)42 // has value 42 +($)Count == null // true when no value is set +($)Count.HasValue // false when null, true when 42 +($)Count.Value // 42 when HasValue is true +``` + +[Nullable<T>][] only wraps [value types][]. You cannot create `Nullable` — [String][] is already a [reference type][] and can be `null` without a wrapper. + +For more on type parameters and constructed types, see [Generics][] and the [Nullable<T>][] data type page. + +### Null items in collections + +Whether a collection item can be `null` depends on the item type (`TItem`): + +* `List` and `List` can contain `null` entries in many contexts. +* `List` stores non-nullable [Int32][] values; adding `null` as an item is not valid and may throw [InvalidPropertyValueException][]. +* [Keys][] in [Dictionary][] and [Structure][] cannot be `null`. + +See [Items][] for how null items interact with collection blocks. ## Remarks +### Nullable block properties + +Some block properties are declared to accept only nullable types. The [If Null][] blocks are the main example: the [Value][] must be a type that allows `null` (a [reference type][] or [Nullable<T>][]). Supplying a non-nullable [value type][] literal or variable causes [PropertyNotNullableException][]. + +[PropertyNotNullableException][] message text refers to types "that do not allow null values (e.g. Int32, Boolean, Char, etc.)". Use a [reference type][] or wrap the value in [Nullable<T>][] when a property requires a nullable type. + +### Default values vs null + +Do not confuse `null` with a type's default value: + +| Data type | Default | Same as `null`? | +| --- | --- | --- | +| [String][] | `null` | Yes | +| [Int32][] | `0` | No | +| [Boolean][] | `false` | No | +| [DateTime][] | `0001-01-01T00:00:00` | No | +| [List<TItem>][] | `null` (no list created) | Yes — until you assign or create an instance | +| [Nullable<Int32>][] | `null` | Yes | + +See [Default values of C# types][MS Default Values] for the full C# rules. + ### Known Limitations -TODO +* The [Nullable<T>][] data type page is not yet complete; behaviour follows standard C# nullable value type rules. +* {{% ctx %}} documentation uses **nullable** to mean "can hold `null`" ([reference types][] and [Nullable<T>][]). This is separate from C# **nullable reference types** (`string?` annotations), which are not described separately in {{% ctx %}} flows. +* [Variables][] do not have a fixed data type. Whether `null` is valid is checked when the variable is used in a [block property][]; [dynamic][] values are checked at run time. See [Variable Typing][]. ## See Also ### Related Concepts -TODO +* [What is a Data Type?][] +* [Generics][] +* [What is an Object?][] +* [Object Equality][] +* [Items][] +* [Empty Text and Whitespace][] ### Related Data Types -TODO +* [Nullable<T>][] +* [String][] +* [Object][] +* [dynamic][] +* [Int32][] +* [Boolean][] ### Related Blocks -TODO +* [Set Variable][] +* [If Null Exit Right][] +* [If Null Exit Bottom][] +* [Is Text Null][] +* [Is Text Null Or Empty][] + +### Related Exceptions + +* [PropertyNullException][] +* [PropertyNotNullableException][] +* [PropertyContainsNullItemException][] +* [InvalidPropertyValueException][] ### External Documentation -TODO +* [Value types (C#)][MS Value Types] +* [Reference types (C#)][MS Reference Types] +* [Default values of C# types (C#)][MS Default Values] +* [Equality comparisons (C#)][MS Equality] + +[Null Value]: {{< ref "../../../Blocks/variables/set-variable/set-variable-block-1.md#null-value" >}} +[Null items in collections]: {{< ref "#null-items-in-collections" >}} + +[data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} +[Generics]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.Generics.MainDoc" >}} +[generic type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.Generics.MainDoc" >}} + +[value type]: {{< ref "what-is-a-data-type.md#value-types" >}} +[value types]: {{< ref "what-is-a-data-type.md#value-types" >}} +[reference type]: {{< ref "what-is-a-data-type.md#reference-types" >}} +[reference types]: {{< ref "what-is-a-data-type.md#reference-types" >}} +[basic data type]: {{< ref "what-is-a-data-type.md#basic-data-types" >}} + +[What is an Object?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} +[Object Equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectEquality.MainDoc" >}} +[Empty Text and Whitespace]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.EmptyTextAndWhitespace.MainDoc" >}} +[Items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} +[Keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} + +[variable]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[Variables]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.MainDoc" >}} +[Variable Typing]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Variables.WhatIsAVariable.MainDoc" >}} +[block property]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.WhatIsABlockProperty.MainDoc" >}} + +[collections]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} + +[Nullable<T>]: {{< url path="Cortex.Reference.DataTypes.Other.Nullable.MainDoc" >}} +[Nullable<Int32>]: {{< url path="Cortex.Reference.DataTypes.Other.Nullable.MainDoc" >}} + +[String]: {{< url path="Cortex.Reference.DataTypes.Text.String.MainDoc" >}} +[Object]: {{< url path="Cortex.Reference.DataTypes.All.Object.MainDoc" >}} +[dynamic]: {{< url path="Cortex.Reference.DataTypes.All.dynamic.MainDoc" >}} +[Int32]: {{< url path="Cortex.Reference.DataTypes.Numbers.Int32.MainDoc" >}} +[Boolean]: {{< url path="Cortex.Reference.DataTypes.ConditionalLogic.Boolean.MainDoc" >}} +[DateTime]: {{< url path="Cortex.Reference.DataTypes.DateAndTime.DateTime.MainDoc" >}} +[Command]: {{< url path="Cortex.Reference.DataTypes.Data.Command.MainDoc" >}} + +[List]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[List<TItem>]: {{< url path="Cortex.Reference.DataTypes.Collections.List.MainDoc" >}} +[Dictionary]: {{< url path="Cortex.Reference.DataTypes.Collections.Dictionary.MainDoc" >}} +[Structure]: {{< url path="Cortex.Reference.DataTypes.Collections.Structure.MainDoc" >}} + +[TValue]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.Generics.MainDoc" >}} +[Value]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} + +[Expression Editor]: {{< url path="Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor.MainDoc" >}} + +[Set Variable]: {{< url path="Cortex.Reference.Blocks.Variables.SetVariable.SetVariable.MainDoc" >}} +[If Null]: {{< ref "../../../Blocks/decisions/if/if-null-exit-right-block-1.md" >}} +[If Null Exit Right]: {{< ref "../../../Blocks/decisions/if/if-null-exit-right-block-1.md" >}} +[If Null Exit Bottom]: {{< ref "../../../Blocks/decisions/if/if-null-exit-bottom-block-1.md" >}} +[Is Text Null]: {{< ref "../../../Blocks/Text/is-text/is-text-null-block.md" >}} +[Is Text Null Or Empty]: {{< ref "../../../Blocks/Text/is-text/is-text-null-or-empty-block.md" >}} +[Add Item At End]: {{< url path="Cortex.Reference.Blocks.Lists.AddItem.AddItemAtEnd.MainDoc" >}} +[Execute Data Command]: {{< url path="Cortex.Reference.Blocks.Data.ExecuteDataCommand.ExecuteDataCommand.MainDoc" >}} + +[PropertyNullException]: {{< url path="Cortex.Reference.Exceptions.Common.Property.PropertyNullException.MainDoc" >}} +[PropertyNotNullableException]: {{< url path="Cortex.Reference.Exceptions.Decisions.PropertyNotNullableException.MainDoc" >}} +[PropertyContainsNullItemException]: {{< url path="Cortex.Reference.Exceptions.Common.Property.PropertyContainsNullItemException.MainDoc" >}} +[InvalidPropertyValueException]: {{< url path="Cortex.Reference.Exceptions.Flows.Blocks.InvalidPropertyValueException.MainDoc" >}} + +[MS Value Types]: {{< url path="MSDocs.CSharp.ValueTypes" >}} +[MS Reference Types]: {{< url path="MSDocs.CSharp.ReferenceTypes" >}} +[MS Default Values]: {{< url path="MSDocs.CSharp.DefaultValues" >}} +[MS Equality]: {{< url path="MSDocs.CSharp.EqualityOperators" >}} From eb3db39348374b5c413768aba80b7ea5699b66a6 Mon Sep 17 00:00:00 2001 From: Donna-Marie Smith Date: Wed, 10 Jun 2026 16:40:55 +0100 Subject: [PATCH 8/8] modifications following PO Review --- .../fundamentals/data-types/generics.md | 12 +++-------- .../data-types/null-and-nullable-types.md | 9 ++++---- .../data-types/what-is-a-data-type.md | 21 +++++++++---------- .../working-with/objects/object-equality.md | 4 ---- .../working-with/objects/what-is-an-object.md | 6 +++--- data/urls.toml | 6 +++--- 6 files changed, 23 insertions(+), 35 deletions(-) diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md index 2fe1dde3f..163fedb6f 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/generics.md @@ -20,7 +20,7 @@ A **generic** data type is a type definition that includes one or more **type pa | Type argument | Concrete type you supply | `Int32`, `String`, `dynamic` | | Constructed type | Generic type with type arguments filled in | `List`, `Dictionary` | -For how data types are classified more broadly, see [What is a Data Type?][]. For how generic collections use type parameters for [items][] and [keys][], see [What is a Collection?][]. +For how data types are classified more broadly, see [What is a Data Type?][]. For how generic collections use type parameters for [items][Items] and [keys][Keys], see [What is a Collection?][]. ## Generic types in {{% ctx %}} @@ -92,8 +92,8 @@ Whether a generic collection holds one item type or many depends on the type arg | Type argument | Collection behaviour | Term | | --- | --- | --- | -| A single specific type (for example `Int32`, `String`) | Every item must be that type | [Homogenous][] | -| [Object][] or [dynamic][] | Items may have different data types | [Heterogenous][] | +| A single specific type (for example `Int32`, `String`) | Every item must be that type | [Homogenous][homogenous] | +| [Object][] or [dynamic][] | Items may have different data types | [Heterogenous][heterogenous] | Examples: @@ -172,20 +172,15 @@ An **open generic type** is a generic definition that still has unfilled type pa * [System.Collections.Generic.Dictionary<TKey, TItem>][MS Dictionary] * [System.Collections.Generic.IEnumerable<TItem>][MS IEnumerable] -[generic type parameter]: {{< ref "#type-parameters-in-documentation" >}} - [data type]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} [What is a Data Type?]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.WhatIsADataType.MainDoc" >}} [Null and Nullable Types]: {{< url path="Cortex.Reference.Concepts.Fundamentals.DataTypes.NullAndNullableTypes.MainDoc" >}} [What is a Collection?]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.WhatIsACollection.MainDoc" >}} [Items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} -[items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} [Keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} -[keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} [Object Casting]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.ObjectCasting.MainDoc" >}} [value type]: {{< ref "what-is-a-data-type.md#value-types" >}} -[value types]: {{< ref "what-is-a-data-type.md#value-types" >}} [homogenous]: {{< url path="Cortex.Reference.Glossary.F-J.Homogenous" >}} [heterogenous]: {{< url path="Cortex.Reference.Glossary.F-J.Heterogenous" >}} @@ -225,7 +220,6 @@ An **open generic type** is a generic definition that still has unfilled type pa [Copy Object]: {{< url path="Cortex.Reference.Blocks.Objects.CopyObject.CopyObject.MainDoc" >}} [TValue]: {{< ref "#type-parameters-in-documentation" >}} -[TPriority]: {{< ref "#type-parameters-in-documentation" >}} [Add Item At End]: {{< url path="Cortex.Reference.Blocks.Lists.AddItem.AddItemAtEnd.MainDoc" >}} [Add Item With Key]: {{< url path="Cortex.Reference.Blocks.Dictionaries.AddItem.AddItemWithKey.MainDoc" >}} diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md index 04e83ed14..20b526684 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/null-and-nullable-types.md @@ -110,10 +110,10 @@ When a nullable value type holds a value, it behaves like the underlying type fo ```csharp ($)Count = (Int32?)null // no value -($)Count = (Int32?)42 // has value 42 -($)Count == null // true when no value is set -($)Count.HasValue // false when null, true when 42 -($)Count.Value // 42 when HasValue is true +($)Count = (Int32?)42 // has value 42 +($)Count == null // true when no value is set +($)Count.HasValue // false when null, true when 42 +($)Count.Value // 42 when HasValue is true ``` [Nullable<T>][] only wraps [value types][]. You cannot create `Nullable` — [String][] is already a [reference type][] and can be `null` without a wrapper. @@ -155,7 +155,6 @@ See [Default values of C# types][MS Default Values] for the full C# rules. ### Known Limitations -* The [Nullable<T>][] data type page is not yet complete; behaviour follows standard C# nullable value type rules. * {{% ctx %}} documentation uses **nullable** to mean "can hold `null`" ([reference types][] and [Nullable<T>][]). This is separate from C# **nullable reference types** (`string?` annotations), which are not described separately in {{% ctx %}} flows. * [Variables][] do not have a fixed data type. Whether `null` is valid is checked when the variable is used in a [block property][]; [dynamic][] values are checked at run time. See [Variable Typing][]. diff --git a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md index e69a9b4b1..49b72a6d1 100644 --- a/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md +++ b/content/en/docs/2026.3/Reference/Concepts/fundamentals/data-types/what-is-a-data-type.md @@ -15,8 +15,8 @@ Data types in {{% ctx %}} are commonly described in two ways: | Classification | Question answered | Examples | | --- | --- | --- | -| [Value type][] or [reference type][] | How is the value stored and copied? | [Int32][] (value), [String][] (reference) | -| [Basic data type][] or [complex data type][] | How is the value shown in the UI and how complex is its structure? | [Boolean][] (basic), [List<TItem>][] (complex) | +| [Value type][value type] or [reference type][] | How is the value stored and copied? | [Int32][] (value), [String][] (reference) | +| [Basic data type][basic data type] or [complex data type][] | How is the value shown in the UI and how complex is its structure? | [Boolean][] (basic), [List<TItem>][] (complex) | These classifications are independent. For example, [String][] is a [basic data type][] but also a [reference type][]. @@ -43,7 +43,7 @@ When a [Set Variable][] block sets one variable to the value of another variable If `($)CountB` is later set to `20`, `($)CountA` remains `10`. -[Copy Object][] can also be used to copy a value type. For value types, assignment already produces a separate instance; [Copy Object][] is more useful when the value is held in an [Object][]- or [dynamic][]-typed variable or inside a [collection][]. +[Copy Object][] can also be used to copy a value type. For value types, assignment already produces a separate instance; [Copy Object][] is more useful when the value is held in an [Object][object]- or [dynamic][]-typed variable or inside a [collection][]. For general C# guidance, see [Value types (C#)][MS Value Types] and [Default values of C# types][MS Default Values]. @@ -100,7 +100,7 @@ Other built-in C# value types (such as enums and structs) follow the same value- ## Complex Data Types -A **complex data type** is a type whose structure is not a single scalar value. In {{% ctx %}}, complex data types include [collections][], platform and domain types, and the general-purpose [Object][] and [dynamic][] types. +A **complex data type** is a type whose structure is not a single scalar value. In {{% ctx %}}, complex data types include [collections][Collections], platform and domain types, and the general-purpose [Object][object] and [dynamic][] types. When a variable holds a complex data type that is not a [collection][], the [Variables List][] may show a summary such as `Instance of Command` until you open the [Variable Details Viewer][]. [Collections][Collections] show their type and item count (for example `Dictionary with 2 item(s)`). @@ -129,28 +129,27 @@ These types are [reference types][] and usually display as `Instance of }} [value equal]: {{< ref "#value-type-equality" >}} [collection blocks]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.MainDoc" >}} -[Comparing and matching items]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Items.MainDoc" >}} -[Comparing keys]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Collections.Keys.MainDoc" >}} [text equality]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Text.Equality.MainDoc" >}} [objects]: {{< url path="Cortex.Reference.Concepts.WorkingWith.Objects.WhatIsAnObject.MainDoc" >}} diff --git a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md index e00081f45..df80dcf9f 100644 --- a/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md +++ b/content/en/docs/2026.3/Reference/Concepts/working-with/objects/what-is-an-object.md @@ -24,8 +24,8 @@ For how data types are classified (basic, complex, value, and reference), see [W A data type tells the platform what shape data has. An object is the live data that exists while a [flow][] runs. -* `Int32` is a data type; the number `42` stored in a variable is an `Int32` object (or more precisely, a boxed or typed value of that type). -* `List` is a data type; the list instance returned from a block is an object of that type. +* `Int32` is a data type; the number `42` stored in a variable is an `Int32` object. +* `List` is a data type; `[1,2,3]` is a `List` object. * [Structure][] is a data type; `{ "Name": "Ada", "Count": 3 }` is a `Structure` object. [Variables][] do not have their own data type—they are named containers that hold objects of any supported [data type][]. When a variable is used in a [block property][], {{% ctx %}} checks that the object it currently holds is compatible with the property's expected type. See [Variable Typing][] in [What is a Variable?][]. @@ -75,7 +75,7 @@ Objects are either [value types][] or [reference types][], depending on their da | --- | --- | --- | | Examples | [Int32][], [Boolean][], [DateTime][] | [String][], [List<TItem>][], [Structure][], [Command][] | | Default | Non-null default (for example `0` for `Int32`) | `null` | -| Assignment via [Set Variable][] | Variables refer to **separate** instances | Variables can refer to the **same** instance | +| Assignment via [Set Variable][] | Variables refer to **separate** instances | Variables refer to the **same** instance | | Equality | Compared by value | Compared by reference (with nuances in blocks; see [Object Equality][]) | When you assign one variable to another with [Set Variable][], a reference type object is shared: changes through either variable affect the same instance. To work with an independent copy, use [Copy Object][], which performs a deep copy (nested objects are copied too). diff --git a/data/urls.toml b/data/urls.toml index d551ca674..5c8bdc77e 100644 --- a/data/urls.toml +++ b/data/urls.toml @@ -1686,16 +1686,16 @@ MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.ExpressionEditor] MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/" - CastingExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#casting-expressions" + CastingExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#casting-expressions" DecompositionExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#decomposition-expressions" DictionaryLiteral = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#dictionary-literal" - EnumExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#enum-expressions" + EnumExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#enum-expressions" Expressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#expressions" IndexExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#index-expressions" InterpolatedStrings = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#interpolated-strings" MethodExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#method-expressions" PropertyExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#property-expressions" - StringExpressions = "docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#string-expressions" + StringExpressions = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/expression-editor/#string-expressions" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.LiteralEditor] MainDoc = "/docs/reference/concepts/fundamentals/blocks/block-properties/property-editors/literal-editor/" [Cortex.Reference.Concepts.Fundamentals.Blocks.BlockProperties.PropertyEditors.VariableEditor]