Traversing data is one of the most common elements of programming. Generally this means you have some sort of collection. If you are interested in seeing the different ways languages approach the foreach loop visit Rosetta Code. However I do not think it does a good job of showing the nuances of the approach. I will start with the basics in D, and use D as the bed for comparing differences.
List of Items
// D
import std;
void main()
auto vehicles = ["car", "truck", "boat", "rv"];
foreach(vehicle; vehicles) {
writeln(vehicle);
}
}
It uses a specific keyword foreach
and separates the variable declaration (on the left) from the iterable (on the right) with a semicolon. D has type inference and does not require a type to be specified for the variable.
// Javascript
["car", "truck", "boat", "rv"].forEach(
function (vehicle) {
console.log(vehicle);
}
);
Here we see that foreach provided as a function which takes a lambda. This method lives on the array type and is not available to other iterable types. D provides a generic template to operate in this manner.
// D
vehicles.each!(vehicle =>
writeln(vehicle));
// C#
string[] things = {"car", "truck", "boat", "rv"};
foreach (var thing in things)
{
Console.WriteLine(thing);
}
C# also has type inference which is explicitly requested. in
separate the variable from the iterable. If you are dealing with the List type C# provides a ForEach method just like Javascript, unlike D it is not available to other iterable types.
-- Lua
auto vehicles = {'car', 'truck', 'boat', 'rv'}
for key, vehicle in ipairs(vehicles) do
print(key, vehicle)
end
Lua uses just the keyword for
probably because it does not provide a C style for
loop.
It also has ipairs
to iterate over positive keys in order. Lua does not have arrays or lists, the only data structure is a table (conceptually an associative array). This means iteration is defined by that extra call.
Dictionary
-- Lua
vehicleMake= {truck='Dodge', car='Honda', boat='Schaefer', rv='Forest River' }
for key, value in pairs(vehicleMake) do
print(key, value)
end
Instead here we use pairs
to get at everything in the table. Let's revisit the other languages.
// C#
var vehicleMake = new Dictionary<string, string>
{
["car"] = "Honda",
["truck"] = "Dodge",
["boat"] = "Schaefer",
["rv"] = "Forest River",
}
foreach(var item in vehicleMake) {
System.Output.WriteLine($"{item.Key} {item.Value}");
}
In this case we see that the key and value are provided in a wrapping type and is not automatically expanded within foreach.
// D
auto vehicleMake = ["truck" : "Dodge", "car" : "Honda", "boat" : "Schaefer", "rv" : "Forest River"];
foreach(key, value; vehicleMake) {
writeln(key, ": ", value);
}
D maintains the same syntax for dictionary iteration. But it is not only available to dictionary, A range returning a tuple will expand within foreach.
//D
auto vehicleMake = [tuple("truck", "Dodge", 8),
tuple("car", "Honda", 4),
tuple("boat", "Schaefer", 5),
tuple("rv", "Forest River", 8)].map!(x => x);
foreach(key, value, num; vehicleMake) {
writeln(key, ": ", value, "-", num);
}
The comma operator is deprecated and there is hope to use it for expansion during assignments, not just in foreach.
You should also notice the identity map used on the array. This is because arrays get special treatment with foreach and so tuple expansion does not happen and this trick turns it into a range.
Another language which takes advantage of tuples to make this work is Python.
#Python
vehicleMake = {"truck" : "Dodge", "car" : "Honda", "boat" : "Schaefer", "rv" : "Forest River"}
for key, value in vehicleMake.items():
print(key, value)
The call for items() provides a tuple used to expand into key and value.
Changing Types
In this little experiment I am going to utilize the basic for each with the two types (array, associative array). You be the judge.
// D
auto arr = ["one", "two"];
auto dict = [1:"one", 2:"two"];
writeln("Array:");
foreach(value; arr) writeln(value);
writeln("Dictionary:");
foreach(value; dict) writeln(value);
/* // output
Array:
one
two
Dictionary:
two
one
*/
// C#
using System;
using System.Collections.Generic;
public class Program {
public static void Main() {
var arr = new string[] {"one", "two"};
var dict = new Dictionary<int, string>() { [1] ="one", [2] ="two"};
Console.WriteLine("Array:");
foreach(var val in arr)
Console.WriteLine(val);
Console.WriteLine("Dictionary:");
foreach(var val in dict)
Console.WriteLine(val);
}
}
/* // output
Array:
one
two
Dictionary:
[1, one]
[2, two]
*/
-- Lua
arr = {"one", "two"}
dict = {[1] ="one", [2] ="two", [0]="zero" }
print("Array:");
for value in ipairs(arr) do print(value) end
print("Dictionary:");
for value in ipairs(dict) do print(value) end
--[[ output
Array:
1
2
Dictionary:
1
2
--]]
Notice the dictionary does not print 0
.
I needed to modify the Lua dictionary in order to demonstrate this languages odd behavior. Because I used integers as a key Lua sees it the same as the array (they are the same because they are both tables). Other dictionaries with strings would not print if you use ipairs
.
# Python
arr = {"one", "two"}
dict = {1:"one", 2:"two"}
print("Array:")
for value in arr:
print(value)
print("Dictionary:")
for key in dict:
print(key)
# output
#Array:
#two
#one
#Dictionary:
#1
#2
Python provides the dictionary key rather than the value as other languages have.
Top comments (0)