IssueRaiser

Reconsider version checks in collections?

Many of our mutable collection types maintain version numbers. These version numbers are incremented for many (not necessarily all) of the mutating operations performed on the type, e.g. https://github.com/dotnet/runtime/blob/2ba2396495c22429035d165e478672c442f81e22/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L196-L198 The version number is then snapshot as part of calling GetEnumerator, and every MoveNext on the resulting enumerator compares the version number that was snapshot against the current version number. https://github.com/dotnet/runtime/blob/2ba2396495c22429035d165e478672c442f81e22/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L1166-L1170 This serves as a way to flag some misuse, where mutation is performed during enumeration. The motivation here is good: help developers find misuse. There are a few problems, though: 1. It adds a little overhead. It's minimal, and this alone is not worth a change for, but it requires an extra Int32 field on the type as well as on the enumerator, it requires an increment operation as part of each mutation, and it requires an extra branch as part of each MoveNext. 2. It doesn't cover all forms of enumeration. If, for example, you enumerate a `List<T>` via `foreach (var item in list) Use(item);`, then it applies, but if you change to iterating via `for (int i = 0; i < list.Count; i++) Use(list[i]);`, then it doesn't. 3. We're considering proposals for enabling the compi

Posted by stephentoub on Feb 2, 2023, 3:36 AM

Tags

Related issues

Raise real-world problems, find people facing the same issue, and discuss solutions.2,500 issues0 comments

github (Software)

Reconsider version checks in collections?

stephentoubFeb 2, 2023, 3:36 AM

Many of our mutable collection types maintain version numbers. These version numbers are incremented for many (not necessarily all) of the mutating operations performed on the type, e.g. https://github.com/dotnet/runtime/blob/2ba2396495c22429035d165e478672c442f81e22/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L196-L198 The version number is then snapshot as part of calling GetEnumerator, and every MoveNext on the resulting enumerator compares the version number that was snapshot against the current version number. https://github.com/dotnet/runtime/blob/2ba2396495c22429035d165e478672c442f81e22/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L1166-L1170 This serves as a way to flag some misuse, where mutation is performed during enumeration. The motivation here is good: help developers find misuse. There are a few problems, though: 1. It adds a little overhead. It's minimal, and this alone is not worth a change for, but it requires an extra Int32 field on the type as well as on the enumerator, it requires an increment operation as part of each mutation, and it requires an extra branch as part of each MoveNext. 2. It doesn't cover all forms of enumeration. If, for example, you enumerate a `List<T>` via `foreach (var item in list) Use(item);`, then it applies, but if you change to iterating via `for (int i = 0; i < list.Count; i++) Use(list[i]);`, then it doesn't. 3. We're considering proposals for enabling the compi

Comments (0)

No comments yet. Start the discussion.

Comment on this issue