The FOREACH statement is a well-known modern programming construct that allows you to iterate sequentially over the elements in an array or collection. The advent of generics in Synergy .NET (released in Synergy/DE 9.5) adds icing to the cake, as the FOREACH statement in Synergy .NET can now be used to iterate over the elements in a generic collection. Consider the following example:
import System.Collections.Generic
main
record
vals, @list ;list is a generic collection
ivar, int
proc
vals = new list()
vals.Add(2)
vals.Add(4)
foreach ivar in vals ;Iterating over a generic collection
Console.WriteLine(ivar)
end
I will be using the term “non-CLS” quite a bit in this article. In a nutshell, types that conform to the .NET Common Language Specification (CLS) are CLS compliant, and those that don’t are referred to as non-CLS types. CLS compliance is beyond the scope of this article, and I recommend that you browse through the MSDN pages on this topic if you are interested in more information. For the purpose of this article, just keep in mind that a structure containing Synergy types (a, d, d., etc.) is a non-CLS structure.
In the above example, the type of the ivar loop variable and the type of the element in the collection are both int. While other .NET languages, such as C# and VB, enforce type equality between the loop variable and the element in the collection in a FOREACH statement, Synergy relaxes this requirement (with a twist, to be explained shortly), primarily because of the way it treats alpha types and non-CLS structure types. A non-CLS structure field can be used wherever an alpha field is expected, and vice versa, in Synergy. In other words, from a Synergy programmer’s perspective, it is perfectly acceptable to use a loop variable of type alpha to iterate over elements of a non-CLS structure type in a collection (for example, an ArrayList).
We ensured that this functionality was available in Synergy .NET by introducing a novel feature to the FOREACH construct: the AS clause. Consider another example where a loop variable is of type alpha and the collection contains elements of a non-CLS structure type:
import System.Collections;
structure fred
afld, a50, "Synergy .NET is so cool"
endstructure
main
record
alist, @ArrayList
sfld, fred
svar, fred
avar, a50
proc
alist = new ArrayList();
alist.Add((object)sfld)
sfld.afld = "I must try it out to see how cool it is"
alist.Add((object)sfld)
foreach svar in alist
Console.WriteLine(svar.afld)
foreach avar in alist as @fred
Console.WriteLine(avar)
end
In the above example, the first FOREACH loop is straightforward, because the loop variable and the elements in the ArrayList (after they are unboxed) are of the same type (in this case, “fred”). In the second FOREACH, however, we have a loop variable of type alpha, and the items added to the ArrayList are of the type structure fred. By specifying “as @fred”, we indicate that the elements in the ArrayList are either of that type or of a type that can be cast to the type indicated in the AS clause. Note that if the “as @fred” part is omitted, you will get a runtime exception as you execute the code. Also note that the AS clause is ignored in traditional Synergy.
A question that comes to mind is whether we then use the AS clause every time we use FOREACH in Synergy .NET. The answer is a resounding “No.” Doing so would generate compile-time errors. Recall that the AS clause is needed only when the type of the variable is different from the type of the items added to the collection. Moreover, note that FOREACH is only allowed on a collection that implements the IEnumerable or the generic IEnumerable<T> interface. The interface provides a method, GetEnumerator(), that returns the Enumerator (or Enumerator<T>) object, which in turn is used to iterate over the elements in the collection. In the case of a collection such as ArrayList, where the compiler is clueless about the type of the items added to the collection, the Enumerator returned by the GetEnumerator() call is an untyped one, whereas the one returned in the case of List<int> is a typed one. Using the AS clause with the FOREACH statement to iterate over a collection whose Enumerator is typed generates a compile-time error. For example:
import System.Collections.Generic
main
record
vals, @list
var, d10
proc
vals = new list()
vals.Add(2)
vals.Add(4)
foreach var in vals as @int
Console.WriteLine(var)
end
The code above generates a NOTALLOWED error (“AS clause not allowed in FOREACH over a collection with typed enumerator”) during compilation.
So now you know how to use this novel feature of Synergy .NET, and you can apply this twist to your own code where necessary. When used appropriately, the AS clause helps tie up the loose ends when a loop variable in a FOREACH statement is one type, the elements in the collection are a different type, and a conversion exists between the types.
For more information about the AS clause, refer to FOREACH in the Synergy Language Reference Manual.
For more information about Synergy/DE 9.5, see our website.