2

In many cases, code will receive an IEnumerable<T> and wish to persist the sequence of items contained therein. A common way to do this is to call ToList on it. If the implementation in question is already an immutable list, however, calling ToList on it would be wasteful.

If I'm were only passing collections only among my code, I could define use an extension method which would would pass an IEnumerable<T> to the constructor of Supercat.ImmutableList<T> (which implements Supercat.IImmutableList<out T>), unless the supplied object already implements Supercat.IImmutableList<T> (in which case it would simply returned as-is). Implementing such a class wouldn't be hard. My concern, though, is that if I implement such a class myself, and everybody else who needed such a class did likewise, every time an object was passed between code written by people who use different "immutable-list" classes, it would end up getting defensively copied (into a form which the previous immutable-copy's creator would no longer recognize as immutable).

Therefore, I'm curious: is there any approach which are achieving anything near criminal mass for taking an immutable snapshot of a sequence of items in such a way that all objects which subscribe to the approach will be able to recognize each other's snapshots as immutable lists? For example, if many people had their immutable classes incorporate a function with some particular name which would not be used for any other purpose but to indicate immutability, then making code efficiently interoperable with that of other people who use the same approach would be reasonably easy (using a static generic class and Reflection). I can imagine quite a few possible approaches, but I'm unaware of any with anything near critical mass. I'd prefer something public-domain which could be built from source, even if that would necessitate the use of Reflection, but would be interested in knowing of any approaches that are out there.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • How *complex* is you *consuming* code going to be if it attempts to examine those flags and account for every combination? (As an aside - I'd usually recommend `ToList` over `ToArray`) – Damien_The_Unbeliever Sep 29 '12 at 16:34
  • @Damien_The_Unbeliever: I would expect that the vast majority of of consuming code would ignore the vast majority of the flags, but so what? If an interface had a dozen `IsWhatever` properties, then vb.net implementers would be stuck adding 60 lines of boilerplate code, but if all of the properties are combined in a single bitmask value, all the implementers have to do is return a number. – supercat Sep 29 '12 at 16:42
  • @Damien_The_Unbeliever: I would expect that by far the most useful flag would be `IsImmutable`, since that could routinely offer major performance improvements at minimal cost. Further, while `IsImmutablePrefix` wouldn't be useful on a whole lot of collections, it wouldn't be too hard for a general-purpose `Memoize` method to take advantage of it when it exists (by returning an object that encapsulates a reference to the original sequence and its length). – supercat Sep 29 '12 at 16:45
  • 1
    Wouldn't it be better for you to declare your function, in such a circumstance, to require an `IReadOnlyCollection` and rely on your callers to perform any necessary conversions? If you *need* a read only collection, why say that you can consume any random `IEnumerable`? – Damien_The_Unbeliever Sep 29 '12 at 16:50
  • @Damien_The_Unbeliever: I would like to see a much richer set of interfaces describing the abilities of collections; had the collection-related parts of the Framework been better designed from the get-go, this wouldn't have imposed much extra work on implementers. Unfortunately, given the interface hierarchy that exists, I don't think it would be practical to use interfaces alone to define enumerables' abilities. Further, there often would be little difficulty having a class that could accept any type of `IEnumerable` and call a general-purpose `Memoize` extension method if necessary. – supercat Sep 29 '12 at 17:07
  • @Damien_The_Unbeliever: It might be useful to have an `IMemoizableEnumerable` with a `Memoize` method, which the general-purpose `Memoize` routine could use if defined, to deal with scenarios where a class exposes a sequence which is controlled by mutable parameters (trying to memoize the sequence directly would be far less efficient than memoizing the parameters), but I didn't want to overcomplicate my question. – supercat Sep 29 '12 at 17:10
  • Even with all of your proposed flags, what does "immutable" mean? - yes, the enumerable type could return the *same* object references each time it is iterated, in the same order, but those referenced objects may have had changes applied to them. Getting everyone to agree on what it means to be immutable would be a fairly big challenge in itself. – Damien_The_Unbeliever Sep 29 '12 at 17:32
  • @Damien_The_Unbeliever: If `T` is a class type, the state of an immutable `IEnumerable` is the sequence of object *identities* contained therein. There are times outer code may want to use an `IEnumerable` to encapsulate potentially-mutable inner state, but unfortunately there's no way to indicate which storage locations are used to encapsulate identity, which ones encapsulate mutable state, which encapsulate both, and which encapsulate neither. – supercat Sep 29 '12 at 17:42
  • So, you agree that, even *if* something tells you code that it is "Immutable", you still don't know whether performing the same operation over the enumerable twice will produce the same results? – Damien_The_Unbeliever Sep 29 '12 at 17:47
  • @Damien_The_Unbeliever: What do you mean? If I have an `IEnumerable` which reports itself as immutable, I would expect that enumeration will always yield references to the same controls, in the same order. If any of the controls are exposed to anything that alters their state, the `IEnumerable` would continue to return references to the same controls (which would now have the new states). If immutability were designed into the framework, and if there were separate collection types for encapsulating object state and identity, one could meaningfully... – supercat Sep 29 '12 at 17:55
  • ...define a "maake deeply immutable copy" method (with the proviso that a collection which held a fixed sequence of object references for the purpose of encapsulating their *identities* could be regarded as deeply immutable even if the objects in question were not (indeed, the usefulness many such the collections would derive from the fact that the objects in question were not immutable). – supercat Sep 29 '12 at 17:56
  • I'm going to give up. *You* have specific immutability constraints, but you should realize that others will have different constraints. Thus, defining a single flag that says "I'm immutable" is impossible. – Damien_The_Unbeliever Sep 29 '12 at 18:04
  • @Damien_The_Unbeliever: How could the state of a collection of an unconstrained class-type `T` possibly be expected to encapsulate mutable aspects of objects of a type `T` it knows nothing about? The most common question the `IsImmutable` question would seek to answer is whether the consumer should use `ToList` or somesuch method to make a private copy of the sequence. The answer to that question is unaffected by whether the items within the collection contains references to mutable objects. – supercat Sep 29 '12 at 18:18
  • This question is much more manageable after the edit. I'm going to delete my answer because it no longer answers the question. You may want to do the same with all your comments. Regarding the edited question: can you define "Immutable?" Does immutable mean that the underlying data may not be changed, or does it simply mean that the underlying data structure cannot be changed anywhere, by anybody? – StriplingWarrior Oct 01 '12 at 22:59
  • 1
    @StriplingWarrior: An immutable implementation of `IEnumerable` is one which will always return the same sequence of `T`'s every time between now and the disappearance of the last reference. "Same" meaning bit-wise equality (which for reference types would mean referring to the same objects). – supercat Oct 02 '12 at 01:40

1 Answers1

0

If by "immutable" you mean that you don't want consumers of the original data to be able to change the values, you can use a ReadOnlyCollection. However, in this case, the underlying list is still mutable, so consumers cannot guarantee that it won't be changed elsewhere.

If you're looking for truly immutable collections, your best bet is probably to use the ones created for F#. See this answer.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • That answer looks interesting and is the sort of thing I'm looking for, though I don't know anything about F# and consequently find the pages a bit hard to read. For example, what is a "module"? It would also seem annoying to write programs that won't work in XP simply because older versions of .net didn't happen to define an immutable collection. – supercat Oct 03 '12 at 17:10
  • 1
    @supercat: Sorry, dude, that's the best I've got. You live in an imperfect world. – StriplingWarrior Oct 03 '12 at 18:34