-
Notifications
You must be signed in to change notification settings - Fork 72
Views #13
Comments
For reference, here is an example given by @Ichoran on gitter about fusion:
|
@julienrf, it's not only because of boxing, it's also because of reduction total memory footprint by 2x. |
Still quoting @Ichoran:
|
Mutable views are nice to have for a variety of divide-and-conquer in-place algorithms. For instance, an in-place sort is easier to express if you don't have to worry about indices. I don't think that dropping the order of evaluation is particularly useful for either mutable or immutable views. That is a different useful thing, but "I want to act on part of my collection without rebuilding it" is a different desire than "I want to parallelize my operations on this collection". If we were to support only one of the two, we at least shouldn't call it a "view" because right now (and in most other languages I've seen) "view" means the former. |
I think this is a niche, 0.1% use case and we should drop it and not worry about it.
Not sure, but I think you might be misunderstanding Stefan's suggestion? It isn't about parallelization. He isn't suggesting leaving iteration order unspecified — allowing element 4 to be operated on before element 3, as can happen with parallel collections. Rather, he's suggesting to allow fusion. If you do |
Also note that evaluation order of views in the current strawman is already different from evaluation order of operations on the underlying collections. If you wanted the same evaluation order you would have to build intermediate results but the whole point of views is to avoid that. I am only suggesting that we do not guarantee the same evaluation order as that of Iterators, either. |
Ah, yes, I did misunderstand. I agree that views should be maximally flexible in that regard; unlike iterators which should promise to be as lazy as possible, views can do whatever is "best" with regards to evaluation of sequential operations. And I don't think evaluation order should be the same save on Seqs and SortedWhatevers where there is already a natural evaluation order. But I think the "niche, 0.1% use case" evaluation is only because we're making it so by providing no support for this way of working. Views are a key aspect of, for instance, image processing operations in ImageJ; the conceptual equivalent of views with indexed ranges are used all over the place both in Java (e.g. One of the weaknesses of the current collections library is that it has relatively poor support for mutating operations. We needn't necessarily improve this greatly (people are used to it not being there), but it doesn't mean that the potential use cases are rare. For instance, if one has a list of files and one wants to replace all the missing ones by default file names, you would normally do this with immutable collections: xs.map(f => if (f.exists) f else default) But although you could reassign everything in place mutably: xs.mapInPlace(f => if (f.exists) f else default) in some ways it's more natural to define a filtered view and fill it: xs.viewWhere(! _.exists).fill(default) Again, I'm not saying it's really important for us to provide this kind of functionality, but I don't think we should view this as for niche applications even if we have immutable alternatives as the standard now. (Except inasmuch as anything mutable is a niche application.) |
It isn't so much that I'm opposed to including support for it, the only thing I'm strongly opposed to is letting this class of use cases be something that drives top-level design decisions. If it can be accommodated without distorting the hierarchy+API, great. (Can it?) |
I think that mutable views would just be a completely different thing than immutable views, so I don't think they'd impact the hierarchy. We could call them something else also. |
I don't think that's necessary. The specified evaluation order of views already demands fusing. An unspecified evaluation order could give you some extra facility, for instance if you want to batch some ops into segments before fusing. But I don't think views are the right place for that. [EDIT] I might be convinced otherwise by benchmarks that show that there's a big win to be had by automatic batching. I am also betting that we will have much better techniques to reason about effects in the future, which would let us optimize without compromising semantics. |
Regarding mutable views, one question is what operations would produce a view? If we do not want to re-index (and I think we should not), then it seems the only sensical operations are to change the start, the end, or the stride. So, instead of views we could use a general notion of slices. E.g., on mutable (indexed?) Seq[A]:
Normal, strict slices are collection transformers and would not be available on mutable collections. There's no danger of silently changing semantics because the new non-strict slice WDYT? |
I just noted that there is a source of confusion for arrays.
creates a new, strict array, or at least it did so far. But |
@odersky Maybe we should suffix operations producing a view with “view” (e.g. |
@julienrf I agree |
I did a web search and it seems except for Scala, the name
The result of |
I am wary of having too many different derived collection types. So far we have immutable, mutable, iterator, immutable view, mutable view, and now we're going to have slice also? One of the primary reasons that the existing views are not used much--aside from surprising behavior that arose from the lack of a clear distinction between mutable and immutable views and inherent bugs due to LSP issues--was that they were buggy because it was hard to maintain so many different parallel implementations. I would therefore try quite hard to keep slices and views the same thing. A slice would be one particular way to get a view. If we're not going to do that I would like to have examples of methods that are very important to have on one but must not be on the other. I can't think of any offhand. |
It's not clear to me why we would need separate types for slices and views. If we distinguish between mutable and immutable views, Are there any other opinions on the method names? If they are used in this way in other languages and libraries it probably makes sense to do the same (modulo the |
How about |
I would like to take advantage of this thread to ask whether we should keep |
The same is true for other lazy collections like |
I agree with Stefan, and I am also not sure whether we should have a marker trait or not. I would defer all that until we have dealt with parallel collections. The order of evaluation (strict/lazy/batched/parallel) can vary a lot and we should think carefully before we invest types to reflect that. |
Yeah, ok, I agree with your arguments :) |
Re: choosing names for in-place mutable operations (from the other thread #7).
What about appending val arr = ArrayBuffer(1,2,3,4,5)
// clearly, I'm doing imperative transformations here:
arr.map_!(x => x + 1).filter_!( _ % 2 == 0 )
// or:
arr map_! (_ + 1) filter_! (_ % 2 == 0) There is precedence for this in Ruby, where it's somewhat nicer because there is no need for the arr.map!(_ + 1).filter!(_ % 2 == 0) I would probably also push for marking methods not guaranteed to have the expected efficient implementation (such as |
|
I expect |
|
I agree. In the strawman we define equality at the level of |
I really expect LazyList or Stream add these powerful and convenient methods : |
My experiences with
|
FWIW I added some of them in that PR: https://github.com/scala/collection-strawman/pull/200/files#diff-c0d7086690fd3b617f2eb319d5b832ce
|
It looks like we've settled on a |
Let's use this ticket for discussions about views. Some comments were already made in #7:
My own 2ct on the topic so far: I never cared for mutable views (too confusing) but I like the ideas of views as reified iterator operations, as currently implemented here. These could be useful in the context of both, mutable and immutable collections. I would like to propose to take them one step further and make the evaluation order of view operations unspecified. If views are used as a lightweight abstraction for composing complex transformations, you don't generally care about side effects, but you always care about performance (otherwise you'd transform the underlying collections in multiple steps). Views could be a place where we allow operations to be fused for better performance.
The text was updated successfully, but these errors were encountered: