[swift-evolution] Should we rename "class" when referring to protocol conformance?
Matthew Johnson
matthew at anandabits.com
Mon May 9 18:06:59 CDT 2016
> On May 8, 2016, at 1:02 AM, Dave Abrahams <dabrahams at apple.com> wrote:
>
>
> on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/>> wrote:
>
>>>
>>> You haven't answered this question. How would you use this protocol?
>>
>> I think the best example was given by Andy when discussing pure
>> functions. Maybe I want to write a generic function and ensure it is
>> pure. I can only do this if I know that any arguments received that
>> compare equal will always present the same observable state.
>
> And that it doesn't touch any globals.
>
>> For example, maybe I wish to memoize the result.
>>
>> I cannot write such a function for all T, and I also cannot write such
>> a function for all T that have value semantics if we adopt the
>> “references are values” view of the world.
>
> Oh, you absolutely can, because if the function applies to all T that
> have value semantics, it only has a few operations to work with:
> initialization, assignment, and equality. Assignment is the only
> mutating one of these.
I was implicitly assuming additional constraints exposing other behavior. I should have stated that explicitly.
>
>> I need an additional constraint that rejects things like
>> Array<UIView>. (T would obviously also be constrained by a protocol
>> that exposes the properties or methods my function requires to compute
>> its result)
>
> Did you just start referring to T as the element type of the array
> instead of the function's parameter type? I think you're
> unintentionally pulling a fast one, reasoning-wise. It might help to
> write down some actual code.
I was intending to refer to T as the element type of the array all along. The signature I was thinking of would look something like:
pure foo<T>(bar: [T]) -> SomeReturnType
I should have written this down to be clear about it.
>
>> In general, it would be used where you need to ensure that the result
>> of any operation observing the state of any part of the aggregate
>> value will always return the same value at any point in the future.
>> If I observe a[0].foo now I know with certainty the result of
>> observing a[0].foo at any point in the future.
>
> Sure, but what you need then is a constraint on a's Element type that it
> has value semantics, not some kind of new PureValue concept to use as a
> constraint on the array itself.
That works if you follow all observable paths until you get to scalars. For example maybe A’s element is Array<Array<UIView>> and `foo ` is implemented in an extension off Array where Element == UIVIew (after we get same type constraints). Once we have conditional conformance that extension could conform to a protocol that makes `foo` visible and it would still have value semantics but it would not be a pure value.
>
>> This aspect of preservation of observed values across time is
>> essential to the distinction between Array<LayoutValue> (see below)
>> and Array<UIView>. It doesn’t matter when I observe the frames of the
>> elements of Array<LayoutValue>, I will always get the same rects back.
>> With Array<UIView> that is obviously not the case as the frame of the
>> view could be mutated by anyone with a reference to the views at any
>> time in between my observations of the frame values.
>>
>> struct LayoutValue {
>> frame: CGRect
>> }
>>
>>>
>>>> let t = MyClass()
>>>> foo.acceptWrapped(Wrap(t))
>>>> t.mutate()
>>>>
>>>> In this example, foo had better not depend on the wrapped instance
>>>> not
>>>> getting
>>>> mutated.
>>>>
>>>> foo has no way to get at the wrapped instance, so it can't depend on
>>>> anything about it.
>>>>
>>>> Ok, but this is a toy example. What is the purpose of Wrap? Maybe
>>>> foo
>>>> passes the
>>>> wrapped instance back to code that *does* have visibility to the
>>>> instance. My
>>>> point was that shared mutable state is still possible here.
>>>>
>>>> And my point is that Wrap<T> encapsulates a T (almost—I should have
>>>> let
>>>> it construct the T in its init rather than accepting a T parameter)
>>>> and
>>>> the fact that it's *possible* to code something with the structure
>>>> of
>>>> Wrap so that it has shared mutable state is irrelevant.
>>>>
>>>> The point I am trying to make is that the semantic properties of
>>>> Wrap<T> depend
>>>> on the semantic properties of T (whether or not non-local mutation
>>>> may be
>>>> observed in this case).
>>>>
>>>> No they do not; Wrap<T> was specifically designed *not* to depend on the
>>>> semantic properties of T. This was in answer to what you said:
>>>>
>>>> A struct wrapping a mutable reference type certainly doesn’t
>>>> “feel” value semantic to me and certainly doesn’t have the
>>>> guarantees usually associated with value semantics (won’t
>>>> mutate behind your back, thread safe, etc).
>>>>
>>>> I have been trying to get you to nail down what you mean by PureValue,
>>>> and I was trying to illustrate that merely being “a struct wrapping a
>>>> mutable reference type” is not enough to disqualify anything from being
>>>> in the category you're trying to describe. What are the properties of
>>>> types in that category, and what generic code would depend on those
>>>> properties?
>>>
>>> Again, the key questions are above, asked a different way.
>>>
>>> --
>>> -Dave
>
> --
> -Dave
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160509/a57108bf/attachment.html>
More information about the swift-evolution
mailing list