I'm struggling a bit to find it on https://github.com/fsharp/fsharp
and this is very important because I need to ensure the least amount of collisions possible.
As VoroniPotato mentions, you might want to override GetHashCode yourself, but the default implemention of GetHashCode works like the following for a record. Assuming fields is a list of the value of the fields in the record, then the following steps are done:
Start with an initial value of 0.
Then for each element in field, starting from the last one defined (i.e. given the record type {a: int; b: string} we start with b), do the following:
0x9e3779b9 + fields.[i].GetHashCode() + (value <<< 6) + (value >>> 2), where value is the value from the previous iteration of the algorithm. We assume fields.[i] isn't null, otherwise its hash value is just set to 0.
Repeat step 2 for all fields.
You can see this in the source code from the code for mkRecdHashWithComparer and mkAddToHashAcc.
For the simple example record of {a: int; b: string}, the decompiled GetHashCode method is this:
[CompilerGenerated]
public sealed override int GetHashCode(IEqualityComparer comp)
{
if (this != null)
{
int num = 0;
num = -1640531527 + ((b#?.GetHashCode() ?? 0) + ((num << 6) + (num >> 2)));
return -1640531527 + (a# + ((num << 6) + (num >> 2)));
}
return 0;
}
Well I can tell you it's not going to provide the least amount of collisions possible. You may want to override GetHashCode. Some have complained that it didn't fit their hashing needs but that for backwards compatiblity it couldn't reasonably be changed. I would add an issue on the github visual fsharp repository if this a serious issue for you due to performance considerations of checking conflicted hashes.
Update, Sources:
github.com/fsharp/fslang-suggestions/issues/366
github.com/fsharp/fsharp/issues/343
github.com/Microsoft/visualfsharp/issues/1838
Related
I have some code and when it executes, it throws a IndexOutOfRangeException, saying,
Index was outside the bounds of the array.
What does this mean, and what can I do about it?
Depending on classes used it can also be ArgumentOutOfRangeException
An exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll but was not handled in user code Additional information: Index was out of range. Must be non-negative and less than the size of the collection.
What Is It?
This exception means that you're trying to access a collection item by index, using an invalid index. An index is invalid when it's lower than the collection's lower bound or greater than or equal to the number of elements it contains.
When It Is Thrown
Given an array declared as:
byte[] array = new byte[4];
You can access this array from 0 to 3, values outside this range will cause IndexOutOfRangeException to be thrown. Remember this when you create and access an array.
Array Length
In C#, usually, arrays are 0-based. It means that first element has index 0 and last element has index Length - 1 (where Length is total number of items in the array) so this code doesn't work:
array[array.Length] = 0;
Moreover please note that if you have a multidimensional array then you can't use Array.Length for both dimension, you have to use Array.GetLength():
int[,] data = new int[10, 5];
for (int i=0; i < data.GetLength(0); ++i) {
for (int j=0; j < data.GetLength(1); ++j) {
data[i, j] = 1;
}
}
Upper Bound Is Not Inclusive
In the following example we create a raw bidimensional array of Color. Each item represents a pixel, indices are from (0, 0) to (imageWidth - 1, imageHeight - 1).
Color[,] pixels = new Color[imageWidth, imageHeight];
for (int x = 0; x <= imageWidth; ++x) {
for (int y = 0; y <= imageHeight; ++y) {
pixels[x, y] = backgroundColor;
}
}
This code will then fail because array is 0-based and last (bottom-right) pixel in the image is pixels[imageWidth - 1, imageHeight - 1]:
pixels[imageWidth, imageHeight] = Color.Black;
In another scenario you may get ArgumentOutOfRangeException for this code (for example if you're using GetPixel method on a Bitmap class).
Arrays Do Not Grow
An array is fast. Very fast in linear search compared to every other collection. It is because items are contiguous in memory so memory address can be calculated (and increment is just an addition). No need to follow a node list, simple math! You pay this with a limitation: they can't grow, if you need more elements you need to reallocate that array (this may take a relatively long time if old items must be copied to a new block). You resize them with Array.Resize<T>(), this example adds a new entry to an existing array:
Array.Resize(ref array, array.Length + 1);
Don't forget that valid indices are from 0 to Length - 1. If you simply try to assign an item at Length you'll get IndexOutOfRangeException (this behavior may confuse you if you think they may increase with a syntax similar to Insert method of other collections).
Special Arrays With Custom Lower Bound
First item in arrays has always index 0. This is not always true because you can create an array with a custom lower bound:
var array = Array.CreateInstance(typeof(byte), new int[] { 4 }, new int[] { 1 });
In that example, array indices are valid from 1 to 4. Of course, upper bound cannot be changed.
Wrong Arguments
If you access an array using unvalidated arguments (from user input or from function user) you may get this error:
private static string[] RomanNumbers =
new string[] { "I", "II", "III", "IV", "V" };
public static string Romanize(int number)
{
return RomanNumbers[number];
}
Unexpected Results
This exception may be thrown for another reason too: by convention, many search functions will return -1 (nullables has been introduced with .NET 2.0 and anyway it's also a well-known convention in use from many years) if they didn't find anything. Let's imagine you have an array of objects comparable with a string. You may think to write this code:
// Items comparable with a string
Console.WriteLine("First item equals to 'Debug' is '{0}'.",
myArray[Array.IndexOf(myArray, "Debug")]);
// Arbitrary objects
Console.WriteLine("First item equals to 'Debug' is '{0}'.",
myArray[Array.FindIndex(myArray, x => x.Type == "Debug")]);
This will fail if no items in myArray will satisfy search condition because Array.IndexOf() will return -1 and then array access will throw.
Next example is a naive example to calculate occurrences of a given set of numbers (knowing maximum number and returning an array where item at index 0 represents number 0, items at index 1 represents number 1 and so on):
static int[] CountOccurences(int maximum, IEnumerable<int> numbers) {
int[] result = new int[maximum + 1]; // Includes 0
foreach (int number in numbers)
++result[number];
return result;
}
Of course, it's a pretty terrible implementation but what I want to show is that it'll fail for negative numbers and numbers above maximum.
How it applies to List<T>?
Same cases as array - range of valid indexes - 0 (List's indexes always start with 0) to list.Count - accessing elements outside of this range will cause the exception.
Note that List<T> throws ArgumentOutOfRangeException for the same cases where arrays use IndexOutOfRangeException.
Unlike arrays, List<T> starts empty - so trying to access items of just created list lead to this exception.
var list = new List<int>();
Common case is to populate list with indexing (similar to Dictionary<int, T>) will cause exception:
list[0] = 42; // exception
list.Add(42); // correct
IDataReader and Columns
Imagine you're trying to read data from a database with this code:
using (var connection = CreateConnection()) {
using (var command = connection.CreateCommand()) {
command.CommandText = "SELECT MyColumn1, MyColumn2 FROM MyTable";
using (var reader = command.ExecuteReader()) {
while (reader.Read()) {
ProcessData(reader.GetString(2)); // Throws!
}
}
}
}
GetString() will throw IndexOutOfRangeException because you're dataset has only two columns but you're trying to get a value from 3rd one (indices are always 0-based).
Please note that this behavior is shared with most IDataReader implementations (SqlDataReader, OleDbDataReader and so on).
You can get the same exception also if you use the IDataReader overload of the indexer operator that takes a column name and pass an invalid column name.
Suppose for example that you have retrieved a column named Column1 but then you try to retrieve the value of that field with
var data = dr["Colum1"]; // Missing the n in Column1.
This happens because the indexer operator is implemented trying to retrieve the index of a Colum1 field that doesn't exist. The GetOrdinal method will throw this exception when its internal helper code returns a -1 as the index of "Colum1".
Others
There is another (documented) case when this exception is thrown: if, in DataView, data column name being supplied to the DataViewSort property is not valid.
How to Avoid
In this example, let me assume, for simplicity, that arrays are always monodimensional and 0-based. If you want to be strict (or you're developing a library), you may need to replace 0 with GetLowerBound(0) and .Length with GetUpperBound(0) (of course if you have parameters of type System.Array, it doesn't apply for T[]). Please note that in this case, upper bound is inclusive then this code:
for (int i=0; i < array.Length; ++i) { }
Should be rewritten like this:
for (int i=array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i) { }
Please note that this is not allowed (it'll throw InvalidCastException), that's why if your parameters are T[] you're safe about custom lower bound arrays:
void foo<T>(T[] array) { }
void test() {
// This will throw InvalidCastException, cannot convert Int32[] to Int32[*]
foo((int)Array.CreateInstance(typeof(int), new int[] { 1 }, new int[] { 1 }));
}
Validate Parameters
If index comes from a parameter you should always validate them (throwing appropriate ArgumentException or ArgumentOutOfRangeException). In the next example, wrong parameters may cause IndexOutOfRangeException, users of this function may expect this because they're passing an array but it's not always so obvious. I'd suggest to always validate parameters for public functions:
static void SetRange<T>(T[] array, int from, int length, Func<i, T> function)
{
if (from < 0 || from>= array.Length)
throw new ArgumentOutOfRangeException("from");
if (length < 0)
throw new ArgumentOutOfRangeException("length");
if (from + length > array.Length)
throw new ArgumentException("...");
for (int i=from; i < from + length; ++i)
array[i] = function(i);
}
If function is private you may simply replace if logic with Debug.Assert():
Debug.Assert(from >= 0 && from < array.Length);
Check Object State
Array index may not come directly from a parameter. It may be part of object state. In general is always a good practice to validate object state (by itself and with function parameters, if needed). You can use Debug.Assert(), throw a proper exception (more descriptive about the problem) or handle that like in this example:
class Table {
public int SelectedIndex { get; set; }
public Row[] Rows { get; set; }
public Row SelectedRow {
get {
if (Rows == null)
throw new InvalidOperationException("...");
// No or wrong selection, here we just return null for
// this case (it may be the reason we use this property
// instead of direct access)
if (SelectedIndex < 0 || SelectedIndex >= Rows.Length)
return null;
return Rows[SelectedIndex];
}
}
Validate Return Values
In one of previous examples we directly used Array.IndexOf() return value. If we know it may fail then it's better to handle that case:
int index = myArray[Array.IndexOf(myArray, "Debug");
if (index != -1) { } else { }
How to Debug
In my opinion, most of the questions, here on SO, about this error can be simply avoided. The time you spend to write a proper question (with a small working example and a small explanation) could easily much more than the time you'll need to debug your code. First of all, read this Eric Lippert's blog post about debugging of small programs, I won't repeat his words here but it's absolutely a must read.
You have source code, you have exception message with a stack trace. Go there, pick right line number and you'll see:
array[index] = newValue;
You found your error, check how index increases. Is it right? Check how array is allocated, is coherent with how index increases? Is it right according to your specifications? If you answer yes to all these questions, then you'll find good help here on StackOverflow but please first check for that by yourself. You'll save your own time!
A good start point is to always use assertions and to validate inputs. You may even want to use code contracts. When something went wrong and you can't figure out what happens with a quick look at your code then you have to resort to an old friend: debugger. Just run your application in debug inside Visual Studio (or your favorite IDE), you'll see exactly which line throws this exception, which array is involved and which index you're trying to use. Really, 99% of the times you'll solve it by yourself in a few minutes.
If this happens in production then you'd better to add assertions in incriminated code, probably we won't see in your code what you can't see by yourself (but you can always bet).
The VB.NET side of the story
Everything that we have said in the C# answer is valid for VB.NET with the obvious syntax differences but there is an important point to consider when you deal with VB.NET arrays.
In VB.NET, arrays are declared setting the maximum valid index value for the array. It is not the count of the elements that we want to store in the array.
' declares an array with space for 5 integer
' 4 is the maximum valid index starting from 0 to 4
Dim myArray(4) as Integer
So this loop will fill the array with 5 integers without causing any IndexOutOfRangeException
For i As Integer = 0 To 4
myArray(i) = i
Next
The VB.NET rule
This exception means that you're trying to access a collection item by index, using an invalid index. An index is invalid when it's lower than the collection's lower bound or greater than equal to the number of elements it contains. the maximum allowed index defined in the array declaration
Simple explanation about what a Index out of bound exception is:
Just think one train is there its compartments are D1,D2,D3.
One passenger came to enter the train and he have the ticket for D4.
now what will happen. the passenger want to enter a compartment that does not exist so obviously problem will arise.
Same scenario: whenever we try to access an array list, etc. we can only access the existing indexes in the array. array[0] and array[1] are existing. If we try to access array[3], it's not there actually, so an index out of bound exception will arise.
To easily understand the problem, imagine we wrote this code:
static void Main(string[] args)
{
string[] test = new string[3];
test[0]= "hello1";
test[1]= "hello2";
test[2]= "hello3";
for (int i = 0; i <= 3; i++)
{
Console.WriteLine(test[i].ToString());
}
}
Result will be:
hello1
hello2
hello3
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
Size of array is 3 (indices 0, 1 and 2), but the for-loop loops 4 times (0, 1, 2 and 3). So when it tries to access outside the bounds with (3) it throws the exception.
A side from the very long complete accepted answer there is an important point to make about IndexOutOfRangeException compared with many other exception types, and that is:
Often there is complex program state that maybe difficult to have control over at a particular point in code e.g a DB connection goes down so data for an input cannot be retrieved etc... This kind of issue often results in an Exception of some kind that has to bubble up to a higher level because where it occurs has no way of dealing with it at that point.
IndexOutOfRangeException is generally different in that it in most cases it is pretty trivial to check for at the point where the exception is being raised. Generally this kind of exception get thrown by some code that could very easily deal with the issue at the place it is occurring - just by checking the actual length of the array. You don't want to 'fix' this by handling this exception higher up - but instead by ensuring its not thrown in the first instance - which in most cases is easy to do by checking the array length.
Another way of putting this is that other exceptions can arise due to genuine lack of control over input or program state BUT IndexOutOfRangeException more often than not is simply just pilot (programmer) error.
These two exceptions are common in various programming languages and as others said it's when you access an element with an index greater than the size of the array. For example:
var array = [1,2,3];
/* var lastElement = array[3] this will throw an exception, because indices
start from zero, length of the array is 3, but its last index is 2. */
The main reason behind this is compilers usually don't check this stuff, hence they will only express themselves at runtime.
Similar to this:
Why don't modern compilers catch attempts to make out-of-bounds access to arrays?
Our professor said that in computer logic it's important when you add a number to another so a+b and b+a are not always equal.
Though,I couldn't find an example of when they would be different and why they won't be equal.
I think it would have to do something with bits but then again ,I'm not sure.
Although you don't share a lot of context it sounds as if your professor did not elaborate on that or you missed something.
In the case that he was talking about logic in general, he could have meant that the behavior of the + operator depends on how you define it.
Example: The definition (+) a b := if (a==0) then 5 else 0 results in a + operator which is not associative, e.g. 1 + 0 would be 0 but 0 + 1 would be 5. There are many programming languages that allow this redefinition (overwriting) of standard operators.
But with the context you share, this is all speculative.
One obscure possibility is if one or other of a or b is a high-definition timer value - ticks since program start.
Due to the cpu cycle(s) consumed to pop one of the values before addition, it's possible the sum could be different dependant on the order.
One more possibility is if a and b are expressions with side effects. E.g.
int x = 0;
int a() {
x += 1;
return x;
}
int b() {
return x;
}
a() + b() will return 2 and b() + a() will return 1 (both from initial state).
Or it could be that a or b are NaN, in which case even a == a is false. Though this one isn't connected with "when you add a number to another".
I'm new to CoffeeScript and have been reading the book, The Little Book on CoffeeScript. Here are a few lines from the book's Chapter 2 which confused me while reading :
The only low-level loop that CoffeeScript exposes is the while loop. This has similar behavior to the while loop in pure JavaScript, but has the added advantage that it returns an array of results, i.e. like the Array.prototype.map() function.
num = 6
minstrel = while num -= 1
num + " Brave Sir Robin ran away"
Though it may look good for a CoffeeScript programmer, being a newbie, I'm unable to understand what the code does. Moreover, the words returns an array of results doesn't seem to go together with the fact that while is a loop construct, not a function. So the notion of it returning something seems confusing. Furthermore, the variable num with the string "Brave Sir Robin ran away" in every iteration of the loop seems to be awkward, as the value num is being used as the loop counter.
I would be thankful if you could explain the behavior of the code and perhaps illustrate what the author is trying to convey with simpler examples.
Wow! I didn't know that but it absolutely makes sense if you remember that Coffeescript always returns the last expression of a "block".
So in your case it returns (not via the "return" statement if that is what confuses you) the expression
num + " Brave Sir Robin ran away"
from the block associated with the while condition and as you will return multiple such expressions it pushes them on an array.
Have a look on the generated JavaScript and it might be clearer as the generated code is pretty much procedural
var minstrel, num;
num = 6;
minstrel = (function() {
var _results;
_results = [];
while (num -= 1) {
_results.push(num + " Brave Sir Robin ran away");
}
return _results;
})();
I hope that makes sense to you.
Beware, that function call can be very inefficient!
Below is a prime factors generator
'use strict'
exports.generate = (number) ->
return [] if number < 2
primes = []
candidate = 1
while number > 1
candidate++
while number % candidate is 0
primes.push candidate
number /= candidate
candidate = number - 1 if Math.sqrt(number) < candidate
primes
This is the version using while as expression
'use strict'
exports.generate = (number) ->
return [] if number < 2
candidate = 1
while number > 1
candidate++
primes = while number % candidate is 0
number /= candidate
candidate
candidate = number - 1 if Math.sqrt(number) < candidate
primes
First version ran my tests in 4 milliseconds, the last one takes 18 milliseconds. I believe the reason is the generated closure which returns the primes.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have the following Scala snippet. In order to solve my given problem, I "cheat" a little and use a var -- essentially a non-final, mutable data type. Its value is updated at each iteration through the loop. I've spent quite a bit of time trying to figure out how to do this using only recursion, and immutable data types and lists.
Original snippet:
def countChange_sort(money: Int, coins: List[Int]): Int =
if (coins.isEmpty || money < 0)
0
else if (coins.tail.isEmpty && money % coins.head != 0) {
0
} else if (coins.tail.isEmpty && money % coins.head == 0 || money == 0) {
1
} else {
-- redacted --
}
}
Essentially, are there any basic techniques I can use to eliminate the i and especially the accumulating cnt variables?
Thanks!!
There are lots of different ways to solve problems in functional style. Often you start by analysing the problem in a different way than you would when designing an imperative algorithm, so writing an imperative algorithm and then "converting" it to a functional one doesn't produce very natural functional algorithms (and you often miss out on lots of the potential benefits of functional style). But when you're an experienced imperative programmer just starting out with functional programming, that's all you've got, and it is a good way to begin getting your head around the new concepts. So here's how you can approach "converting" such a function as the one you wrote to functional style in a fairly uncreative way (i.e. not coming up with a different algorithm).
Lets just consider the else expression since the rest is fine.
Functional style has no loops, so if you need run a block of code a number of times (the body of the imperative loop), that block of code must be a function. Often the function is a simple non-recursive one, and you call a higher-order function such as map or fold to do the actual recursion, but I'm going to presume you need the practice thinking recursively and want to see it explicitly. The loop condition is calculated from the quantities you have at hand in the loop body, so we just have the loop-replacement function recursively invoke itself depending on exactly the same condition:
} else {
var cnt = 0
var i = 0
def loop(????) : ??? = {
if (money - (i * coins.head) > 0) {
cnt += countChange_sort(money - (i * coins.head), coins.tail)
i = i + 1
loop(????)
}
}
loop(????)
cnt
}
Information is only communicated to a function through its input arguments or through its definition, and communicated from a function through its return value.
The information that enters a function through its definition is constant when the function is created (either at compile time, or at runtime when the closure is created). Doesn't sound very useful for the information contained in cnt and i, which needs to be different on each call. So they obviously need to be passed in as arguments:
} else {
var cnt = 0
var i = 0
def loop(cnt : Int, i : Int) : ??? = {
if (money - (i * coins.head) > 0) {
cnt += countChange_sort(money - (i * coins.head), coins.tail)
i = i + 1
loop(cnt, i)
}
}
loop(cnt, i)
cnt
}
But we want to use the final value of cnt after the function call. If information is only communicated from loop through its return value, then we can only get the last value of cnt by having loop return it. That's pretty easy:
} else {
var cnt = 0
var i = 0
def loop(cnt : Int, i : Int) : Int = {
if (money - (i * coins.head) > 0) {
cnt += countChange_sort(money - (i * coins.head), coins.tail)
i = i + 1
loop(cnt, i)
} else {
cnt
}
}
cnt = loop(cnt, i)
cnt
}
coins, money, and countChange_sort are examples of information "entering a function through its definition". coins and money are even "variable", but they're constant at the point when loop is defined. If you wanted to move loop out of the body of countChange_sort to become a stand-alone function, you would have to make coins and money additional arguments; they would be passed in from the top-level call in countChange_sort, and then passed down unmodified in each recursive call inside loop. That would still make loop dependent on countChange_sort itself though (as well as the arithmetic operators * and -!), so you never really get away from having the function know about external things that don't come into it through its arguments.
Looking pretty good. But we're still using assignment statements inside loop, which isn't right. However all we do is assign new values to cnt and i and then pass them to a recursive invocation of loop, so those assignments can be easily removed:
} else {
var cnt = 0
var i = 0
def loop(cnt : Int, i : Int) : Int = {
if (money - (i * coins.head) > 0) {
loop(cnt + countChange_sort(money - (i * coins.head), coins.tail), i + 1)
} else {
cnt
}
}
cnt = loop(cnt, i)
cnt
}
Now there are some obvious simplifications, because we're not really doing anything at all with the mutable cnt and i other than initialising them, and then passing their initial value, assigning to cnt once and then immediately returning it. So we can (finally) get rid of the mutable cnt and i entirely:
} else {
def loop(cnt : Int, i : Int) : Int = {
if (money - (i * coins.head) > 0) {
loop(cnt + countChange_sort(money - (i * coins.head), coins.tail), i + 1)
} else {
cnt
}
}
loop(0, 0)
}
And we're done! No side effects in sight!
Note that I haven't thought much at all about what your algorithm actually does (I have made no attempt to even figure out whether it's actually correct, though I presume it is). All I've done is straightforwardly applied the general principle that information only enters a function through its arguments and leaves through its return values; all mutable state accessible to an expression is really extra hidden inputs and hidden outputs of the expression. Making them immutable explicit inputs and outputs, and then allows you to prune away unneeded ones. For example, i doesn't need to be included in the return value from loop because it's not actually needed by anything, so the conversion to functional style has made it clear that it's purely internal to loop, whereas you had to actually read the code of the imperative version to deduce this.
cnt and i are what is known as accumulators. Accumulators aren't anything special, they're just ordinary arguments; the term only refers to how they are used. Basically, if your algorithm needs to keep track of some data as it goes, you can introduce an accumulator parameter so that each recursive call can "pass forward" the data from what has been done so far. They often fill the role that local temporary mutable variables fill in imperative algorithms.
It's quite a common pattern for the return value of a recursive function to be the value of an accumulator parameter once it is determined that there's no more work left to do, as happens with cnt in this case.
Note that these sort of techniques don't necessarily produce good functional code, but it's very easy to convert functions implemented using "local" mutable state to functional style using this technique. Pervasive non-local use of mutability, such as is typical of most traditional OO programs, is harder to convert like this; you can do it, but you tend to have to modify the entire program at once, and the resulting functions have large numbers of extra arguments (explicitly exposing all the hidden data-flow that was present in original program).
I don't have any basic techniques to change the code you have specifically. However, here is a general tip for solving recursion algorithms:
Can you break the problem into sub-problems? In the money example, for example, if you are trying to get to $10 with a $5, that's similar to the question of getting to $5 with a $5 (having already chosen the $5 once). Try to draw it out and make rules. You'll be surprised at how much more obviously correct your solution is.
Since nobody answers your question I will try to give you some hints:
What is a loop?
Traversing each element of a collection. stop meeting a condition
What can you do with recursion:
Traversing each element of a collection. stop meeting a condition.
Start simple write a method without vars which prints each element of a collection.
Then the rest becomes simple look at your loop and what you are doing.
Instead of manipulating the variables directly(like i=i + 1), simply pass i + 1 to the recursive call of your method.
HTH
So, while working my way through "Scala for the Impatient" I found myself wondering: Can you use a Scala for loop without a sequence?
For example, there is an exercise in the book that asks you to build a counter object that cannot be incremented past Integer.MAX_VALUE. In order to test my solution, I wrote the following code:
var c = new Counter
for( i <- 0 to Integer.MAX_VALUE ) c.increment()
This throws an error: sequences cannot contain more than Int.MaxValue elements.
It seems to me that means that Scala is first allocating and populating a sequence object, with the values 0 through Integer.MaxValue, and then doing a foreach loop on that sequence object.
I realize that I could do this instead:
var c = new Counter
while(c.value < Integer.MAX_VALUE ) c.increment()
But is there any way to do a traditional C-style for loop with the for statement?
In fact, 0 to N does not actually populate anything with integers from 0 to N. It instead creates an instance of scala.collection.immutable.Range, which applies its methods to all the integers generated on the fly.
The error you ran into is only because you have to be able to fit the number of elements (whether they actually exist or not) into the positive part of an Int in order to maintain the contract for the length method. 1 to Int.MaxValue works fine, as does 0 until Int.MaxValue. And the latter is what your while loop is doing anyway (to includes the right endpoint, until omits it).
Anyway, since the Scala for is a very different (much more generic) creature than the C for, the short answer is no, you can't do exactly the same thing. But you can probably do what you want with for (though maybe not as fast as you want, since there is some performance penalty).
Wow, some nice technical answers for a simple question (which is good!) But in case anyone is just looking for a simple answer:
//start from 0, stop at 9 inclusive
for (i <- 0 until 10){
println("Hi " + i)
}
//or start from 0, stop at 9 inclusive
for (i <- 0 to 9){
println("Hi " + i)
}
As Rex pointed out, "to" includes the right endpoint, "until" omits it.
Yes and no, it depends what you are asking for. If you're asking whether you can iterate over a sequence of integers without having to build that sequence first, then yes you can, for instance using streams:
def fromTo(from : Int, to : Int) : Stream[Int] =
if(from > to) {
Stream.empty
} else {
// println("one more.") // uncomment to see when it is called
Stream.cons(from, fromTo(from + 1, to))
}
Then:
for(i <- fromTo(0, 5)) println(i)
Writing your own iterator by defining hasNext and next is another option.
If you're asking whether you can use the 'for' syntax to write a "native" loop, i.e. a loop that works by incrementing some native integer rather than iterating over values produced by an instance of an object, then the answer is, as far as I know, no. As you may know, 'for' comprehensions are syntactic sugar for a combination of calls to flatMap, filter, map and/or foreach (all defined in the FilterMonadic trait), depending on the nesting of generators and their types. You can try to compile some loop and print its compiler intermediate representation with
scalac -Xprint:refchecks
to see how they are expanded.
There's a bunch of these out there, but I can't be bothered googling them at the moment. The following is pretty canonical:
#scala.annotation.tailrec
def loop(from: Int, until: Int)(f: Int => Unit): Unit = {
if (from < until) {
f(from)
loop(from + 1, until)(f)
}
}
loop(0, 10) { i =>
println("Hi " + i)
}