Implementation of custom iterator does not change one of its parameters - c#

I have this iterator and want it to stop on some condition, thus, there is a 3rd parameter called "condition".
public static IEnumerable<long> Dates(long start, int step, bool condition)
{
var k = start + step;
while (condition)
{
k += step;
yield return k;
}
}
I call it this way :
var i = 0;
foreach (var k in Iterator.Dates(0, 5, i++ < 100))
{
// Here goes infinite loop because (i++ < 100) is always true inside iterator
}
Unfortunately, this parameter does not change inside loop so now it is always true because seems that it gets executed only on the first iteration.
Question : how to check or execute "condition" on each iteration?

Argument is bool, but you need predicate function like this:
public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
var k = start + step;
while (condition())
{
k += step;
yield return k;
}
}
Usage:
var i = 0;
foreach (var k in Dates(0, 5, () => i++ < 100))
{
// Here goes infinite loop because (i++ < 100) is always true inside iterator
}
Comments
() => i++ < 100 is lambda expression similar to boolean function without arguments that returns i++ < 100.

What you want to provide is a piece of functionality, a rule. Instead you have provided a value, and this value is calculated in the expression before the method is called and thus inside the method it is constant, never changes, exactly like you observed.
Instead you need to pass in a delegate, you "delegate" the responsibility of providing the rule to the caller.
A simple delegate type appropriate for this example is Func<T> which is basically defined like this:
public delegate T Func<T>();
This is a delegate that wraps a method that returns a value, without taking any parameters.
Since you want to use the result of this function in a while statement, you need it to return bool.
Here's how you would declare the method:
public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
var k = start + step;
while (condition())
{
k += step;
yield return k;
}
}
Note that you need to change the while expression to call the delegate. Since it wraps a method, to obtain the value from the method you have to call it.
Here's how to call the new method:
var i = 0;
foreach (var k in Iterator.Dates(0, 5, () => i++ < 100))
{
// No longer infinite loop because (i++ < 100) is now evaluated on every iteration
}
This new expression:
() => i++ < 100
is basically the same as writing this:
int i;
bool Func()
{
return i++ < 100;
}
but wrapped in a smaller syntax.
Now, every time the loop runs one iteration, it will call this func, which will increase the value and compare it to 100.

Related

Why does Lazy<T> using ExecutionAndPublication behave differently with yielded IEnumerables?

I had a problem in my code where a Lazy initializer was called more frequently than what I expected. From the documentation, I expected that using LazyThreadSafetyMode.ExecutionAndPublication would ensure my initializer function was only ever called once, for example if accessing numbers.Value after defining:
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
However, what I have found is that if the initialization function yields its results, the initialization function gets called more than once. I presume this has to with yields delayed execution but I only have a fuzzy sense why.
Question:
In the code below, why do the respective initialization functions get executed a different number of times?
void Main()
{
var foo = new foo();
var tasks = new List<Task>();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var number in foo.Numbers) Debug.WriteLine(number);}));
Task.WaitAll(tasks.ToArray());
tasks.Clear();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var letter in foo.Letters) Debug.WriteLine(letter);}));
Task.WaitAll(tasks.ToArray());
}
public class foo
{
public IEnumerable<int> Numbers => numbers.Value;
public IEnumerable<char> Letters => letters.Value;
readonly Lazy<IEnumerable<int>> numbers;
readonly Lazy<IEnumerable<char>> letters;
public foo()
{
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
letters = new Lazy<IEnumerable<char>>(
() => GetLetters().ToList(), //ToList enumerates all yielded letters, creating the expected call once behavior
LazyThreadSafetyMode.ExecutionAndPublication
);
}
protected IEnumerable<char> GetLetters()
{
Debug.WriteLine($"{nameof(GetLetters)} Called");
yield return 'a';
yield return 'b';
yield return 'c';
yield break;
}
protected IEnumerable<int> GetNumbers()
{
Debug.WriteLine($"{nameof(GetNumbers)} Called");
yield return 1;
yield return 2;
yield return 3;
yield break;
}
}
I had a problem in my code where a Lazy initializer was called more frequently than what I expected.
No, the initializer of the lazy is called once. The initializer of the lazy is
() => GetNumbers()
and that is called exactly once.
GetNumbers returns an IEnumerable<int> -- a sequence of integers.
When you foreach that sequence, it calls GetEnumerator to get an enumerator, and then calls MoveNext on the enumerator object until MoveNext returns false.
You've said that you want the sequence to be enumerated as:
the first time MoveNext is called, do a writeline and produce 1
the second time MoveNext is called, produce 2
the third time MoveNext is called, produce 3
the fourth time MoveNext is called, produce 4
Every subsequent time MoveNext is called, return false
So every time you enumerate the sequence, that's what happens.
Can you explain what you expected to happen? I am interested to learn why people have false beliefs about computer programs.
Also it is not clear to me why you are using Lazy at all. You would typically use Lazy to avoid expensive work until it is needed, but sequences already defer work until they are enumerated.

Why for loop want take parameters of function in c#?

Why this code doesn't work?
private void Function(int starts , int ends)
{
int i = starts;
int z = ends;
for(i; i < z; i++)
{
[...]
}
}
It's say: Error 3 Only assignment, call, increment, decrement, and new object expressions can be used as a statement.
What to do to make code work?
What to do to make code work?
How about
for (; i < z; i++)
{
[...]
}
OR why creating an extra variable 'z' when you can do
for (int i = starts; i < ends; i++)
{
[...]
}
Why your code doesn't not work!!
Because syntax of for loop is
for (initializer; condition; increment or decrement)
{
}
You were not initializing i in initializer. You could initialize it (as my second snippet) or remove initializer if you are initializing it in some earlier statement(as my first snippet).
i in and of itself is not a statement, it's an expression. In the same way that you can-not simply write i; somewhere in your code. The initialization-part of a for-loop needs to be initialization; however, if (as is the case here) the loop is already initialized (i is already set), you can just omit it as Nikhil showed. Simply do for(;i<z;i++).
The first part of the for loop takes initialization statements. i is not a statement. If you don't want to initialize anything, you can leave that part empty, as in Nikhil's answer:
for(; i < z; i++)
{
[...]
}
Never use outside-defined variables as indexers in for loops.
private void Function(int starts , int ends)
{
// int i = starts; // don't do it. you're exposing yourself to headaches if/when you lose control of the value of i
int z = ends;
for(int i = starts; i < z; i++) //first statement of for loops initializes the indexer
{
[...]
}
}
I think this is the better answer is it not?
private void Function(int starts , int ends)
{
for(int i = starts; i < ends; i++)
{
[...]
}
}

Can an Action/delegate change it's arguments value?

I ran into what was to me an unexpected result when testing a simple ForEach extension method.
ForEach method
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null) throw new ArgumentNullException("action");
foreach (T element in list)
{
action(element);
}
}
Test method
[TestMethod]
public void BasicForEachTest()
{
int[] numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.ForEach(num =>
{
num = 0;
});
Assert.AreEqual(0, numbers.Sum());
}
Why would numbers.Sum() be equal to 55 and not 0?
num is the copy of the value of the current element you are iterating over. So you are just changing the copy.
What you do is basically this:
foreach(int num in numbers)
{
num = 0;
}
Surely you do not expect this to change the content of the array?
Edit: What you want is this:
for (int i in numbers.Length)
{
numbers[i] = 0;
}
In your specific case you could maintain an index in your ForEach extension method and pass that as second argument to the action and then use it like this:
numbers.ForEachWithIndex((num, index) => numbers[index] = 0);
However in general: Creating Linq style extension methods which modify the collection they are applied to are bad style (IMO). If you write an extension method which cannot be applied to an IEnumerable<T> you should really think hard about it if you really need it (especially when you write with the intention of modifying the collection). You have not much to gain but much to loose (like unexpected side effects). I'm sure there are exceptions but I stick to that rule and it has served me well.
Because num is a copy.
It's as if you were doing this:
int i = numbers[0];
i = 0;
You wouldn't expect that to change numbers[0], would you?
Because int is a value type and is passed to your extension method as a value parameter. Thus a copy of numbers is passed to your ForEach method. The values stored in the numbers array that is initialized in the BasicForEachTest method are never modified.
Check this article by Jon Skeet to read more on value types and value parameters.
I am not claiming that the code in this answer is useful, but (it works and) I think it illustrates what you need in order to make your approach work. The argument must be marked ref. The BCL does not have a delegate type with ref, so just write your own (not inside any class):
public delegate void MyActionRef<T>(ref T arg);
With that, your method becomes:
public static void ForEach2<T>(this T[] list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Length; idx++)
{
actionRef(ref list[idx]);
}
}
Now, remember to use the ref keyword in your test method:
numbers.ForEach2((ref int num) =>
{
num = 0;
});
This works because it is OK to pass an array entry ByRef (ref).
If you want to extend IList<> instead, you have to do:
public static void ForEach3<T>(this IList<T> list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Count; idx++)
{
var temp = list[idx];
actionRef(ref temp);
list[idx] = temp;
}
}
Hope this helps your understanding.
Note: I had to use for loops. In C#, in foreach (var x in Yyyy) { /* ... */ }, it is not allowed to assign to x (which includes passing x ByRef (with ref or out)) inside the loop body.

Is there an "upto" method in C#?

Here's a bit of code which prints out the squares of the numbers from 0 to 9:
for (int i = 0; i < 10; i++)
Console.WriteLine(i*i);
Doing something from 0 to N by 1 via a for loop is a very common idiom.
Here's an UpTo method which expresses this:
class MathUtil
{
public static void UpTo(int n, Action<int> proc)
{
for (int i = 0; i < n; i++)
proc(i);
}
}
The squares example above is now:
MathUtil.UpTo(10, (i) => Console.WriteLine(i * i));
My question is, does the standard C# library come with something like the above UpTo?
Ideally, I'd like a way to have 'UpTo' be a method on all integer objects. So I could do:
var n = 10;
n.UpTo(...);
Is this possible in C#?
Turn it into an extension method (note the this before the n parameter, which defines the type this method operates on):
static class MathUtil
{
public static void UpTo(this int n, Action<int> proc)
{
for (int i = 0; i < n; i++)
proc(i);
}
}
Usage:
10.UpTo((i) => Console.WriteLine(i * i));
Note: The above method call isn't particularly intuitive though. Remember code is written once and read many times.
Maybe allowing something like below might be slightly better, but to be honest i'd still just write a foreach loop.
0.UpTo(10 /*or 9 maybe*/, (i) => Console.WriteLine(i * i));
If you wanted this, then you could write an extension method like this:
public static void UpTo(this int start, int end, Action<int> proc)
{
for (int i = start; i < end; i++)
proc(i);
}
Change < to <= if you want an inclusive upper bound.
Take a look at LINQ TakeWhile or for your specific case of integers, use Enumerable.Range
Enumerable.Range(1, 10).Select(i => ...);
Arguably you shouldn't be putting an Action on the end there, see comments on ForEach here.
Try this:
public static class IntExtensions
{
public static void UpTo(this int n, Action<int> proc)
{
for (int i = 0; i < n; i++)
proc(i);
}
}
With this you could write
10.UpTo(i => Console.WriteLine(i * i));
The function I wrote is called an extension method.
At design time you notice is not a native function because it has a different icon.
Estension methods are static methods or functions included in a static class and type they work on is the first param on which you must use this keyword.
In IntExtensions class you could write all methods you please; grouping them inside the same static class makes you easy manage them.
wanna do it in one line ? here it goes:
Enumerable.Range(0, 9).Select(i => i * i).ToList().ForEach(j=>Console.WriteLine("%d",j));
Try Enumerable.Range, possibly in combination with Take or TakeWhile:
IEnumerable<int> values = Enumerable.Range(0, 20)
.Take(10); // Not necessary in this example
foreach(var value in values)
{
Console.WriteLine(value);
}
// or ...
foreach(var i in Enumerable.Range(0, 10))
{
Console.WriteLine(i * i);
}
There is a ForEach on List<T> that you could use to get closer syntax to what you want, but I consider it bad form. It takes a pure query/filter/transform syntax, that works in an effectively immutable fashion, and introduces side-effects.
For your future amusement you might want to check out extension methods, IEnumerable<T>, and yield return. A lot of generator-type functionality and interesting syntax becomes possible when you use those three things in combination. Although I would argue that this particular example isn't the best place to use them because the resulting syntax becomes a mess.
Make your method like this in a static class "Extensions" for example:
public static void UpTo(this int n, Action<int> proc)
{
for (var i = 0; i < n; i++)
proc(i);
}
And the usage:
var n = 10;
n.UpTo(i => Console.WriteLine(i * i));
Hope this helps! :)

Need help in terminating deferred execution

The following snippet prints 1 through 10 on the console, but does not terminate until variable 'i' reaches int.MaxValue. TIA for pointing out what I am missing.
class Program
{
public static IEnumerable<int> GetList()
{
int i = 0;
while (i < int.MaxValue)
{
i++;
yield return i;
}
}
static void Main(string[] args)
{
var q = from i in GetList() // keeps calling until i reaches int.MaxValue
where i <= 10
select i;
foreach (int i in q)
Console.WriteLine(i);
}
}
You could try:
var q = GetList ().TakeWhile ((i)=> i <=10);
The query that you defined in Main doesn't know anything about the ordering of your GetList method, and it must check every value of that list with the predicate i <= 10. If you want to stop processing sooner, you will you can use the Take extension method or use the TakeWhile extension method:
foreach (int i in GetList().Take(10))
Console.WriteLine(i);
foreach (int i in GetList().TakeWhile(x => x <= 10))
Console.WriteLine(i);
Your iterators limits are 0 through Int32.MaxValue, so it will process that whole range. Iterators are only smart enough to not pre-iterate the results of the range of data you design it to iterate. However they are not smart enough to know when the code that uses them no longer needs more unless you tell it so (i.e. you break out of a foreach loop.) The only way to allow the iterator to limit itself is to pass in the upper bound to the GetList function:
public static IEnumerable<int> GetList(int upperBound)
{
int i = 0;
while (i < upperBound)
{
i++;
yield return i;
}
}
You could also explicitly tell the iterator that you only wish to iterate the first 10 results:
var numbers = GetList().Take(10);
Consider using the LINQ extension method .Take() with your argument instead of having it in your where clause. More on Take.
var q = from i in GetList().Take(10)
select i;

Categories