public MyPanel(ImmutableArray<Widget> widgets) { ... }

That's the use case I was missing. Thanks for taking the time to debate,
guys.

rjrjr

On Mon, Mar 22, 2010 at 4:05 PM, Bruce Johnson <br...@google.com> wrote:

> I think Rodrigo's point already subsumed what I'm about to say, but there
> are three cases here:
>
> 1) A read-only reference to a collection that may or may not be mutable by
> someone else. This is the purpose of the root type Array, which has not
> mutators but doesn't make a guarantee about whether the referenced
> collection is mutable or immutable.
>
> 2) A reference to a read-only collection whose contents are guaranteed to
> in fact be immutable.
>
> 3) A normal, mutable array that is read/write.
>
> @Ray: The idea of an immutableView() method doesn't seem to quite handle
> these use cases, because either the returned object is a separate object
> with a runtime wrapper (the equivalent of unmodifiableList()) or it's a
> read-only interface to a collection that isn't really guaranteed to be
> immutable, merely read-only. Also note that MutableArray extends the
> read-only Array class, and so every MutableArray can be implicitly returned
> as a read-only alias anywhere you want, which is even easier than
> immutableView().
>
> I would guess it would be fairly typical to use mostly MutableArray and
> Array, but ImmutableArray has a real role, too. Imagine a MyPanel that takes
> a list of Widgets in its constructor. You could declare the constructor like
> this:
>
>    public MyPanel(ImmutableArray<Widget> widgets) { ... }
>
> That's useful because you can code the class with full knowledge that the
> set of widgets won't be changing out from under you from the calling code --
> you can just directly assign that param to a field without making a copy.
> Had the constructor been:
>
>    public MyPanel(List<Widget> widgets) { ... }
>
> you could never be sure and would probably feel compelled to make a
> defensive copy.
>
> I'm going to guess this is how it would play out:
>
> 1) Constructors will often take ImmutableArray because it's nice to assign
> ctor params directly to fields and know for a fact there's no reason to make
> defensive copies.
>
> 2) Fields will be declared as MutableArray, and in getters the return type
> will be Array, thus allowing getters to safely return references directly,
> happy in the knowledge that there is neither a need to make a defensive
> outgoing copy nor a risk that the caller can mutate your private field's
> contents.
>
> 3) Library methods will take the least-specific type that can suffice for
> the respective algorithm. For example, binarySearch(), find(), forEach(),
> etc. would take a param of type Array, thus allowing either mutable or
> immutable arrays to use the method. Then again, sort() would explicitly take
> a MutableArray.
>
> And of course, there is no desire to design all this in a vacuum -- and we
> shouldn't argue against it in a vacuum either. This is a starting point
> strawman, so I'd propose we use this design as a stake in the ground and
> then see how it would play it if we retrofitted it into real code, both app
> code and library code. Then we'll really get a feel for how useful vs.
> confusing it is, and most importantly, we can get metrics on the speed and
> size.
>
>
>
> On Mon, Mar 22, 2010 at 6:34 PM, Rodrigo Chandia <rchan...@google.com>wrote:
>
>> Immutability is a stronger assertion than read-only access. If I receive a
>> read-only object I better make sure to handle the case of the data being
>> changed by others; be it by tacit agreement, using other channels, locking
>> or simply ignoring the issue. Immutability guarantees the data is stable and
>> unchanging. The agreement is explicit. I will be able to read it to my
>> heart's content without worry.
>>
>> Granted, being this a simple implementation it has some inconveniences:
>>
>> 1. The Immutability is achieved by "freezing" the original Mutable
>> container while it may be useful to keep working with the original container
>> instead.
>> 2. The receiver of a MutableArray may find later that someone called
>> freeze on the object causing an error.
>>
>> This is largely a matter of it being a lightweight implementation. There
>> is no contract forcing the mutable view to be tied to the original mutable
>> container. A more sophisticated implementation could copy the container,
>> implement copy-on-write semantics, or any number of alternative
>> implementations. Still the meaning of an immutable collection implies the
>> contents will not change, while a read-only view makes no such promise.
>>
>> 2010/3/22 Ray Ryan <rj...@google.com>
>>
>>> My argument is that one is necessary and sufficient. Two is kind of
>>> pointless if you have achieved one, and maybe even counterproductive.
>>>
>>>
>>> On Mon, Mar 22, 2010 at 2:32 PM, Joel Webber <j...@google.com> wrote:
>>>
>>>> I think we're talking about two different things here. Rodrigo's (valid)
>>>> point is that implementing immutability sanely early on is a good idea. And
>>>> this implementation is pretty much analogous to the one you describe from
>>>> Cocoa.
>>>>
>>>> The question at hand is whether it makes sense to get an immutable
>>>> collection from a mutable one, with no copies. There are two ways to do
>>>> this:
>>>> 1. Create an immutable "view" of a mutable list, but with no guarantees
>>>> that the list won't be mutated by the original owner later.
>>>> 2. "Freeze" a mutable list into an immutable view of said list, making
>>>> the former "runtime immutable".
>>>>
>>>> (1) solves the problem of a class giving access to one of its internal
>>>> collections without having to guard against external mutation. (2) can be
>>>> used to replicate the "builder" pattern.
>>>>
>>>> I don't have a strong opinion about (2) myself, but (1) is pretty damned
>>>> important, because it's the source of innumerable stupid defensive copies 
>>>> in
>>>> JRE code. The provider of such an interface would just have to be very 
>>>> clear
>>>> about whether the "immutable" list might be modified later (because it's a
>>>> view on a mutable one).
>>>>
>>>> On Mon, Mar 22, 2010 at 5:23 PM, Ray Ryan <rj...@google.com> wrote:
>>>>
>>>>> I think you're missing my point. An object is immutable if there exists
>>>>> no api to mutate it. That should be enough.
>>>>>
>>>>> Let me put it another way. It's lame that the JRE achieves immutability
>>>>> by turning mutate methods into runtime errors. It will be equally lame of 
>>>>> us
>>>>> to do the same, especially since we can't enforce it at production time. 
>>>>> It
>>>>> would be much better to provide an api such that there is not even 
>>>>> possible
>>>>> to compile the mutate call (without cheating with casts, but then you know
>>>>> you're being bad).
>>>>>
>>>>> The Cocoa approach to this is to have interfaces like NSArray be
>>>>> immutable, and then have NSMutableArray extend NSArray. If we're going to
>>>>> roll our own collection classes, it seems to me we could do the same: e.g.
>>>>> LiteImmutableList and List extends LiteImmutableList.
>>>>>
>>>>> rjrjr
>>>>>
>>>>>
>>>>> On Mon, Mar 22, 2010 at 2:12 PM, Rodrigo Chandia 
>>>>> <rchan...@google.com>wrote:
>>>>>
>>>>>> I like the *concept* of immutability being introduced early in the
>>>>>> development. The initial implementation may be limiting for some use 
>>>>>> cases,
>>>>>> but I believe it is a useful concept to expand on. If specific needs 
>>>>>> require
>>>>>> simultaneous mutable and immutable access we can provide implementations 
>>>>>> to
>>>>>> address that problem (copy on write semantics, for example).
>>>>>>
>>>>>> 2010/3/22 Ray Ryan <rj...@google.com>
>>>>>>
>>>>>> I guess I'm overstating my opposition. It's not really dangerous, but
>>>>>>> it just doesn't seem useful. Just by existing I think it'll promote
>>>>>>> confusion and perhaps bad habits. Why bother?
>>>>>>>
>>>>>>> I think the 90% use case is for something like the following (writing
>>>>>>> in JRE terms here):
>>>>>>>
>>>>>>> private final List<String> magicValues;
>>>>>>> {
>>>>>>>    List<String> buildValues = new ArrayList<String>();
>>>>>>>    buildValues.add("able");
>>>>>>>    buildValues.add("baker");
>>>>>>>    buildValues.add("charlie");
>>>>>>>    magicValues = Collections.unmodifiableList(buildValues);
>>>>>>> }
>>>>>>>
>>>>>>> Ta da: it's a read only structure and no copy was made. In our world,
>>>>>>> we could do better:
>>>>>>>
>>>>>>> private final ImmutableLiteList<String> magicValues;
>>>>>>> {
>>>>>>>    LiteList<String> buildValues = new LiteList<String>();
>>>>>>>    buildValues.add("able");
>>>>>>>    buildValues.add("baker");
>>>>>>>    buildValues.add("charlie");
>>>>>>>    magicValues = buildValues.immutableView(); // more equivalent of
>>>>>>> cast()
>>>>>>> }
>>>>>>>
>>>>>>> The user never thinks in terms of freezing, just cutting off access.
>>>>>>> No extra dev mode mechanism to maintain, and basically the same idiom
>>>>>>> already in use in Java.
>>>>>>>
>>>>>>
>>>>>>
>>>>>  --
>>>>> http://groups.google.com/group/Google-Web-Toolkit-Contributors
>>>>>
>>>>> To unsubscribe from this group, send email to
>>>>> google-web-toolkit-contributors+unsubscribegooglegroups.com or reply
>>>>> to this email with the words "REMOVE ME" as the subject.
>>>>>
>>>>
>>>>  --
>>>> http://groups.google.com/group/Google-Web-Toolkit-Contributors
>>>>
>>>> To unsubscribe from this group, send email to
>>>> google-web-toolkit-contributors+unsubscribegooglegroups.com or reply to
>>>> this email with the words "REMOVE ME" as the subject.
>>>>
>>>
>>>
>>
>

-- 
http://groups.google.com/group/Google-Web-Toolkit-Contributors

To unsubscribe from this group, send email to 
google-web-toolkit-contributors+unsubscribegooglegroups.com or reply to this 
email with the words "REMOVE ME" as the subject.

Reply via email to