Replies: 1 comment 3 replies
-
|
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation
Lambda expression trees bound to
Expression<T>
are constructed every time such an expression is encountered. This is obviously necessary when the expression uses a local variable, but in many (perhaps most) cases, the expression is independent on any variable and can be cached. This can be advantageous to expression rewriters, verifiers, SQL generators etc., as they can also cache the output based on the identity of the expression. The expression tree can be of course moved to a static variable, but this harms readability (especially when the expression is used in code only once).Rather than changing how expression trees are generated, I think this could be solved generally, for this and other similar cases.
Idea
An expression could be marked
static
. This serves two purposes:Example
This can be translated to this:
Details
For every expression marked
static
, a cache class should be created alongside the method where it is used (copying the generic parameters of it). This leaves the optimal lazy strategy up to the CLR, which only ensures the value is readily available when needed, and handles all necessary synchronization and checks as part of the type initializer.The expression cannot reference local variables, parameters, and members dependent on
this
. It also cannot contain anotherstatic
expression, as it would be redundant. Static local functions can be referenced freely, as well as all other visible static members.Moving the expression to a nested static class ensures that all static members from the containing class are already initialized when the expression is executed, and so the risks of using uninitialized static fields are minimized. This of course doesn't apply when such an expression is used from within another type initializer.
Exceptions thrown by the
static
expression are, of course, wrapped inTypeInitializationException
.The type initializer can be marked
beforefieldinit
or not. This is up to discussion.Use cases
Any value that can be described as unique, but is local enough not to warrant moving it explicitly to its own static field, can benefit from this. This is even better than
static
variables found in other languages, as the results ofstatic
expressions are not easily modifiable, and are, obviously, directly used when they're needed.There are other cases which could benefit from this, for example:
Math
class).typeof
(which always calls a method on the result ofldtoken
).In other words, all cases where the compiler could be argued to cache the result of the expression, but does not do so (after all, the cost of caching and retrieving the value might be larger than the cost of always having to construct it). If one finds caching the result of those expressions is more performant, than they would have the option to use
static
there without making significant changes to the code.Beta Was this translation helpful? Give feedback.
All reactions