Can't find what you're looking for? Ask The Community  

assignment from non constant source expression

BDaly asked a question.

Hi, I am getting the following error trying to set a variable:

Unsupported feature 'assignment from non-constant source expression'.

set TEST = (SELECT ARRAY_AGG(DISTINCT account_code) FROM Cust_Table);

What does it mean?

  • Snowsight/UI
  • Snowflake Community Questions

assignment from non constant source expression

Sergiu Panaite (Snowflake)

Can you try this version:

  • set TEST = ( SELECT ARRAY_AGG ( DISTINCT account_code ):: ARRAY FROM Cust_Table );

Thanks Sergiu,

I get the same error I'm afraid.

It's odd because both versions work on their own, just when I put 'set Test = ' in front of them do I get the error. I'm new to using the Set function so unsure of next step in troubleshooting it.

Either way, thank you for your suggestion

I am able to reproduce as well. It seems certain functions like ARRAY_AGG or ARRAY_CONSTRUCT are non-constant ones since this gives me the same error:

  • set tt = ( SELECT ARRAY_CONSTRUCT ( 1 , 2 , 3 ));

Open a case with Snowflake support since it is not clear from the docs this would not be supported.

Related Questions

© 2023 Snowflake Inc. All Rights Reserved | If you’d rather not receive future emails from Snowflake, unsubscribe here or customize your communication preferences

cppreference.com

Constexpr specifier (since c++11).

  • constexpr - specifies that the value of a variable or function can appear in constant expressions

[ edit ] Explanation

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given).

A constexpr specifier used in an object declaration or non-static member function (until C++14) implies const . A constexpr specifier used in a function or static data member (since C++17) declaration implies inline . If any declaration of a function or function template has a constexpr specifier, then every declaration must contain that specifier.

[ edit ] constexpr variable

A constexpr variable must satisfy the following requirements:

  • its type must be a LiteralType
  • it must be immediately initialized
  • the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression

[ edit ] constexpr function

A constexpr function must satisfy the following requirements:

  • for constructor and destructor (since C++20) , the class must have no virtual base classes
  • a definition of a variable of non-literal type
  • a definition of a variable of static or thread storage duration
  • every constructor selected to initializing non-static data members and base class must be a constexpr constructor.

constexpr destructor

For constexpr function templates and constexpr member functions of class templates, at least one specialization must satisfy the abovementioned requirements. Other specializations are still considered as constexpr, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr function when considered as a non-template function, the template is ill-formed, no diagnostic required. (until C++23)

[ edit ] Notes

Constexpr constructors are permitted for classes that aren't literal types. For example, the default constructor of std::unique_ptr is constexpr, allowing constant initialization .

Reference variables can be declared constexpr (their initializers have to be reference constant expressions ):

[ edit ] Keywords

[ edit ] example.

Defines C++11/14 constexpr functions that compute factorials; defines a literal type that extends string literals:

[ edit ] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

[ edit ] See also

  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 30 October 2023, at 03:29.
  • This page has been accessed 2,343,991 times.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

Have a Question?

If you have any question you can ask below or enter what you are looking for!

  • Programming /

Unsupported feature 'assignment from non-constant source expression'

We are getting the below error when executing a standard script:

Error: Unsupported feature ‘assignment from non-constant source expression’.

Script set geo = (Select st_makepoint(-79.3810586,43.6562331));

Avatar for davy.ai

March 28, 2023 at 12:01 pm

This error message indicates that the script is trying to assign a non-constant value to the variable ‘geo’. The issue may be caused by the usage of the ‘Select’ statement within the script.

One possible solution could be to use a direct value assignment method instead of the ‘Select’ statement. For example, replacing the script with the following code:

set geo = st_makepoint(-79.3810586, 43.6562331);

This should assign the correct value to the variable ‘geo’ and resolve the error. However, it’s important to review the context of the script and ensure that this change does not negatively impact any other aspects of the code or the overall system.

Comments are closed.

Learn C++

5.8 — Constexpr and consteval functions

In lesson 5.5 -- Constexpr variables , we introduced the constexpr keyword, which we used to create compile-time (symbolic) constants. We also introduced constant expressions, which are expressions that can be evaluated at compile-time rather than runtime.

Consider the following program, which uses two constexpr variables:

This produces the result:

Because x and y are constexpr, the compiler can evaluate the constant expression (x > y ? x : y) at compile-time, reducing it to just 6 . Because this expression no longer needs to be evaluated at runtime, our program will run faster.

However, having a non-trivial expression in the middle of our print statement isn’t ideal -- it would be better if the expression were a named function. Here’s the same example using a function:

This program produces the same output as the prior one. But there’s a downside to putting our expression in a function: the call to greater(x, y) will execute at runtime. By using a function (which is good for modularity and documentation) we’ve lost our ability for that code to be evaluated at compile-time (which is bad for performance).

So how might we address this?

Constexpr functions can be evaluated at compile-time

A constexpr function is a function whose return value may be computed at compile-time. To make a function a constexpr function, we simply use the constexpr keyword in front of the return type. Here’s a similar program to the one above, using a constexpr function:

This produces the same output as the prior example, but the function call greater(x, y) will be evaluated at compile-time instead of runtime!

When a function call is evaluated at compile-time, the compiler will calculate the return value of the function call at compile-time, and then replace the function call with the return value.

So in our example, the call to greater(x, y) will be replaced by the result of the function call, which is the integer value 6 . In other words, the compiler will compile this:

To be eligible for compile-time evaluation, a function must have a constexpr return type, and a call to the function must have arguments that are known at compile time (e.g. are constant expressions).

Author’s note

We’ll use the term “eligible for compile-time evaluation” later in the article, so remember this definition.

For advanced readers

There are some other lesser encountered criteria as well. These can be found here .

Our greater() function definition and function call in the above example meets these requirements, so it is eligible for compile-time evaluation.

Constexpr functions can also be evaluated at runtime

Functions with a constexpr return value can also be evaluated at runtime, in which case they will return a non-constexpr result. For example:

In this example, because arguments x and y are not constant expressions, the function cannot be resolved at compile-time. However, the function will still be resolved at runtime, returning the expected value as a non-constexpr int .

Key insight

Allowing functions with a constexpr return type to be evaluated at either compile-time or runtime was allowed so that a single function can serve both cases.

Otherwise, you’d need to have separate functions (a function with a constexpr return type, and a function with a non-constexpr return type). This would not only require duplicate code, the two functions would also need to have different names!

So when is a constexpr function evaluated at compile-time?

You might think that a constexpr function would evaluate at compile-time whenever possible, but unfortunately this is not the case.

According to the C++ standard, a constexpr function that is eligible for compile-time evaluation must be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, the compiler is free to evaluate the function at either compile-time or runtime.

Let’s examine a few cases to explore this further:

In case 1, we’re calling greater() with constant expression arguments, so it is eligible to be evaluated at compile-time. The initializer of constexpr variable g must be a constant expression, so the return value is used where a constant expression is required. Thus, greater() must be evaluated at compile-time.

In case 2, the greater() function is again being called with constant expression arguments, so it is eligible for compile-time evaluation. However, the return value is not being used in a context that requires a constant expression (operator<< always executes at runtime), so the compiler is free to choose whether this call to greater() will be evaluated at compile-time or runtime!

In case 3, we’re calling greater() with one argument that is not a constant expression. However, this argument has a value that is known at compile-time. Under the as-if rule, the compiler could decide to treat x as constexpr, and call evaluate this call to greater() at compile-time. But more likely, it will evaluate it at runtime.

In case 4, the value of argument x can’t be known at compile-time, so this call to greater() will always evaluate at runtime.

Note that your compiler’s optimization level setting may have an impact on whether it decides to evaluate a function at compile-time or runtime. This also means that your compiler may make different choices for debug vs. release builds (as debug builds typically have optimizations turned off).

A constexpr function must be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

Thus, a constexpr function is better thought of as “can be used in a constant expression”, not “will be evaluated at compile-time”.

When a constexpr (or consteval) function is being evaluated at compile-time, any other functions it calls are required to be evaluated at compile-time (otherwise the initial function would not be able to return a result at compile-time).

Put another way, we can categorize the likelihood that a constexpr function will actually be evaluated at compile-time as follows:

Always (required by the standard):

  • Constexpr function is called where constant expression is required.
  • Constexpr function is called from other function being evaluated at compile-time.

Probably (there’s little reason not to):

  • Constexpr function is called where constant expression isn’t required, all arguments are constant expressions.

Possibly (if optimized under the as-if rule):

  • Constexpr function is called where constant expression isn’t required, some arguments are not constant expressions but their values are known at compile-time.

Never (not possible):

  • Constexpr function is called where constant expression isn’t required, some arguments have values that are not known at compile-time.

Determining if a constexpr function call is evaluating at compile-time or runtime

C++ does not currently provide any reliable mechanisms to do this.

What about std::is_constant_evaluated or if consteval ?

Introduced in C++20, std::is_constant_evaluated() (defined in the <type_traits> header) was intended to allow differentiation of behavior when a function is evaluating at runtime vs compile-time, so you could do something like this:

However, as the paper that proposed this feature indicates, the standard doesn’t actually make a distinction between “compile time” and “run time”. So instead, std::is_constant_evaluated() returns a bool indicating whether the current function is executing in a constant-evaluated context. A constant-evaluated context (also called a constant context ) is defined as one in which a constant expression is required (such as the initialization of a constexpr variable). In cases where the compiler is required to evaluate a constant expression at compile-time std::is_constant_evaluated will true as expected.

However, the compiler may also choose to evaluate a constexpr function at compile-time in a context that does not require a constant expression. In such cases, std::is_constant_evaluated() will return false even though the function did evaluate at compile-time. So std::is_constant_evaluated() really means “the compiler is being forced to evaluate this at compile-time”, not “this is evaluating at compile-time”.

Introduced in C++23, if consteval is shorthand for if (std::is_constant_evaluated()) (that also does not require the <type_traits> header). It has the same issue.

Forcing a constexpr function to be evaluated at compile-time

There is no way to tell the compiler that a constexpr function should prefer to evaluate at compile-time whenever it can (e.g. in cases where the return value is used in a non-constant expression).

However, we can force a constexpr function that is eligible to be evaluated at compile-time to actually evaluate at compile-time by ensuring the return value is used where a constant expression is required. This needs to be done on a per-call basis.

The most common way to do this is to use the return value to initialize a constexpr variable (this is why we’ve been using variable ‘g’ in prior examples). Unfortunately, this requires introducing a new variable into our program just to ensure compile-time evaluation, which is ugly and reduces code readability.

There are several hacky ways that people have tried to work around the problem of having to introduce a new constexpr variable each time we want to force compile-time evaluation. See here and here .

However, in C++20, there is a better workaround to this issue, which we’ll present in a moment.

Consteval C++20

C++20 introduces the keyword consteval , which is used to indicate that a function must evaluate at compile-time, otherwise a compile error will result. Such functions are called immediate functions .

In the above example, the first two calls to greater() will evaluate at compile-time. The call to greater(x, 6) cannot be evaluated at compile-time, so a compile error will result.

Best practice

Use consteval if you have a function that must run at compile-time for some reason (e.g. performance).

Using consteval to make constexpr execute at compile-time C++20

The downside of consteval functions is that such functions can’t evaluate at runtime, making them less flexible than constexpr functions, which can do either. Therefore, it would still be useful to have a convenient way to force constexpr functions to evaluate at compile-time (even when the return value is being used where a constant expression is not required), so that we could have compile-time evaluation when possible, and runtime evaluation when we can’t.

Consteval functions provides a way to make this happen, using a neat helper function:

This works because consteval functions require constant expressions as arguments -- therefore, if we use the return value of a constexpr function as an argument to a consteval function, the constexpr function must be evaluated at compile-time! The consteval function just returns this argument as its own return value, so the caller can still use it.

Note that the consteval function returns by value. While this might be inefficient to do at runtime (if the value was some type that is expensive to copy, e.g. std::string), in a compile-time context, it doesn’t matter because the entire call to the consteval function will simply be replaced with the calculated return value.

Related content

We cover auto return types in lesson 10.9 -- Type deduction for functions . We cover abbreviated function templates ( auto parameters) in lesson 11.8 -- Function templates with multiple template types .

Constexpr/consteval functions are implicitly inline

Because constexpr functions may be evaluated at compile-time, the compiler must be able to see the full definition of the constexpr function at all points where the function is called. A forward declaration will not suffice, even if the actual function definition appears later in the same compilation unit.

This means that a constexpr function called in multiple files needs to have its definition included into each such file -- which would normally be a violation of the one-definition rule. To avoid such problems, constexpr functions are implicitly inline, which makes them exempt from the one-definition rule.

As a result, constexpr functions are often defined in header files, so they can be #included into any .cpp file that requires the full definition.

Consteval functions are also implicitly inline (presumably for consistency).

The compiler must be able to see the full definition of a constexpr or consteval function, not just a forward declaration.

Constexpr/consteval functions used in a single source file (.cpp) can be defined in the source file above where they are used.

Constexpr/consteval functions used in multiple source files should be defined in a header file so they can be included into each source file.

Constexpr/consteval function parameters are not constexpr

The parameters of a constexpr function are not implicitly constexpr, nor may they be declared as constexpr .

A constexpr function parameter would imply the function could only be called with a constexpr argument. But this is not the case -- constexpr functions can be called with non-constexpr arguments when the function is evaluated at runtime.

Because such parameters are not constexpr, they cannot be used in constant expressions within the function.

In the above example, function parameter b is not constexpr (even though argument a is a constant expression). This means b cannot be used anywhere a constant expression is required, such as the the initializer for a constexpr variable (e.g. b2 ) or in a call to a consteval function ( goo(b) ).

Perhaps surprisingly, the parameters of a consteval function are also not constexpr (even though consteval functions can only be evaluated at compile-time). This decision was made for the sake of consistency.

The parameters of constexpr/consteval functions may be declared as const , in which case they are treated as runtime constants.

If you need parameters that are constant expressions, see 11.9 -- Non-type template parameters .

Constexpr/consteval functions can use non-const local variables

Within a constexpr or consteval function, we can use local variables that are not constexpr, and the value of these variables can be changed.

As a silly example:

When such functions are evaluated at compile-time, the compiler will essentially “execute” the function and return the calculated value.

Constexpr/consteval functions can use function parameters and local variables as arguments in constexpr function calls

Above, we noted, “When a constexpr (or consteval) function is being evaluated at compile-time, any other functions it calls are required to be evaluated at compile-time.”

Perhaps surprisingly, a constexpr or consteval function can use its function parameters (which aren’t constexpr) or even local variables (which may not be const at all) as arguments in a constexpr function call. When a constexpr or consteval function is being evaluated at compile-time, the value of all function parameters and local variables must be known to the compiler (otherwise it couldn’t evaluate them at compile-time). Therefore, in this specific context, C++ allows these values to be used as arguments in a call to a constexpr function, and that constexpr function call can still be evaluated at compile-time.

In the above example, foo(5) may or may not be evaluated at compile time. If it is, then the compiler knows that b is 5 . And even though b is not constexpr, the compiler can treat the call to goo(b) as if it were goo(5) and evaluate that function call at compile-time. If foo(5) is instead resolved at runtime, then goo(b) will also be resolved at runtime.

Can a constexpr function call a non-constexpr function?

The answer is yes, but only when the constexpr function is being evaluated in a non-constant context. A non-constexpr function may not be called when a constexpr function is evaluating in a constant context (because then the constexpr function wouldn’t be able to produce a compile-time constant value), and doing so will produce a compilation error.

Calling a non-constexpr function is allowed so that a constexpr function can do something like this:

Now consider this variant:

This is legal as long as someFunction(false) is never called in a constant expression.

As an aside…

Prior to C++23, the C++ standard says that a constexpr function must return a constexpr value for at least one set of arguments, otherwise it is technically ill-formed. Calling a non-constexpr function unconditionally in a constexpr function makes the constexpr function ill-formed. However, compilers are not required to generate errors or warnings for such cases -- therefore, the compiler probably won’t complain unless you try to call such a constexpr function in a constant context. In C++23, this requirement was rescinded.

For best results, we’d advise the following:

  • Avoid calling non-constexpr functions from within a constexpr function if possible.
  • If your constexpr function requires different behavior for constant and non-constant contexts, conditionalize the behavior with if (std::is_constant_evaluated()) .
  • Always test your constexpr functions in a constant context, as they may work when called in a non-constant context but fail in a constant context.

Why not constexpr every eligible function?

There are a few reasons you may not want to constexpr a function:

  • constexpr is part of the interface of a function. Once a function is made constexpr, it can be called by other constexpr functions or used in contexts that require constant expressions. Removing the constexpr later will break such code.
  • constexpr makes functions harder to debug because you can’t inspect them at runtime.

But as a general rule, if you can constexpr a function, you should.

Unless you have a specific reason not to, a function that can be made constexpr generally should be made constexpr .

guest

Python Enhancement Proposals

  • Python »
  • PEP Index »

PEP 572 – Assignment Expressions

The importance of real code, exceptional cases, scope of the target, relative precedence of :=, change to evaluation order, differences between assignment expressions and assignment statements, specification changes during implementation, _pydecimal.py, datetime.py, sysconfig.py, simplifying list comprehensions, capturing condition values, changing the scope rules for comprehensions, alternative spellings, special-casing conditional statements, special-casing comprehensions, lowering operator precedence, allowing commas to the right, always requiring parentheses, why not just turn existing assignment into an expression, with assignment expressions, why bother with assignment statements, why not use a sublocal scope and prevent namespace pollution, style guide recommendations, acknowledgements, a numeric example, appendix b: rough code translations for comprehensions, appendix c: no changes to scope semantics.

This is a proposal for creating a way to assign to variables within an expression using the notation NAME := expr .

As part of this change, there is also an update to dictionary comprehension evaluation order to ensure key expressions are executed before value expressions (allowing the key to be bound to a name and then re-used as part of calculating the corresponding value).

During discussion of this PEP, the operator became informally known as “the walrus operator”. The construct’s formal name is “Assignment Expressions” (as per the PEP title), but they may also be referred to as “Named Expressions” (e.g. the CPython reference implementation uses that name internally).

Naming the result of an expression is an important part of programming, allowing a descriptive name to be used in place of a longer expression, and permitting reuse. Currently, this feature is available only in statement form, making it unavailable in list comprehensions and other expression contexts.

Additionally, naming sub-parts of a large expression can assist an interactive debugger, providing useful display hooks and partial results. Without a way to capture sub-expressions inline, this would require refactoring of the original code; with assignment expressions, this merely requires the insertion of a few name := markers. Removing the need to refactor reduces the likelihood that the code be inadvertently changed as part of debugging (a common cause of Heisenbugs), and is easier to dictate to another programmer.

During the development of this PEP many people (supporters and critics both) have had a tendency to focus on toy examples on the one hand, and on overly complex examples on the other.

The danger of toy examples is twofold: they are often too abstract to make anyone go “ooh, that’s compelling”, and they are easily refuted with “I would never write it that way anyway”.

The danger of overly complex examples is that they provide a convenient strawman for critics of the proposal to shoot down (“that’s obfuscated”).

Yet there is some use for both extremely simple and extremely complex examples: they are helpful to clarify the intended semantics. Therefore, there will be some of each below.

However, in order to be compelling , examples should be rooted in real code, i.e. code that was written without any thought of this PEP, as part of a useful application, however large or small. Tim Peters has been extremely helpful by going over his own personal code repository and picking examples of code he had written that (in his view) would have been clearer if rewritten with (sparing) use of assignment expressions. His conclusion: the current proposal would have allowed a modest but clear improvement in quite a few bits of code.

Another use of real code is to observe indirectly how much value programmers place on compactness. Guido van Rossum searched through a Dropbox code base and discovered some evidence that programmers value writing fewer lines over shorter lines.

Case in point: Guido found several examples where a programmer repeated a subexpression, slowing down the program, in order to save one line of code, e.g. instead of writing:

they would write:

Another example illustrates that programmers sometimes do more work to save an extra level of indentation:

This code tries to match pattern2 even if pattern1 has a match (in which case the match on pattern2 is never used). The more efficient rewrite would have been:

Syntax and semantics

In most contexts where arbitrary Python expressions can be used, a named expression can appear. This is of the form NAME := expr where expr is any valid Python expression other than an unparenthesized tuple, and NAME is an identifier.

The value of such a named expression is the same as the incorporated expression, with the additional side-effect that the target is assigned that value:

There are a few places where assignment expressions are not allowed, in order to avoid ambiguities or user confusion:

This rule is included to simplify the choice for the user between an assignment statement and an assignment expression – there is no syntactic position where both are valid.

Again, this rule is included to avoid two visually similar ways of saying the same thing.

This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

This rule is included to discourage side effects in a position whose exact semantics are already confusing to many users (cf. the common style recommendation against mutable default values), and also to echo the similar prohibition in calls (the previous bullet).

The reasoning here is similar to the two previous cases; this ungrouped assortment of symbols and operators composed of : and = is hard to read correctly.

This allows lambda to always bind less tightly than := ; having a name binding at the top level inside a lambda function is unlikely to be of value, as there is no way to make use of it. In cases where the name will be used more than once, the expression is likely to need parenthesizing anyway, so this prohibition will rarely affect code.

This shows that what looks like an assignment operator in an f-string is not always an assignment operator. The f-string parser uses : to indicate formatting options. To preserve backwards compatibility, assignment operator usage inside of f-strings must be parenthesized. As noted above, this usage of the assignment operator is not recommended.

An assignment expression does not introduce a new scope. In most cases the scope in which the target will be bound is self-explanatory: it is the current scope. If this scope contains a nonlocal or global declaration for the target, the assignment expression honors that. A lambda (being an explicit, if anonymous, function definition) counts as a scope for this purpose.

There is one special case: an assignment expression occurring in a list, set or dict comprehension or in a generator expression (below collectively referred to as “comprehensions”) binds the target in the containing scope, honoring a nonlocal or global declaration for the target in that scope, if one exists. For the purpose of this rule the containing scope of a nested comprehension is the scope that contains the outermost comprehension. A lambda counts as a containing scope.

The motivation for this special case is twofold. First, it allows us to conveniently capture a “witness” for an any() expression, or a counterexample for all() , for example:

Second, it allows a compact way of updating mutable state from a comprehension, for example:

However, an assignment expression target name cannot be the same as a for -target name appearing in any comprehension containing the assignment expression. The latter names are local to the comprehension in which they appear, so it would be contradictory for a contained use of the same name to refer to the scope containing the outermost comprehension instead.

For example, [i := i+1 for i in range(5)] is invalid: the for i part establishes that i is local to the comprehension, but the i := part insists that i is not local to the comprehension. The same reason makes these examples invalid too:

While it’s technically possible to assign consistent semantics to these cases, it’s difficult to determine whether those semantics actually make sense in the absence of real use cases. Accordingly, the reference implementation [1] will ensure that such cases raise SyntaxError , rather than executing with implementation defined behaviour.

This restriction applies even if the assignment expression is never executed:

For the comprehension body (the part before the first “for” keyword) and the filter expression (the part after “if” and before any nested “for”), this restriction applies solely to target names that are also used as iteration variables in the comprehension. Lambda expressions appearing in these positions introduce a new explicit function scope, and hence may use assignment expressions with no additional restrictions.

Due to design constraints in the reference implementation (the symbol table analyser cannot easily detect when names are re-used between the leftmost comprehension iterable expression and the rest of the comprehension), named expressions are disallowed entirely as part of comprehension iterable expressions (the part after each “in”, and before any subsequent “if” or “for” keyword):

A further exception applies when an assignment expression occurs in a comprehension whose containing scope is a class scope. If the rules above were to result in the target being assigned in that class’s scope, the assignment expression is expressly invalid. This case also raises SyntaxError :

(The reason for the latter exception is the implicit function scope created for comprehensions – there is currently no runtime mechanism for a function to refer to a variable in the containing class scope, and we do not want to add such a mechanism. If this issue ever gets resolved this special case may be removed from the specification of assignment expressions. Note that the problem already exists for using a variable defined in the class scope from a comprehension.)

See Appendix B for some examples of how the rules for targets in comprehensions translate to equivalent code.

The := operator groups more tightly than a comma in all syntactic positions where it is legal, but less tightly than all other operators, including or , and , not , and conditional expressions ( A if C else B ). As follows from section “Exceptional cases” above, it is never allowed at the same level as = . In case a different grouping is desired, parentheses should be used.

The := operator may be used directly in a positional function call argument; however it is invalid directly in a keyword argument.

Some examples to clarify what’s technically valid or invalid:

Most of the “valid” examples above are not recommended, since human readers of Python source code who are quickly glancing at some code may miss the distinction. But simple cases are not objectionable:

This PEP recommends always putting spaces around := , similar to PEP 8 ’s recommendation for = when used for assignment, whereas the latter disallows spaces around = used for keyword arguments.)

In order to have precisely defined semantics, the proposal requires evaluation order to be well-defined. This is technically not a new requirement, as function calls may already have side effects. Python already has a rule that subexpressions are generally evaluated from left to right. However, assignment expressions make these side effects more visible, and we propose a single change to the current evaluation order:

  • In a dict comprehension {X: Y for ...} , Y is currently evaluated before X . We propose to change this so that X is evaluated before Y . (In a dict display like {X: Y} this is already the case, and also in dict((X, Y) for ...) which should clearly be equivalent to the dict comprehension.)

Most importantly, since := is an expression, it can be used in contexts where statements are illegal, including lambda functions and comprehensions.

Conversely, assignment expressions don’t support the advanced features found in assignment statements:

  • Multiple targets are not directly supported: x = y = z = 0 # Equivalent: (z := (y := (x := 0)))
  • Single assignment targets other than a single NAME are not supported: # No equivalent a [ i ] = x self . rest = []
  • Priority around commas is different: x = 1 , 2 # Sets x to (1, 2) ( x := 1 , 2 ) # Sets x to 1
  • Iterable packing and unpacking (both regular or extended forms) are not supported: # Equivalent needs extra parentheses loc = x , y # Use (loc := (x, y)) info = name , phone , * rest # Use (info := (name, phone, *rest)) # No equivalent px , py , pz = position name , phone , email , * other_info = contact
  • Inline type annotations are not supported: # Closest equivalent is "p: Optional[int]" as a separate declaration p : Optional [ int ] = None
  • Augmented assignment is not supported: total += tax # Equivalent: (total := total + tax)

The following changes have been made based on implementation experience and additional review after the PEP was first accepted and before Python 3.8 was released:

  • for consistency with other similar exceptions, and to avoid locking in an exception name that is not necessarily going to improve clarity for end users, the originally proposed TargetScopeError subclass of SyntaxError was dropped in favour of just raising SyntaxError directly. [3]
  • due to a limitation in CPython’s symbol table analysis process, the reference implementation raises SyntaxError for all uses of named expressions inside comprehension iterable expressions, rather than only raising them when the named expression target conflicts with one of the iteration variables in the comprehension. This could be revisited given sufficiently compelling examples, but the extra complexity needed to implement the more selective restriction doesn’t seem worthwhile for purely hypothetical use cases.

Examples from the Python standard library

env_base is only used on these lines, putting its assignment on the if moves it as the “header” of the block.

  • Current: env_base = os . environ . get ( "PYTHONUSERBASE" , None ) if env_base : return env_base
  • Improved: if env_base := os . environ . get ( "PYTHONUSERBASE" , None ): return env_base

Avoid nested if and remove one indentation level.

  • Current: if self . _is_special : ans = self . _check_nans ( context = context ) if ans : return ans
  • Improved: if self . _is_special and ( ans := self . _check_nans ( context = context )): return ans

Code looks more regular and avoid multiple nested if. (See Appendix A for the origin of this example.)

  • Current: reductor = dispatch_table . get ( cls ) if reductor : rv = reductor ( x ) else : reductor = getattr ( x , "__reduce_ex__" , None ) if reductor : rv = reductor ( 4 ) else : reductor = getattr ( x , "__reduce__" , None ) if reductor : rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )
  • Improved: if reductor := dispatch_table . get ( cls ): rv = reductor ( x ) elif reductor := getattr ( x , "__reduce_ex__" , None ): rv = reductor ( 4 ) elif reductor := getattr ( x , "__reduce__" , None ): rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )

tz is only used for s += tz , moving its assignment inside the if helps to show its scope.

  • Current: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) tz = self . _tzstr () if tz : s += tz return s
  • Improved: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) if tz := self . _tzstr (): s += tz return s

Calling fp.readline() in the while condition and calling .match() on the if lines make the code more compact without making it harder to understand.

  • Current: while True : line = fp . readline () if not line : break m = define_rx . match ( line ) if m : n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v else : m = undef_rx . match ( line ) if m : vars [ m . group ( 1 )] = 0
  • Improved: while line := fp . readline (): if m := define_rx . match ( line ): n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v elif m := undef_rx . match ( line ): vars [ m . group ( 1 )] = 0

A list comprehension can map and filter efficiently by capturing the condition:

Similarly, a subexpression can be reused within the main expression, by giving it a name on first use:

Note that in both cases the variable y is bound in the containing scope (i.e. at the same level as results or stuff ).

Assignment expressions can be used to good effect in the header of an if or while statement:

Particularly with the while loop, this can remove the need to have an infinite loop, an assignment, and a condition. It also creates a smooth parallel between a loop which simply uses a function call as its condition, and one which uses that as its condition but also uses the actual value.

An example from the low-level UNIX world:

Rejected alternative proposals

Proposals broadly similar to this one have come up frequently on python-ideas. Below are a number of alternative syntaxes, some of them specific to comprehensions, which have been rejected in favour of the one given above.

A previous version of this PEP proposed subtle changes to the scope rules for comprehensions, to make them more usable in class scope and to unify the scope of the “outermost iterable” and the rest of the comprehension. However, this part of the proposal would have caused backwards incompatibilities, and has been withdrawn so the PEP can focus on assignment expressions.

Broadly the same semantics as the current proposal, but spelled differently.

Since EXPR as NAME already has meaning in import , except and with statements (with different semantics), this would create unnecessary confusion or require special-casing (e.g. to forbid assignment within the headers of these statements).

(Note that with EXPR as VAR does not simply assign the value of EXPR to VAR – it calls EXPR.__enter__() and assigns the result of that to VAR .)

Additional reasons to prefer := over this spelling include:

  • In if f(x) as y the assignment target doesn’t jump out at you – it just reads like if f x blah blah and it is too similar visually to if f(x) and y .
  • import foo as bar
  • except Exc as var
  • with ctxmgr() as var

To the contrary, the assignment expression does not belong to the if or while that starts the line, and we intentionally allow assignment expressions in other contexts as well.

  • NAME = EXPR
  • if NAME := EXPR

reinforces the visual recognition of assignment expressions.

This syntax is inspired by languages such as R and Haskell, and some programmable calculators. (Note that a left-facing arrow y <- f(x) is not possible in Python, as it would be interpreted as less-than and unary minus.) This syntax has a slight advantage over ‘as’ in that it does not conflict with with , except and import , but otherwise is equivalent. But it is entirely unrelated to Python’s other use of -> (function return type annotations), and compared to := (which dates back to Algol-58) it has a much weaker tradition.

This has the advantage that leaked usage can be readily detected, removing some forms of syntactic ambiguity. However, this would be the only place in Python where a variable’s scope is encoded into its name, making refactoring harder.

Execution order is inverted (the indented body is performed first, followed by the “header”). This requires a new keyword, unless an existing keyword is repurposed (most likely with: ). See PEP 3150 for prior discussion on this subject (with the proposed keyword being given: ).

This syntax has fewer conflicts than as does (conflicting only with the raise Exc from Exc notation), but is otherwise comparable to it. Instead of paralleling with expr as target: (which can be useful but can also be confusing), this has no parallels, but is evocative.

One of the most popular use-cases is if and while statements. Instead of a more general solution, this proposal enhances the syntax of these two statements to add a means of capturing the compared value:

This works beautifully if and ONLY if the desired condition is based on the truthiness of the captured value. It is thus effective for specific use-cases (regex matches, socket reads that return '' when done), and completely useless in more complicated cases (e.g. where the condition is f(x) < 0 and you want to capture the value of f(x) ). It also has no benefit to list comprehensions.

Advantages: No syntactic ambiguities. Disadvantages: Answers only a fraction of possible use-cases, even in if / while statements.

Another common use-case is comprehensions (list/set/dict, and genexps). As above, proposals have been made for comprehension-specific solutions.

This brings the subexpression to a location in between the ‘for’ loop and the expression. It introduces an additional language keyword, which creates conflicts. Of the three, where reads the most cleanly, but also has the greatest potential for conflict (e.g. SQLAlchemy and numpy have where methods, as does tkinter.dnd.Icon in the standard library).

As above, but reusing the with keyword. Doesn’t read too badly, and needs no additional language keyword. Is restricted to comprehensions, though, and cannot as easily be transformed into “longhand” for-loop syntax. Has the C problem that an equals sign in an expression can now create a name binding, rather than performing a comparison. Would raise the question of why “with NAME = EXPR:” cannot be used as a statement on its own.

As per option 2, but using as rather than an equals sign. Aligns syntactically with other uses of as for name binding, but a simple transformation to for-loop longhand would create drastically different semantics; the meaning of with inside a comprehension would be completely different from the meaning as a stand-alone statement, while retaining identical syntax.

Regardless of the spelling chosen, this introduces a stark difference between comprehensions and the equivalent unrolled long-hand form of the loop. It is no longer possible to unwrap the loop into statement form without reworking any name bindings. The only keyword that can be repurposed to this task is with , thus giving it sneakily different semantics in a comprehension than in a statement; alternatively, a new keyword is needed, with all the costs therein.

There are two logical precedences for the := operator. Either it should bind as loosely as possible, as does statement-assignment; or it should bind more tightly than comparison operators. Placing its precedence between the comparison and arithmetic operators (to be precise: just lower than bitwise OR) allows most uses inside while and if conditions to be spelled without parentheses, as it is most likely that you wish to capture the value of something, then perform a comparison on it:

Once find() returns -1, the loop terminates. If := binds as loosely as = does, this would capture the result of the comparison (generally either True or False ), which is less useful.

While this behaviour would be convenient in many situations, it is also harder to explain than “the := operator behaves just like the assignment statement”, and as such, the precedence for := has been made as close as possible to that of = (with the exception that it binds tighter than comma).

Some critics have claimed that the assignment expressions should allow unparenthesized tuples on the right, so that these two would be equivalent:

(With the current version of the proposal, the latter would be equivalent to ((point := x), y) .)

However, adopting this stance would logically lead to the conclusion that when used in a function call, assignment expressions also bind less tight than comma, so we’d have the following confusing equivalence:

The less confusing option is to make := bind more tightly than comma.

It’s been proposed to just always require parentheses around an assignment expression. This would resolve many ambiguities, and indeed parentheses will frequently be needed to extract the desired subexpression. But in the following cases the extra parentheses feel redundant:

Frequently Raised Objections

C and its derivatives define the = operator as an expression, rather than a statement as is Python’s way. This allows assignments in more contexts, including contexts where comparisons are more common. The syntactic similarity between if (x == y) and if (x = y) belies their drastically different semantics. Thus this proposal uses := to clarify the distinction.

The two forms have different flexibilities. The := operator can be used inside a larger expression; the = statement can be augmented to += and its friends, can be chained, and can assign to attributes and subscripts.

Previous revisions of this proposal involved sublocal scope (restricted to a single statement), preventing name leakage and namespace pollution. While a definite advantage in a number of situations, this increases complexity in many others, and the costs are not justified by the benefits. In the interests of language simplicity, the name bindings created here are exactly equivalent to any other name bindings, including that usage at class or module scope will create externally-visible names. This is no different from for loops or other constructs, and can be solved the same way: del the name once it is no longer needed, or prefix it with an underscore.

(The author wishes to thank Guido van Rossum and Christoph Groth for their suggestions to move the proposal in this direction. [2] )

As expression assignments can sometimes be used equivalently to statement assignments, the question of which should be preferred will arise. For the benefit of style guides such as PEP 8 , two recommendations are suggested.

  • If either assignment statements or assignment expressions can be used, prefer statements; they are a clear declaration of intent.
  • If using assignment expressions would lead to ambiguity about execution order, restructure it to use statements instead.

The authors wish to thank Alyssa Coghlan and Steven D’Aprano for their considerable contributions to this proposal, and members of the core-mentorship mailing list for assistance with implementation.

Search code, repositories, users, issues, pull requests...

Provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix assignments to constants using non-constant expressions #1013

@mwetter

sjoelund commented Oct 19, 2017

See also: https://trac.openmodelica.org/OpenModelica/ticket/4550 https://trac.openmodelica.org/OpenModelica/ticket/3150

The text was updated successfully, but these errors were encountered:

@mwetter

mwetter commented Oct 19, 2017

Sorry, something went wrong.

mwetter commented Oct 20, 2017

Sjoelund commented oct 20, 2017, sjoelund commented oct 21, 2017.

@tbeu

tbeu commented Oct 21, 2017 • edited

Mwetter commented oct 21, 2017, tbeu commented oct 21, 2017, tbeu commented oct 23, 2017, mwetter commented oct 23, 2017, tbeu commented oct 23, 2017 • edited, sjoelund commented nov 3, 2017, mwetter commented nov 3, 2017.

@modelica-trac-importer

Successfully merging a pull request may close this issue.

@mwetter

  • Skip to main content
  • Skip to search
  • Skip to select language
  • Sign up for free
  • English (US)

SyntaxError: cannot use `??` unparenthesized within `||` and `&&` expressions

The JavaScript exception "cannot use ?? unparenthesized within || and && expressions" occurs when an nullish coalescing operator is used with a logical OR or logical AND in the same expression without parentheses.

What went wrong?

The operator precedence chain looks like this:

However, the precedence between ?? and && / || is intentionally undefined, because the short circuiting behavior of logical operators can make the expression's evaluation counter-intuitive. Therefore, the following combinations are all syntax errors, because the language doesn't know how to parenthesize the operands:

Instead, make your intent clear by parenthesizing either side explicitly:

When migrating legacy code that uses || and && for guarding against null or undefined , you may often convert it partially:

Instead, consider parenthesizing the && :

Even better, consider using optional chaining instead of && :

  • Issue about nullish coalescing precedence in the TC39 nullish-coalescing proposal
  • Nullish coalescing operator ( ?? )
  • Operator precedence

COMMENTS

  1. Unsupported feature 'assignment from non-constant source expression'

    JOIN A USER GROUP CHAPTER Located in cities around the world, our user groups bring together data professionals to connect, share ideas and innovate together. Get together to talk about what you have built, check out new features, and learn from each other. Learn More >>

  2. Unsupported feature 'assignment from non-constant source expression'

    Stack Overflow Public questions & answers; Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers; Talent Build your employer brand ; Advertising Reach developers & technologists worldwide; Labs The future of collective knowledge sharing; About the company

  3. Unsupported feature 'assignment from non-constant source expression'

    Unsupported feature 'assignment from non-constant source expression'. ... Unsupported feature 'assignment from non-constant source expression'. set TEST = (SELECT ARRAY_AGG(DISTINCT account_code) FROM Cust_Table); ... It seems certain functions like ARRAY_AGG or ARRAY_CONSTRUCT are non-constant ones since this gives me the same error: set tt ...

  4. TypeError: invalid assignment to const "x"

    The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an object, this means the object itself can still be altered. This means that you can't mutate the value stored in a variable: js.

  5. constexpr specifier (since C++11)

    Explanation. The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given).. A constexpr specifier used in an object declaration or non-static member function (until C++14 ...

  6. Unsupported feature 'assignment from non-constant source expression'

    One possible solution could be to use a direct value assignment method instead of the 'Select' statement. For example, replacing the script with the following code: set geo = st_makepoint(-79.3810586, 43.6562331);

  7. 5.8

    5.8 — Constexpr and consteval functions. In lesson 5.5 -- Constexpr variables, we introduced the constexpr keyword, which we used to create compile-time (symbolic) constants. We also introduced constant expressions, which are expressions that can be evaluated at compile-time rather than runtime. Consider the following program, which uses two ...

  8. PEP 572

    Unparenthesized assignment expressions are prohibited for the value of a keyword argument in a call. Example: foo(x = y := f(x)) # INVALID foo(x=(y := f(x))) # Valid, though probably confusing. This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

  9. Using LD, the GNU linker

    Two things distinguish assignment from other operators in ld expressions. ... The linker tries to put off the evaluation of an assignment until all the terms in the source expression are known (see section Evaluation). For instance, the sizes of sections cannot be known until after allocation, so assignments dependent upon these are not ...

  10. ID:10414 VHDL Unsupported Feature error at <location>: cannot ...

    CAUSE: In a VHDL design file at the specified location, you either declared a non-constant object with a real type or converted a non-constant value into a real value. Integrated Synthesis does not support non-constant real values or objects.

  11. PDF Verilog Language Reference

    Verilog language source files are a stream of lexical tokens. A lexical token consists of one or ... during assignment of non-string values. ... Both <msb_constant_expression> and <lsb_constant_expression> are non-negative constant expressions. There are no restrictions on the values of the indices.

  12. intel fpga

    \$\begingroup\$ @askque , your need to show your code. Update your question, change the "Edited code:" section. From your description you didn't add clk port list but you did declare it as an input. That is the annoyance with non-ANSI, you have define the port name, direction and type on different lines; with ANSI it is all together one the same line. \$\endgroup\$

  13. Can I pass parameters down

    I have a parameter passed into an interface. Within this interface I am doing a bind whilst passing that parameter in. I get an error: Error-[NCEI] Non-constant expression in parameter bind_if.sv, 78 my_module, "param_path" The use of a non-constant expression to override a parameter value is illegal. Please replace the offending expression by an elaboration-time constant. The interface is ...

  14. Fix assignments to constants using non-constant expressions #1013

    makes me wonder if this is really invalid. nEle is a parameter.nEle is only used to determine the size of the vector of constants initialize_p1, and the size right hand side of the assignment.However, each element of the expression that assigns a value to the constant initialize_p1 depends on constants only.. Is this therefore something that could be fixed on the OpenModelica parser?

  15. Expression assigned to a wider essential type

    As for the reason for the warning, it is rule 10.6: The value of a composite expression shall not be assigned to an object with wider essential type. If we ignore the meaning of all these terms, what the rule boils down to is that if you have an operation with 2 operands of a smaller type, the result should not get assigned to a variable of ...

  16. SyntaxError: cannot use `??` unparenthesized within `||` and

    The operator precedence chain looks like this:. However, the precedence between?? and &&/|| is intentionally undefined, because the short circuiting behavior of logical operators can make the expression's evaluation counter-intuitive. Therefore, the following combinations are all syntax errors, because the language doesn't know how to parenthesize the operands:

  17. Setting variable for number of months dynamically : r/SQL

    Snowflake. I just started working with declaring variables so that I don't have to change them throughout my code and I'm having trouble with one in particular: SET PRETX = '1/1/2018'; --Pre transactional period. SET POSTTX = '9/30/2022'; --Post transactional period. SET NUMMO = Number of months between the two dates above.

  18. Can I assign a const reference to a non-const variable?

    1. Yes, you can assign a const reference to a non-reference variable. int x = 42; const int &y = x; // y is a const reference to x. int w = y; // this works. int z& = y; // this doesn't. You can assign a const reference to a non-reference because the value is copied, meaning that x won't be modified if w is modified as w is a copy of the data.