You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We've had some recent breaking changes around symbol table handling.
This was started in #503 and continued in #817, #901. #503 describes the goals, but the gist is:
String resolution should be done at compile time, not runtime.
Allow sharing config and chaining. A common config may hold all the connectors, and then a smaller config may chain to it and add a function.
Allow mutating config to enable "sessions". Mutations during bind will be caught and the binding will fail - similar to how mutating a collection during enumeration will be caught and fail the enumeration.
Allow passing in config per-expression (Rather than just engine wide)
Allow passing in runtime state per expression to functions (useful for User(), Rand(), Now()/TimeZoneInfo(), etc).
Unify globals and locals
Clear split between compile-time vs. runtime responsibilities.
SymbolTable vs. SymbolValue
The end result is:
We introduce SymbolTable - this is a compile-time class to capture which symbols are used. SymbolTables can be composed together and shared across compositions.
Creating new values on the symbol table creates a Slot, which abstracts away the name. Runtime only uses Slots. A slot lives on a specific SymbolTable.
From a SymbolTable, you can create SymbolValue (which points back to that exact SymbolTable instance) which can map Slots to Values and be passed to the eval. SymbolValue : SymbolTable is N:1 since a single check result can be shared across many evals.
There are a few key invariants:
The SymbolValue used at runtime must match the SymbolTable used at compile-time.
Passing in any extra SymbolValues at Eval (not associated with a SymbolTable from Check) is an error - since this assumed to be a mistake that you must have passed in the wrong values.
The base class is immutable, but derived classes may be mutable. So SymbolTable derives from ReadOnlySymbolTable. SymbolValues derive from ReadOnlySymbolValues. Eval uses the ReadOnly versions.
ReadOnly means the structure is locked (no new keys, no changing types); but the variables can still be mutated. The Set() function can still modify values held in a ReadOnlySymbolValues.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
We've had some recent breaking changes around symbol table handling.
This was started in #503 and continued in #817, #901. #503 describes the goals, but the gist is:
SymbolTable vs. SymbolValue
The end result is:
There are a few key invariants:
See test cases here for more documentation and examples:
https://github.com/microsoft/Power-Fx/blob/main/src/tests/Microsoft.PowerFx.Interpreter.Tests/SymbolValueTests.cs
https://github.com/microsoft/Power-Fx/blob/main/src/tests/Microsoft.PowerFx.Core.Tests/SymbolTableTests.cs
ServiceProviders
Eval requires a RuntimeConfig (https://github.com/microsoft/Power-Fx/blob/main/src/libraries/Microsoft.PowerFx.Interpreter/Environment/RuntimeConfig.cs) , which includes a SymbolValue as well as an IServiceProvider. The service provider can handle both:
We support per-eval services.
ReadOnly pattern
We use a ReadOnly pattern similar to Dictionary implements : IReadOnlyDictionary
Notably:
Beta Was this translation helpful? Give feedback.
All reactions