Yield Better Code in Version 10

By Jim Sahaj, Senior Systems Software Engineer

Do you ever wish you could write code that can create a collection on the fly by performing complex logic and keep it separate from the logic that iterated over it?  In Synergy .NET version 10, we introduce the new YIELD language construct that works with enumerations to do just that.

To see how to create a collection on the fly using YIELD, let’s look at an example:

import  System.Collections
                 
namespace ns1
public class List
 
    public static method Power, @IEnumerable
        number, int 
        exponent, int
    proc
        data counter, int, 0
        data result, int, 1
        while (counter < exponent)
        begin
            incr counter
            result = result * number
            yield mreturn result
        end
    endmethod
endclass
endnamespace
 
main
proc
data i, int
foreach i in  ns1.List.Power(2, 8)
        Console.Write("{0} ", i)
end

In this code, the Power() method takes a number and produces a power of that number up to the exponent power.  Note that the YIELD is on the MRETURN of a method that returns an Enumerable interface.  Under the covers, the compiler creates an enumeration that gets filled by successive calls to YIELD MRETURN in Power().  Each time Power() is called the YIELD MRETURN adds the value to the enumeration and the loop is essentially suspended at that place until the next call of Power(), at which point it will retest the conditional (counter < result) and proceed from there.

The YIELD statement comes in two forms, YIELD MRETURN expression and YIELD EXIT.  The YIELD MRETURN gives the next value to put in the collection.  It will continue returning until the YIELD MRETURN statement isn’t reached because of surrounding conditionals, in this case when counter >= exponent.   If you need to terminate the addition of values, without regard to surrounding conditionals, use YIELD EXIT.

When YIELD is specified, the compiler creates state-based code that stores the values in variables within Power() across calls to Power() through a hoisting mechanism.   In this example, counter, result, number, and exponent values are preserved across calls, enabling the calculation of the next value based on these values.  This enables us to put the complex calculation in the Power() method and put the processing of the collection in a separate loop away from the complexity of that calculation, making the code easier to follow and more readable.

Check out YIELD  in the Synergy/DE documentation for more detail on this powerful version 10 feature.