Parameter types


Each parameter has two independent properties: a data type (what expressions it accepts) and a passing mode (how the argument is transferred from call site to function body).

Passing modes

VAL

The argument is evaluated once, in the evaluation context of the caller, before the function body runs. The parameter behaves like a VAR bound to that value. Changes in filter or row context inside the function body have no effect on the parameter’s value.

Semantic equivalent for a call F( SUM ( Sales[Quantity] ) ) with parameter qty : VAL:

VAR qty = SUM ( Sales[Quantity] )
RETURN <body>

EXPR

The argument expression is captured unevaluated and substituted inline at every reference to the parameter inside the function body. The expression is re-evaluated each time it is referenced, in the evaluation context present at that point in the body.

Semantic equivalent for a call F( SUM ( Sales[Quantity] ) ) with parameter qty : EXPR:

-- every reference to qty in the body becomes SUM ( Sales[Quantity] )

Context transition: EXPR parameters do not receive automatic context transition in row contexts, unlike a measure reference. To ensure correct behavior inside iterators, wrap the parameter reference in CALCULATE:

CALCULATE ( paramExpr )

MEASUREREF (see below) is the only reference type that guarantees context transition automatically.

Data types

Type Accepts Passing mode Notes
ANYVAL Any scalar or table VAL (default) Default when no type hint is specified
SCALAR Scalar expressions only VAL or EXPR Accepts a subtype to restrict the data type
TABLE Table expressions only VAL or EXPR  
ANYREF Any expression EXPR (forced) No semantic guarantee on the expression kind
MEASUREREF Measure references only EXPR (forced) Guarantees context transition in row contexts
COLUMNREF Column references only EXPR (forced) Enables model-independent column access
TABLEREF Model table references only EXPR (forced) Provides full column and relationship access
CALENDARREF Calendar references only EXPR (forced) Intended for time intelligence functions

ANYREF, MEASUREREF, COLUMNREF, TABLEREF, and CALENDARREF force EXPR passing mode and cannot be declared as VAL.

Scalar subtypes

SCALAR can be qualified with a subtype that restricts the accepted data type and enables automatic coercion:

Subtype Accepts
VARIANT (default) Any scalar data type
INT64 Integer
DECIMAL Fixed-decimal number
DOUBLE Floating-point number
NUMERIC Any numeric type (INT64, DECIMAL, DOUBLE)
STRING Text
DATETIME Date or timestamp
BOOLEAN True/False

Coercion applies independently to each parameter; it does not propagate across parameters.

Type declaration syntax

<ParameterName> : <Type> [<Subtype>] [<PassingMode>]

When only a passing mode is written without a type, the type defaults to ANYVAL:

FUNCTION F = ( a : VAL, b : EXPR ) => ...

Type checking

Type checking and coercion apply differently depending on the parameter category:

Scalar subtypes (INT64, DECIMAL, DOUBLE, etc.) do not reject incompatible arguments; they coerce them. Each argument is independently converted to the declared type before the function body runs. No error is raised; see the coercion note under Scalar subtypes above.

Reference types (MEASUREREF, COLUMNREF, TABLEREF, CALENDARREF) perform genuine type checking at call time. Passing an incompatible expression produces an error that identifies the expected and received types, for example: “An invalid argument type was passed into parameter ‘amountMeasure’ of the user-defined function. Expected ‘MEASUREREF’ but got ‘SCALAR’.” There is a known limitation for COLUMNREF: when a column reference is invalid, the internal syntax error from the function body surfaces before any custom validation error the function author may have written.

ANYREF performs no type checking. An incompatible argument may produce confusing errors deep inside the function body or, in the worst case, incorrect results with no error at all. Functions using ANYREF must handle the general case defensively, for example by wrapping every reference to the parameter in CALCULATE to guarantee context transition regardless of what was passed.

Introspection functions

Two functions are available for use inside a function body with COLUMNREF or TABLEREF parameters:

  • TABLEOF ( columnRef ): returns the table in which the referenced column is defined.
  • NAMEOF ( columnRef ): returns the column’s fully qualified name as a string.

These functions are intended to support runtime validation, for example checking that two COLUMNREF parameters belong to the same table:

IF (
    NAMEOF ( TABLEOF ( col1 ) ) <> NAMEOF ( TABLEOF ( col2 ) ),
    ERROR ( "col1 and col2 must belong to the same table" )
)

This pattern does not work reliably today: when the column parameters are used incorrectly in the function body, DAX generates its own internal error from that usage before the IF/ERROR validation code executes, hiding the custom error message. The intent is correct and the pattern is expected to work once the evaluation order is enforced.

See Understanding parameter types in DAX user-defined functions.

Last update: Jun 06, 2026