PLT: Talk about evaluation strategy

Source: Internet
Author: User


When learning methods/functions, we always have access to two concepts of value-based and reference-passing values. Like C # is a value-by-value, but when the argument list is added ref/out It is a reference value, but something strange happens.

namespacefoo{classbar{ PublicString msg{Get;Set;} }  classprogram{ Public Static voidMain (string[] args) {Bar bar1=NewBar (); Bar1. MSG="Hey, man!";      Updateprop (BAR1); Console.WriteLine (bar1. MSG); //bye!    }    Static voidUpdateprop (bar bar) {bar. MSG="bye!"; }  }}

Q:updateprop is clearly the value of the value, the bar modification how can affect the bar1 in main?

Extension Q: What exactly is a value-by-value, reference-pass value?

To answer these questions, we need to understand the evaluation strategy!

What is evaluation strategy?

Evaluation strategy is actually the definition of when the arguments for a function/method should be evaluated and what type of value is passed into the function/method interior.

A programming language uses an evaluation strategy to determine when to evaluate the argument (s) of a function CA ll (for function, also read:operation, method, or relation) and what kind of value to pass to the function.

With time dimensions, there are three categories of evaluation strategies:

1. Strict/eager Evaluation, evaluates the arguments before executing the function (essentially before the function execution context is built).

2. Non-strict Evaluation (Lazy Evaluation), evaluates the argument only when the function is executed.

3. Non-deterministic, the timing of argument evaluation is erratic.

It is also important to note that most programming languages employ more than one evaluation strategy.

Strict/eager Evaluation

Most languages now support this type of evaluation strategy, and we're used to it, so we're so excited when lazy computations like LINQ, LAMBDA expression, and so forth.

But Strict/eager evaluation also includes a lot of specific definitions, let's take a look at each one.

applicative Order (Evaluation)

Applicative Order aka leftmost innermost, Chinese translation as "application sequence", the actual operation process and Post-order tree traversal algorithm is similar, must first calculate the leaf node and then compute the root node, Therefore, the following example causes a memory overflow bug to occur when an argument is evaluated.

// function Definitions function foo () {  return false | | foo ()}function test (A, f) {  + f)}//  main thread, Fall into Foo function hentai recursive call in test (1, foo ())


By value, which is one of the most common evaluation strategies, the actual operation is to clone the argument and assign the copy to the parameter variable.

function foo (val) {  3}var1//  display 1/ the value of the variable bar in the global scope is not affected by the assignment of an argument to a function scope.  

So what is the case with C # in brief? In fact, the problem is where to clone the "value", for bar bar = new Bar (), the bar corresponds to the memory space for a pointer to the new bar () memory space, and so the clone is a pointer instead of the new bar () This object, In other words, the clone is the "value" of the memory space where the argument corresponds. If we define bar as a struct rather than a class, then we understand that C # does follow the Call-by-value strategy.

namespacefoo{structbar{ PublicString msg{Get;Set;} }  classprogram{ Public Static voidMain (string[] args) {Bar bar1=NewBar (); Bar1. MSG="Hey, man!";      Updateprop (BAR1); Console.WriteLine (bar1. MSG); //hey,man!    }    Static voidUpdateprop (bar bar) {bar. MSG="bye!"; }  }}

To summarize a little, Call-by-value has the following features:

1. If the cloned "value" is a value type then the value itself, and any modifications within the function will not affect the value of the external corresponding variable;

2. If the cloned "value" is a reference type then the memory address, and the modification within the function will affect the value of the external corresponding variable, but the assignment operation does not affect the value of the external corresponding variable.

Note: Since the 2nd feature is the same as call-by-sharing, Java should be a call-by-sharing strategy, but the community claims that Java is using the Call-by-value strategy.


In fact, Call-by-reference and Call-by-value as easy to be misunderstood, thinking that the memory address as the actual parameter is call-by-reference, but it is not. The key is that this "memory address" is the memory address of the argument, not the address in memory that corresponds to the argument. C-language Wood has a natural support for call-by-reference strategy, but can be simulated by pointers, but it allows us to better understand the entire evaluation process.

inti =1;int*pi = &i;//&i will get the address of I corresponding memory space and store it in the corresponding memory space of pi.voidFooint*);voidFooint*PI) {PI=2;//Direct operation I corresponds to the memory space, equivalent to i = 2}intMain () {foo (pI); printf ("%s", i);//returns 2  return 0;}

Memory structure:

C # can be set using call-by-reference policy by adding ref or out on formal parameters, and Java and JavaScript are inherently unsupported and do not provide a way to simulate.


The language in which the policy is used implies that the language is primarily based on reference types rather than value types.

Call by sharing implies this values in the language is based on objects rather than primitive types, i.e. that's all values Is "boxed".

It's obvious that Java and Java-influenced JavaScript are using this strategy.

The characteristics of this strategy are consistent with the characteristics of call-by-value.

call-by-copy-restore (copy in copy out, Call-by-value-result, Call-by-value-return)

For the time being, I'm not in touch with any language. The evaluation strategy of Call-by-copy-restore is mainly divided into two steps:

1. As in the case of Call-by-value 1, copy the arguments and pass the copy to the function body. The point is that even if the argument is a reference type, the object that the reference points to is copied, not just the pointer.

Effect: Any manipulation of the arguments in the function body (Putvalue and assignment) does not affect the externally corresponding variables.

2. When exiting the function execution context, assign the argument value to the external corresponding variable.

 /***  pseudo code ***/ varA ={}function foo (a) {'Fsjohnhuang'Console.log ('within Foo:' hangs 1000ms  varSD = +NewDate () while(+NewDATE-SD < +);}//Execute foo asynchronouslyvarPromise = foo.Async(a) while(+NewDATE-SD < -);//when the execution context of Foo is not exited, access and return undefinedConsole.log ( {//returns when exiting the execution context of Foo, returning ' Fsjohnhuang 'Console.log (}

Partial Evaluation

That is, part of the argument will not participate in the evaluation operation until the function execution context is entered. Examples are as follows:

var ' Freevar ' }function GetName () {  return  freevar}function print (MSG, fn) {  + fn ())}  //  GetName will not be evaluated immediately when print is called ('Hi,', GetName)

You can see that the above print function call does not immediately evaluate the getname argument, but will immediately evaluate the ' Hi '. It is important to note that, since getname is a delay calculation, if there are free variables (such as Freevar) in the function body, then each subsequent calculation may be different (that is, side effect).

Non-strict Evaluation (Lazy-evaluation/calculation)

Non-strict evaluation is a strategy that requires this argument to be used in the process of executing a function body. Remember the short-circuit operation (short-circuit evaluation) of the logical operator (| |,&&)? This is one example of a delay calculation.

Let's take a look at 4 kinds of lazy computing strategies!

Normal Order (Evaluation)

Normal order also known as leftmost outermost, Chinese translation as "normal sequence", generally through the comparison with the applicative order to understand the effect is better. Remember that applicative order might cause a memory overflow problem? That is because the applicative order will continue to evaluate the value of the highest-level protocol expression node in the AST layer, while the normal order uses the most shallow, configurable expression node of the AST middle number.

/ function definitionsfunction foo () {  returnfalse | | foo ()}function test (A, f) {  + f)}//  main thread, display "1false"Test (1, Foo ())


This delay calculation strategy is easy to understand, the calculation process is the execution of the function body, when you encounter the need to calculate an argument expression to perform the operation. Note the point:

1. The operation is performed each time an argument expression is executed;

2. If the operation of an argument is computationally intensive or blocking, it blocks the execution of subsequent commands on the function body. (This can be optimized by thunk for Call-by-name)


In fact, Call-by-name + memoized, which is the first calculation of an argument expression, automatically saves the result when the result is returned, and returns the result of the first calculation when the next execution of an argument expression evaluates. Note the point:

1. This policy applies only to the pure function's arguments, and the presence of free variable results in an inability to ensure that each evaluation result is the same.


When using macro in Clojure, the call-by-macro-expansion strategy is used, and the expansion phase is replaced with the expression defined by macro in the function body, and then the operation is performed.

Non-deterministic Strategies

In addition, due to the uncertainty of the operation timing of the arguments, the following strategies cannot be classified into the strict and non-strict evaluation strategies.


This is a concurrency evaluation strategy, which is to delegate the evaluation operation to the future, and the subsequent promise to complete the evaluation operation, and then the caller to obtain the evaluation result through the next. Note the point:

1. The evaluation operation may occur when the future is created, or it is possible to invoke the future to obtain the result when the value is evaluated.


The above is to consult the data, the understanding of several types of evaluation strategy, if there are flaws please correct me, thank you!

Respect the original, reprint please indicate from: Fat boy John ^_^






PLT: Talk about evaluation strategy

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.