Should we rename "class" when referring to protocol conformance?

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

   Sure it does.

   public struct Wrap<T: AnyObject> : Equatable {
   init(_ x: T) { self.x = x }
   private x: T
   }

   func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
   return lhs.x === rhs.x
   }

   I defy you to find any scenario where Wrap<T> doesn't have value
   semantics, whether T is mutable or not.

   Alternately, you can look at the Array implementation. Array is a
   struct wrapping a mutable class. It has value semantics by virtue of
   CoW.

This goes back to where you draw the line as to the “boundary of the value”.
Wrap and Array are “value semantic” in a shallow sense and are capable of deep
value semantics when T is deeply value semantic.

No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
not understanding the boundaries of your value. Or, put more
solicitously: sure, you can look at the world that way, but it just
makes everything prohibitively complicated, so why would you want to?

In my world, there's no such thing as a “deep copy” or a “shallow copy;”
there's just “copy,” which logically creates an independent version of
everything up to the boundaries of the value. Likewise, there's no
“deep value semantics” or “shallow value semantics.”
Equality defines
value semantics, and the boundaries of an Array value always includes
the values of its elements. The *only* problem here is that we have no
way to do equality comparison on some arrays because some types aren't
Equatable. IMO the costs of not having everything be equatable, in
complexity-of-programming-model terms, are too high.

Thank you for clarifying the terminology for me. This is helpful.

I think I may have misunderstood what you meant by “boundary of the value”. Do you mean that the boundary of an Array value stops at the reference identity for elements with reference semantics? If you have an Array whose elements are of an immutable reference type that has value semantics would you say the boundary extends past the reference identity of an element and includes a definition of equality defined by that type?

Are you arguing that reference types should be equatable by default, using equality of the reference if the type does not provide a custom definition of equality?

Both have their place, but the maximum benefit of value semantics
(purity)

I don't know what definition of purity you're using. The only one I
know of applies to functions and implies no side effects. In that
world, there is no mutation and value semantics is equivalent to
reference semantics.

I was using it in the sense of “PureValue” as discussed in this thread. I was using it to mean values for which no *observable* mutation is possible (allowing for CoW, etc). Is there a better term for this than purity?

is derived from deep value semantics. This is when there is no
possibility of shared mutable state. This is an extremely important
property.

It's the wrong property, IMO.

Wrong in what sense? I don’t mean to imply that it is the *only* valuable property. However, it I (and many others) do believe it is an extremely valuable property in many cases. Do you disagree?

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.

···

On May 5, 2016, at 10:02 PM, Dave Abrahams <dabrahams@apple.com> wrote:
on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:

   On May 5, 2016, at 4:59 PM, Dave Abrahams <dabrahams@apple.com> wrote:
   on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev <swift-evolution@swift.org> >> wrote:

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

   The language outlaws certain kinds of inout aliasing without
   providing static enforcement. This is like that.

I did not know this. Now you have me curious. Can you give an example of where
we are able to violate law? I ask mostly because it sounds like there is a
possibility of stumbling into dangerous territory, possibly without being aware
that you have done so.

See “In-out Parameters” in
The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

   That would be one *consequence* of effectively outlawing it. The library
   could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

--
Dave

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

   Sure it does.

   public struct Wrap<T: AnyObject> : Equatable {
   init(_ x: T) { self.x = x }
   private x: T
   }

   func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
   return lhs.x === rhs.x
   }

   I defy you to find any scenario where Wrap<T> doesn't have value
   semantics, whether T is mutable or not.

   Alternately, you can look at the Array implementation. Array is a
   struct wrapping a mutable class. It has value semantics by virtue of
   CoW.

This goes back to where you draw the line as to the “boundary of the value”.
Wrap and Array are “value semantic” in a shallow sense and are capable of deep
value semantics when T is deeply value semantic.

No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
not understanding the boundaries of your value. Or, put more
solicitously: sure, you can look at the world that way, but it just
makes everything prohibitively complicated, so why would you want to?

In my world, there's no such thing as a “deep copy” or a “shallow copy;”
there's just “copy,” which logically creates an independent version of
everything up to the boundaries of the value. Likewise, there's no
“deep value semantics” or “shallow value semantics.” Equality defines
value semantics, and the boundaries of an Array value always includes
the values of its elements. The *only* problem here is that we have no
way to do equality comparison on some arrays because some types aren't
Equatable. IMO the costs of not having everything be equatable, in
complexity-of-programming-model terms, are too high.

My point with this is, in case I was a bit rambling, if you’re going to draw boundaries around a value, for the purpose of copying or immutability, then equality should always match with those boundaries. As you say, “Equality defines value semantics, and the boundaries of an Array value always includes the values of its elements.”

Under this reasoning, custom equality violates these boundaries. And without custom equality, equality checks on reference types are essentially useless. But maybe value types in Swift are powerful enough where this doesn’t matter.

···

On May 5, 2016, at 8:02 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:

   On May 5, 2016, at 4:59 PM, Dave Abrahams <dabrahams@apple.com> wrote:
   on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev <swift-evolution@swift.org> >> wrote:

Both have their place, but the maximum benefit of value semantics
(purity)

I don't know what definition of purity you're using. The only one I
know of applies to functions and implies no side effects. In that
world, there is no mutation and value semantics is equivalent to
reference semantics.

is derived from deep value semantics. This is when there is no
possibility of shared mutable state. This is an extremely important
property.

It's the wrong property, IMO.

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.

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

   The language outlaws certain kinds of inout aliasing without
   providing static enforcement. This is like that.

I did not know this. Now you have me curious. Can you give an example of where
we are able to violate law? I ask mostly because it sounds like there is a
possibility of stumbling into dangerous territory, possibly without being aware
that you have done so.

See “In-out Parameters” in
The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

   That would be one *consequence* of effectively outlawing it. The library
   could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

--
Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

        Not sure what to think about the enum cases inside a
        protocol (if AnyEnum would
        even exist), it could be a nice addition to the language, but
        this is an own
        proposal I guess.

        We should start by adding AnyValue protocol to which all value
        types
        conforms.

        Having a way to constrain conformance to things with value semantics
        is
        something I've long wanted. *However*, the approach described is too
        simplistic. It's possible to build classes whose instances have
        value
        semantics (just make them immutable) and it's possible to build
        structs
        whose instances have reference semantics (just put the struct's
        storage
        in a mutable class instance that it holds as a property, and don't
        do
        copy-on-write).

        In order for something like AnyValue to have meaning, we need to
        impose
        greater order. After thinking through many approaches over the
        years, I
        have arrived at the (admittedly rather drastic) opinion that the
        language should effectively outlaw the creation of structs and enums
        that don't have value semantics. (I have no problem with the idea
        that
        immutable classes that want to act as values should be wrapped in a
        struct). The language could then do lots of things much more
        intelligently, such as correctly generating implementations of
        equality.

        That is a drastic solution indeed! How would this impact things like
        Array<UIView>? While Array itself has value semantics, the aggregate
        obviously does not as it contains references which usually be mutated
        underneath us.

        Value semantics and mutation can only be measured with respect to
        equality. The definition of == for all class types would be equivalent
        to ===. Problem solved.

        Similar considerations apply to simpler wrapper structs such as Weak.

        Same answer.

        Hmm. If those qualify as “value semantic” then what kind of structs and
        enums
        would not? 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).

        Sure it does.

        public struct Wrap<T: AnyObject> : Equatable {
        init(_ x: T) { self.x = x }
        private x: T
        }

        func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
        return lhs.x === rhs.x
        }

        I defy you to find any scenario where Wrap<T> doesn't have value
        semantics, whether T is mutable or not.

        Alternately, you can look at the Array implementation. Array is a
        struct wrapping a mutable class. It has value semantics by virtue of
        CoW.

        This goes back to where you draw the line as to the “boundary of the
        value”.
        Wrap and Array are “value semantic” in a shallow sense and are capable
        of deep
        value semantics when T is deeply value semantic.

    No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
    not understanding the boundaries of your value. Or, put more
    solicitously: sure, you can look at the world that way, but it just
    makes everything prohibitively complicated, so why would you want to?

    In my world, there's no such thing as a “deep copy” or a “shallow copy;”
    there's just “copy,” which logically creates an independent version of
    everything up to the boundaries of the value. Likewise, there's no
    “deep value semantics” or “shallow value semantics.”

    Equality defines
    value semantics, and the boundaries of an Array value always includes
    the values of its elements. The *only* problem here is that we have no
    way to do equality comparison on some arrays because some types aren't
    Equatable. IMO the costs of not having everything be equatable, in
    complexity-of-programming-model terms, are too high.

Thank you for clarifying the terminology for me. This is helpful.

I think I may have misunderstood what you meant by “boundary of the value”. Do
you mean that the boundary of an Array value stops at the reference identity for
elements with reference semantics?

Yes.

If you have an Array whose elements are of an immutable reference type
that has value semantics would you say the boundary extends past the
reference identity of an element and includes a definition of equality
defined by that type?

Yes!

Are you arguing that reference types should be equatable by default, using
equality of the reference if the type does not provide a custom definition of
equality?

Yes!!

        Both have their place, but the maximum benefit of value semantics
        (purity)

    I don't know what definition of purity you're using. The only one I
    know of applies to functions and implies no side effects. In that
    world, there is no mutation and value semantics is equivalent to
    reference semantics.

I was using it in the sense of “PureValue” as discussed in this
thread.

Sorry, this is the first mention I can find in the whole thread, honest.
Oh, it was a different thread. Joe describes it as a protocol for
“types that represent fully self-contained values,” which is just fuzzy
enough that everyone reading it can have his own interpretation of what
it means.

I was using it to mean values for which no *observable* mutation is
possible (allowing for CoW, etc). Is there a better term for this than
purity?

You're still not making any sense to me. A type for which no observable
mutation is possible is **immutable**. The “write” part of
copy-on-write is a pretty clear indicator that it's all about
**mutation**. I don't see how they're compatible.

I think perhaps what you mean by “purity” is just, “has value
semantics.” But I could be wrong.

        is derived from deep value semantics. This is when there is no
        possibility of shared mutable state. This is an extremely important
        property.

    It's the wrong property, IMO.

Wrong in what sense?

Wrong in the sense that it rules out using things like Array that are
logically value types but happen to be implemented with CoW, and if you
have proper encapsulation there's no way for these types to behave as
anything other than values, so it would be extremely limiting.

I don’t mean to imply that it is the *only* valuable
property. However, it I (and many others) do believe it is an extremely valuable
property in many cases. Do you disagree?

I think I do. What is valuable about such a protocol? What generic
algorithms could you write that work on models of PureValue but don't
work just as well on Array<Int>?

        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.

HTH,

···

on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:

    On May 5, 2016, at 10:02 PM, Dave Abrahams > <dabrahams@apple.com> wrote:
    on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
        On May 5, 2016, at 4:59 PM, Dave Abrahams > <dabrahams@apple.com> wrote:
        on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
        On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
        on Wed May 04 2016, Matthew Johnson > <swift-evolution@swift.org> wrote:
        On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
        on Wed May 04 2016, Adrian Zubarev > <swift-evolution@swift.org> > wrote:

        My expectation is a generic aggregate such as Array would have to
        conditionally conform to AnyValue only when Element also conforms to
        AnyValue.

        I’m also wondering how such a rule would be implemented while still
        allowing for CoW structs that *do* implement value semantics, but do
        so while using references internally.

        I am not talking about any kind of statically-enforceable rule, although
        we could probably make warnings sophisticated enough to help with this.

        You said the you have arrived at the opinion that the language should
        “effectively outlaw” structs and enums that do not have value semantics.
        That
        sounded like static enforcement to me.

        The language outlaws certain kinds of inout aliasing without
        providing static enforcement. This is like that.

        I did not know this. Now you have me curious. Can you give an example of
        where
        we are able to violate law? I ask mostly because it sounds like there is
        a
        possibility of stumbling into dangerous territory, possibly without
        being aware
        that you have done so.

    See “In-out Parameters” in
    The Swift Programming Language: Redirect

        Maybe you meant we should allow the compiler to assume value semantics
        for structs and enums despite the fact that it doesn’t statically
        enforce this?

        That would be one *consequence* of effectively outlawing it. The library
        could make similar assumptions.

        If the compiler can be sophisticated enough to verify value semantics
        statically maybe it would be better to have that mechanism be
        triggered by conformance to AnyValue rather than for all structs and
        enums. Types that conform to AnyValue would receive the benefits of
        the compiler knowing they have value semantics, while other uses of
        structs and enums would remain valid. Best practice would be to
        conform structs and enums to AnyValue whenever possible.

        Another possible advantage of this approach would be allowing
        immutable reference types to conform to AnyValue and receive the
        associated benefits such as the generated implementation of equality,
        etc.

        -Matthew

        --
        Dave

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        --
        Dave

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        --
        Dave

    --
    Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

For me and my English its become hard to follow where this is going right now.

Let’s stick with my `AnyReference` and `AnyValue` protocols just for the example.

Do I get your intention right that we discuss here about value types that are constructed from their deepest only from other value types (same for `PureReferences`)? That’s what my understanding is for `PureValue`.

···
               \+\-\-\-\-\-\+
               &gt; Any |
               \+\-\-\+\-\-\+
                  &gt;
    \+\-\-\-\-\-\-\-\-\-\-\-\-\-\+\-\-\-\-\-\-\-\-\-\-\-\-\-\+
    &gt;                           &gt;

+------+-------+ +-----+----+
> AnyReference | | AnyValue |
+--+---+-------+ +-----+----+
> > >
+-------+-------+ +-----+-----+

PureReference | | PureValue |

+---------------+ +-----+-----+
>
+---+--------------+

AnyObject (ObjC) |

+------------------+

Side note: If SE-0083 will be accepted it might be possible that @objc will be dropped from `AnyObject`, correct me if I'm wrong.

I'm fine with that if that’s the case, but I'm not if one-day Swift won't allow anymore to mix value types with reference types.

I also don't think that `PureReference` and `PureValue` protocols could be implicit, but their base protocols can.

Explicit usage of these protocols on actual types:

class A: PureValue {} // won't work

class B: PureReference {
  var value: OtherClass
} // can only contain only reference types (if that’s what we've been talking about here)

struct C: PureReference {} // won't work

struct D: PureValue {
  var value: Int
} // can only contain value types, and all value types inside follow the same rule

Explicit usage on protocols:

protocol E: SomeOtherProtocol, PureReference {} // shouldn't work, because if we want to replace the `class` keyword we should at least the rule that out constraint protocols should sit right behind `: ` or behind Any(Reference/Value) which will take the first place instead.

protocol F: PureReference {
  var value: SomeClass { get }
} // can only be applied to types that follow the pure reference constraint + SomeClass should follow the pure reference rule

protocol G: F {} // same as F

protocol H: SomeOtherProtocol, PureValue {} // same problem as with E

protocol I: PureValue {
  var value: Int
  func foo() -> Int
} // same rule as with class D

protocol J: PureValue {
  var value: SomeClass
} // should not work

protocol K: PureValue {
  func foo() -> SomeClass
} // I guess this should not work!?

protocol L: PureReference {
  func foo() -> Int
} // should this work?

protocol M: PureReference {
  func foo() -> SomeClass
} // like F

Implicit usage of the Any protocols:

class N {
  var value: SomeValue
  var anotherValue: SomeClass
  func foo() -> Int
  func boo() -> AClass
} // implicitly AnyReference; SomeClass can follow PureReference rule but still can be nested into a AnyClass or AnyValue type (same goes for SomeValue)

struct O {
  var value: SomeValue
  var anotherValue: SomeClass
  func foo() -> Int
  func boo() -> AClass
} // implicitly AnyValue; same rules as for N

Explicit protocol constrains:

protocol P: AnyValue, PureValue {} // or just PureValue

protocol Q: AnyReference, PureReference {} or just PureReference

protocol R: AnyValue {} // This protocol is problematic now, because logically we could apply it to a PureValue type but this shouldn’t work, just because we said that PureProtocols are more constrained

Now we have two options:

1. Split the Any and Pure concepts

              \+\-\-\-\-\-\-\+
              &gt; Pure |
              \+\-\-\+\-\-\-\+
                 &gt;
   \+\-\-\-\-\-\-\-\-\-\-\-\-\-\+\-\-\-\-\-\-\-\-\-\-\-\-\-\+
   &gt;                           &gt;

+------+--------+ +-----+-----+

PureReference | | PureValue |

+---------------+ +-----+-----+

              \+\-\-\-\-\-\+
              &gt; Any |
              \+\-\-\+\-\-\+
                 &gt;
   \+\-\-\-\-\-\-\-\-\-\-\-\-\-\+\-\-\-\-\-\-\-\-\-\-\-\-\+
   &gt;                          &gt;

+------+-------+ +-----+----+

AnyReference | | AnyValue |

+--------------+ +-----+----+

This solution feels strange. `Pure` is something like `AnyPure`.

2. Reorder Pure and Any protocols:

              \+\-\-\-\-\-\+
              &gt; Any |
              \+\-\-\+\-\-\+
                 &gt;
   \+\-\-\-\-\-\-\-\-\-\-\-\-\-\+\-\-\-\-\-\-\-\-\-\-\-\-\-\+
   &gt;                           &gt;

+------+--------+ +-----+-----+

PureReference | | PureValue |

+------+--------+ +-----+-----+
> >
+------+-------+ +-----+----+

AnyReference | | AnyValue |

+--------------+ +-----+----+

protocol R: AnyValue {} // is fine now because we can't apply it to a PureValue anymore.

With this reorder I suggest that `PureValue` and `PureReference` also becomes implicit protocols, BUT all existing types should be implicitly `AnyReference` or `AnyValue` where the strict rule from `PureProtocols` is ignored/disabled. To use the constraints of pure protocols should require its explicit usage.

Does this make any sense to you or am I totally wrong here?

What I’d prefer could look like this:

              \+\-\-\-\-\-\+
              &gt; Any |
              \+\-\-\+\-\-\+
                 &gt;
   \+\-\-\-\-\-\-\-\-\-\-\-\-\-\+\-\-\-\-\-\-\-\-\-\-\-\-\+
   &gt;                          &gt;

+------+-------+ +-----+----+

AnyReference | | AnyValue |

+--------------+ +-----+----+

pure protocol A: AnyReference {}
pure class B: A {}

I'm not sure why this topic become so complicated where we only discussed about dropping the `class` keyword from protocols and I suggested to use implicit protocols instead, where we need at least one more for value types (I'm fine with `AnyObject` as long it won't bridge to ObjC types anymore, but I'd rename it for possible new reference type in the future of Swift).

--
Adrian Zubarev
Sent with Airmail

Am 7. Mai 2016 bei 09:56:24, Tyler Fleming Cloutier via swift-evolution (swift-evolution@swift.org) schrieb:

On May 5, 2016, at 8:02 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

On May 5, 2016, at 4:59 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

   On May 4, 2016, at 5:50 PM, Dave Abrahams via swift\-evolution &lt;swift\-evolution@swift\.org&gt; wrote:

   on Wed May 04 2016, Matthew Johnson &lt;swift\-evolution@swift\.org&gt; wrote:

   On May 4, 2016, at 1:29 PM, Dave Abrahams via swift\-evolution &lt;swift\-evolution@swift\.org&gt; wrote:

   on Wed May 04 2016, Adrian Zubarev &lt;swift\-evolution@swift\.org&gt; wrote:

   Not sure what to think about the enum cases inside a
   protocol \(if AnyEnum would
   even exist\), it could be a nice addition to the language, but
   this is an own
   proposal I guess\.

   We should start by adding AnyValue protocol to which all value
   types
   conforms\.

   Having a way to constrain conformance to things with value semantics
   is
   something I&#39;ve long wanted\. \*However\*, the approach described is too
   simplistic\. It&#39;s possible to build classes whose instances have
   value
   semantics \(just make them immutable\) and it&#39;s possible to build
   structs
   whose instances have reference semantics \(just put the struct&#39;s
   storage
   in a mutable class instance that it holds as a property, and don&#39;t
   do
   copy\-on\-write\)\. 

   In order for something like AnyValue to have meaning, we need to
   impose
   greater order\. After thinking through many approaches over the
   years, I
   have arrived at the \(admittedly rather drastic\) opinion that the
   language should effectively outlaw the creation of structs and enums
   that don&#39;t have value semantics\. \(I have no problem with the idea
   that
   immutable classes that want to act as values should be wrapped in a
   struct\)\. The language could then do lots of things much more
   intelligently, such as correctly generating implementations of
   equality\.

   That is a drastic solution indeed\! How would this impact things like
   Array&lt;UIView&gt;? While Array itself has value semantics, the aggregate
   obviously does not as it contains references which usually be mutated
   underneath us\. 

   Value semantics and mutation can only be measured with respect to
   equality\. The definition of == for all class types would be equivalent
   to ===\. Problem solved\.

   Similar considerations apply to simpler wrapper structs such as Weak\.

   Same answer\.

   Hmm\. If those qualify as “value semantic” then what kind of structs and
   enums
   would not? 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\)\.

Sure it does.

public struct Wrap<T: AnyObject> : Equatable {
init(_ x: T) { self.x = x }
private x: T
}

func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
return lhs.x === rhs.x
}

I defy you to find any scenario where Wrap<T> doesn't have value
semantics, whether T is mutable or not.

Alternately, you can look at the Array implementation. Array is a
struct wrapping a mutable class. It has value semantics by virtue of
CoW.

This goes back to where you draw the line as to the “boundary of the value”.
Wrap and Array are “value semantic” in a shallow sense and are capable of deep
value semantics when T is deeply value semantic.

No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
not understanding the boundaries of your value. Or, put more
solicitously: sure, you can look at the world that way, but it just
makes everything prohibitively complicated, so why would you want to?

In my world, there's no such thing as a “deep copy” or a “shallow copy;”
there's just “copy,” which logically creates an independent version of
everything up to the boundaries of the value. Likewise, there's no
“deep value semantics” or “shallow value semantics.” Equality defines
value semantics, and the boundaries of an Array value always includes
the values of its elements. The *only* problem here is that we have no
way to do equality comparison on some arrays because some types aren't
Equatable. IMO the costs of not having everything be equatable, in
complexity-of-programming-model terms, are too high.

My point with this is, in case I was a bit rambling, if you’re going to draw boundaries around a value, for the purpose of copying or immutability, then equality should always match with those boundaries. As you say, “Equality defines value semantics, and the boundaries of an Array value always includes the values of its elements.”

Under this reasoning, custom equality violates these boundaries. And without custom equality, equality checks on reference types are essentially useless. But maybe value types in Swift are powerful enough where this doesn’t matter.

Both have their place, but the maximum benefit of value semantics
(purity)

I don't know what definition of purity you're using. The only one I
know of applies to functions and implies no side effects. In that
world, there is no mutation and value semantics is equivalent to
reference semantics.

is derived from deep value semantics. This is when there is no
possibility of shared mutable state. This is an extremely important
property.

It's the wrong property, IMO.

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.

   My expectation is a generic aggregate such as Array would have to
   conditionally conform to AnyValue only when Element also conforms to
   AnyValue\.

   I’m also wondering how such a rule would be implemented while still
   allowing for CoW structs that \*do\* implement value semantics, but do
   so while using references internally\.

   I am not talking about any kind of statically\-enforceable rule, although
   we could probably make warnings sophisticated enough to help with this\.

   You said the you have arrived at the opinion that the language should
   “effectively outlaw” structs and enums that do not have value semantics\.
   That
   sounded like static enforcement to me\. 

The language outlaws certain kinds of inout aliasing without
providing static enforcement. This is like that.

I did not know this. Now you have me curious. Can you give an example of where
we are able to violate law? I ask mostly because it sounds like there is a
possibility of stumbling into dangerous territory, possibly without being aware
that you have done so.

See “In-out Parameters” in
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID362

   Maybe you meant we should allow the compiler to assume value semantics
   for structs and enums despite the fact that it doesn’t statically
   enforce this?

That would be one *consequence* of effectively outlawing it. The library
could make similar assumptions.

   If the compiler can be sophisticated enough to verify value semantics
   statically maybe it would be better to have that mechanism be
   triggered by conformance to AnyValue rather than for all structs and
   enums\. Types that conform to AnyValue would receive the benefits of
   the compiler knowing they have value semantics, while other uses of
   structs and enums would remain valid\. Best practice would be to
   conform structs and enums to AnyValue whenever possible\.

   Another possible advantage of this approach would be allowing
   immutable reference types to conform to AnyValue and receive the
   associated benefits such as the generated implementation of equality,
   etc\.

   \-Matthew

   \-\- 
   Dave

   \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
   swift\-evolution mailing list
   swift\-evolution@swift\.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

   \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
   swift\-evolution mailing list
   swift\-evolution@swift\.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

   \-\- 
   Dave

   \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
   swift\-evolution mailing list
   swift\-evolution@swift\.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

--
Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

    No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
    not understanding the boundaries of your value. Or, put more
    solicitously: sure, you can look at the world that way, but it just
    makes everything prohibitively complicated, so why would you want to?

    In my world, there's no such thing as a “deep copy” or a “shallow copy;”
    there's just “copy,” which logically creates an independent version of
    everything up to the boundaries of the value. Likewise, there's no
    “deep value semantics” or “shallow value semantics.” Equality defines
    value semantics, and the boundaries of an Array value always includes
    the values of its elements. The *only* problem here is that we have no
    way to do equality comparison on some arrays because some types aren't
    Equatable. IMO the costs of not having everything be equatable, in
    complexity-of-programming-model terms, are too high.

My point with this is, in case I was a bit rambling, if you’re going to draw
boundaries around a value, for the purpose of copying or immutability, then
equality should always match with those boundaries.

Quite.

As you say, “Equality defines value semantics, and the boundaries of
an Array value always includes the values of its elements.”

Under this reasoning, custom equality violates these boundaries.

No, it defines those boundaries.

And without custom equality, equality checks on reference types are
essentially useless.

No, comparing reference identity is completely useful. That's why “===”
exists. We just spelled it wrong :-)

···

on Sat May 07 2016, Tyler Fleming Cloutier <cloutiertyler-AT-aol.com> wrote:

--
-Dave

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

   No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
   not understanding the boundaries of your value. Or, put more
   solicitously: sure, you can look at the world that way, but it just
   makes everything prohibitively complicated, so why would you want to?

   In my world, there's no such thing as a “deep copy” or a “shallow copy;”
   there's just “copy,” which logically creates an independent version of
   everything up to the boundaries of the value. Likewise, there's no
   “deep value semantics” or “shallow value semantics.”

   Equality defines
   value semantics, and the boundaries of an Array value always includes
   the values of its elements. The *only* problem here is that we have no
   way to do equality comparison on some arrays because some types aren't
   Equatable. IMO the costs of not having everything be equatable, in
   complexity-of-programming-model terms, are too high.

Thank you for clarifying the terminology for me. This is helpful.

I think I may have misunderstood what you meant by “boundary of the value”. Do
you mean that the boundary of an Array value stops at the reference identity for
elements with reference semantics?

Yes.

If you have an Array whose elements are of an immutable reference type
that has value semantics would you say the boundary extends past the
reference identity of an element and includes a definition of equality
defined by that type?

Yes!

Are you arguing that reference types should be equatable by default, using
equality of the reference if the type does not provide a custom definition of
equality?

Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

   I don't know what definition of purity you're using. The only one I
   know of applies to functions and implies no side effects. In that
   world, there is no mutation and value semantics is equivalent to
   reference semantics.

I was using it in the sense of “PureValue” as discussed in this
thread.

Sorry, this is the first mention I can find in the whole thread, honest.
Oh, it was a different thread. Joe describes it as a protocol for
“types that represent fully self-contained values,” which is just fuzzy
enough that everyone reading it can have his own interpretation of what
it means.

I was using it to mean values for which no *observable* mutation is
possible (allowing for CoW, etc). Is there a better term for this than
purity?

You're still not making any sense to me. A type for which no observable
mutation is possible is **immutable**. The “write” part of
copy-on-write is a pretty clear indicator that it's all about
**mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable mutation *that happens behind your back*. In other words, the only *observable* mutation possible is local. Immutability accomplishes this by simply prohibiting all mutation. Primitive value types like Int and structs or enums that only contain primitive value types accomplish this by getting copied everywhere.

Swift’s collections also accomplish this through copying, but only when the elements they contain also have the same property. On the other hand, it is immediately obvious that non-local mutation is quite possibly in the elements of a Swift Array<AnyObject> unless they are all uniquely referenced.

I think perhaps what you mean by “purity” is just, “has value
semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

   It's the wrong property, IMO.

Wrong in what sense?

Wrong in the sense that it rules out using things like Array that are
logically value types but happen to be implemented with CoW, and if you
have proper encapsulation there's no way for these types to behave as
anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been miscommunicating if you thought I was suggesting something that would prohibit CoW.

I don’t mean to imply that it is the *only* valuable
property. However, it I (and many others) do believe it is an extremely valuable
property in many cases. Do you disagree?

I think I do. What is valuable about such a protocol? What generic
algorithms could you write that work on models of PureValue but don't
work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be any. Array<AnyObject> is a completely different story. With Array<AnyObject> you cannot rely on a guarantee the objects contained in the array will not be mutated by code elsewhere that also happens to have a reference to the same objects.

       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). It certainly isn’t irrelevant to that point.

···

On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

   On May 5, 2016, at 10:02 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
   on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson >> <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev >> <swift-evolution@swift.org> >> wrote:

HTH,

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

       The language outlaws certain kinds of inout aliasing without
       providing static enforcement. This is like that.

       I did not know this. Now you have me curious. Can you give an example of
       where
       we are able to violate law? I ask mostly because it sounds like there is
       a
       possibility of stumbling into dangerous territory, possibly without
       being aware
       that you have done so.

   See “In-out Parameters” in
   The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

       That would be one *consequence* of effectively outlawing it. The library
       could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

   --
   Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

FWIW, I've been taking it to mean a) something that can always be correctly copied simply by copying its memory, and b) something for which equality can be determined by comparing memory (or at least won't give a false positive... I hadn't considered the "0 == -0" kind of equality until just now).

I'm not sure that's any less fuzzy than the description you referenced, though. This thread has several terms that I'm not as familiar with as I should be.

- Dave Sweeris

···

On May 6, 2016, at 19:48, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, this is the first mention I can find in the whole thread, honest.
Oh, it was a different thread. Joe describes it as a protocol for
“types that represent fully self-contained values,” which is just fuzzy
enough that everyone reading it can have his own interpretation of what
it means.

class Storage {
  var element: Int = 0
}

struct Value {
  var storage: Storage
}

func amIPure(v: Value) -> Int {
  v.storage.element = 3
  return v.storage.element
}

I (the optimizer) want to know if 'amIPure' is a pure function. The developer needs to tell me where the boundaries of the value lie. Does 'storage' lie inside the Value, or outside? If it is inside, then Value is a 'PureValue' and 'amIPure' is a pure function. To enforce that, the developer will need to implement CoW, or we need add some language features.

If I know about every operation inside 'amIPure', and know where the value's boundary is, then I don't really need to know that 'Value' is a 'PureValue'. For example, I know that this function is pure without caring about 'PureValue'.

func IAmPure(v: Value, s: Storage) -> Int {
  var t = v
  t.storage = s
  return t.storage.element
}

However, I might only have summary information. I might know that the function only writes to memory reachable from Value. In that case, it would be nice to have summary information about the storage type. 'PureValue' is another way of saying that it does not contain references to objects outside the value's boundary (I would add that it cannot have a user-defined deinit). The only thing vague about that is that we don't have a general way for the developer to define the value's boundary. It certainly should be consistent with '==', but implementing '==' doesn't tell the optimizer anything.

Anyway, these are only optimizer concerns, and programming model should take precedence in these discussion. But I thought that might help.

-Andy

···

On May 6, 2016, at 5:48 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

I don’t mean to imply that it is the *only* valuable
property. However, it I (and many others) do believe it is an extremely valuable
property in many cases. Do you disagree?

I think I do. What is valuable about such a protocol? What generic
algorithms could you write that work on models of PureValue but don't
work just as well on Array<Int>?

        Not sure what to think about the enum cases inside a
        protocol (if AnyEnum would
        even exist), it could be a nice addition to the language, but
        this is an own
        proposal I guess.

        We should start by adding AnyValue protocol to which all value
        types
        conforms.

        Having a way to constrain conformance to things with value semantics
        is
        something I've long wanted. *However*, the approach described is too
        simplistic. It's possible to build classes whose instances have
        value
        semantics (just make them immutable) and it's possible to build
        structs
        whose instances have reference semantics (just put the struct's
        storage
        in a mutable class instance that it holds as a property, and don't
        do
        copy-on-write).

        In order for something like AnyValue to have meaning, we need to
        impose
        greater order. After thinking through many approaches over the
        years, I
        have arrived at the (admittedly rather drastic) opinion that the
        language should effectively outlaw the creation of structs and enums
        that don't have value semantics. (I have no problem with the idea
        that
        immutable classes that want to act as values should be wrapped in a
        struct). The language could then do lots of things much more
        intelligently, such as correctly generating implementations of
        equality.

        That is a drastic solution indeed! How would this impact things like
        Array<UIView>? While Array itself has value semantics, the aggregate
        obviously does not as it contains references which usually be mutated
        underneath us.

        Value semantics and mutation can only be measured with respect to
        equality. The definition of == for all class types would be equivalent
        to ===. Problem solved.

        Similar considerations apply to simpler wrapper structs such as Weak.

        Same answer.

        Hmm. If those qualify as “value semantic” then what kind of structs and
        enums
        would not? 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).

        Sure it does.

        public struct Wrap<T: AnyObject> : Equatable {
        init(_ x: T) { self.x = x }
        private x: T
        }

        func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
        return lhs.x === rhs.x
        }

        I defy you to find any scenario where Wrap<T> doesn't have value
        semantics, whether T is mutable or not.

        Alternately, you can look at the Array implementation. Array is a
        struct wrapping a mutable class. It has value semantics by virtue of
        CoW.

        This goes back to where you draw the line as to the “boundary of the
        value”.
        Wrap and Array are “value semantic” in a shallow sense and are capable
        of deep
        value semantics when T is deeply value semantic.

        No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
        not understanding the boundaries of your value. Or, put more
        solicitously: sure, you can look at the world that way, but it just
        makes everything prohibitively complicated, so why would you want to?

        In my world, there's no such thing as a “deep copy” or a “shallow copy;”
        there's just “copy,” which logically creates an independent version of
        everything up to the boundaries of the value. Likewise, there's no
        “deep value semantics” or “shallow value semantics.”

        Equality defines
        value semantics, and the boundaries of an Array value always includes
        the values of its elements. The *only* problem here is that we have no
        way to do equality comparison on some arrays because some types aren't
        Equatable. IMO the costs of not having everything be equatable, in
        complexity-of-programming-model terms, are too high.

        Thank you for clarifying the terminology for me. This is helpful.

        I think I may have misunderstood what you meant by “boundary of the
        value”. Do
        you mean that the boundary of an Array value stops at the reference
        identity for
        elements with reference semantics?

    Yes.

        If you have an Array whose elements are of an immutable reference type
        that has value semantics would you say the boundary extends past the
        reference identity of an element and includes a definition of equality
        defined by that type?

    Yes!

        Are you arguing that reference types should be equatable by default,
        using
        equality of the reference if the type does not provide a custom
        definition of
        equality?

    Yes!!

        Both have their place, but the maximum benefit of value semantics
        (purity)

        I don't know what definition of purity you're using. The only one I
        know of applies to functions and implies no side effects. In that
        world, there is no mutation and value semantics is equivalent to
        reference semantics.

        I was using it in the sense of “PureValue” as discussed in this
        thread.

    Sorry, this is the first mention I can find in the whole thread, honest.
    Oh, it was a different thread. Joe describes it as a protocol for
    “types that represent fully self-contained values,” which is just fuzzy
    enough that everyone reading it can have his own interpretation of what
    it means.

        I was using it to mean values for which no *observable* mutation is
        possible (allowing for CoW, etc). Is there a better term for this than
        purity?

    You're still not making any sense to me. A type for which no observable
    mutation is possible is **immutable**. The “write” part of
    copy-on-write is a pretty clear indicator that it's all about
    **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

    I think perhaps what you mean by “purity” is just, “has value
    semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

        is derived from deep value semantics. This is when there is no
        possibility of shared mutable state. This is an extremely important
        property.

        It's the wrong property, IMO.

        Wrong in what sense?

    Wrong in the sense that it rules out using things like Array that are
    logically value types but happen to be implemented with CoW, and if you
    have proper encapsulation there's no way for these types to behave as
    anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

        I don’t mean to imply that it is the *only* valuable
        property. However, it I (and many others) do believe it is an extremely
        valuable
        property in many cases. Do you disagree?

    I think I do. What is valuable about such a protocol? What generic
    algorithms could you write that work on models of PureValue but don't
    work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

        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?

···

on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

    On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
    on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
        On May 5, 2016, at 10:02 PM, Dave Abrahams > <dabrahams@apple.com> wrote:
        on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
        On May 5, 2016, at 4:59 PM, Dave Abrahams > <dabrahams@apple.com> wrote:
        on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
        On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
        on Wed May 04 2016, Matthew Johnson > <swift-evolution@swift.org> wrote:
        On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
        on Wed May 04 2016, Adrian Zubarev > <swift-evolution@swift.org> > wrote:

It certainly isn’t irrelevant to that point.

    HTH,

        My expectation is a generic aggregate such as Array would have to
        conditionally conform to AnyValue only when Element also conforms to
        AnyValue.

        I’m also wondering how such a rule would be implemented while still
        allowing for CoW structs that *do* implement value semantics, but do
        so while using references internally.

        I am not talking about any kind of statically-enforceable rule, although
        we could probably make warnings sophisticated enough to help with this.

        You said the you have arrived at the opinion that the language should
        “effectively outlaw” structs and enums that do not have value semantics.
        That
        sounded like static enforcement to me.

        The language outlaws certain kinds of inout aliasing without
        providing static enforcement. This is like that.

        I did not know this. Now you have me curious. Can you give an example of
        where
        we are able to violate law? I ask mostly because it sounds like there is
        a
        possibility of stumbling into dangerous territory, possibly without
        being aware
        that you have done so.

        See “In-out Parameters” in
        The Swift Programming Language: Redirect

        Maybe you meant we should allow the compiler to assume value semantics
        for structs and enums despite the fact that it doesn’t statically
        enforce this?

        That would be one *consequence* of effectively outlawing it. The library
        could make similar assumptions.

        If the compiler can be sophisticated enough to verify value semantics
        statically maybe it would be better to have that mechanism be
        triggered by conformance to AnyValue rather than for all structs and
        enums. Types that conform to AnyValue would receive the benefits of
        the compiler knowing they have value semantics, while other uses of
        structs and enums would remain valid. Best practice would be to
        conform structs and enums to AnyValue whenever possible.

        Another possible advantage of this approach would be allowing
        immutable reference types to conform to AnyValue and receive the
        associated benefits such as the generated implementation of equality,
        etc.

        -Matthew

        --
        Dave

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        --
        Dave

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

        --
        Dave

        --
        Dave

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org
        https://lists.swift.org/mailman/listinfo/swift-evolution

    --
    Dave

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org
    https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

       No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
       not understanding the boundaries of your value. Or, put more
       solicitously: sure, you can look at the world that way, but it just
       makes everything prohibitively complicated, so why would you want to?

       In my world, there's no such thing as a “deep copy” or a “shallow copy;”
       there's just “copy,” which logically creates an independent version of
       everything up to the boundaries of the value. Likewise, there's no
       “deep value semantics” or “shallow value semantics.”

       Equality defines
       value semantics, and the boundaries of an Array value always includes
       the values of its elements. The *only* problem here is that we have no
       way to do equality comparison on some arrays because some types aren't
       Equatable. IMO the costs of not having everything be equatable, in
       complexity-of-programming-model terms, are too high.

       Thank you for clarifying the terminology for me. This is helpful.

       I think I may have misunderstood what you meant by “boundary of the
       value”. Do
       you mean that the boundary of an Array value stops at the reference
       identity for
       elements with reference semantics?

   Yes.

       If you have an Array whose elements are of an immutable reference type
       that has value semantics would you say the boundary extends past the
       reference identity of an element and includes a definition of equality
       defined by that type?

   Yes!

       Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

       I don't know what definition of purity you're using. The only one I
       know of applies to functions and implies no side effects. In that
       world, there is no mutation and value semantics is equivalent to
       reference semantics.

       I was using it in the sense of “PureValue” as discussed in this
       thread.

   Sorry, this is the first mention I can find in the whole thread, honest.
   Oh, it was a different thread. Joe describes it as a protocol for
   “types that represent fully self-contained values,” which is just fuzzy
   enough that everyone reading it can have his own interpretation of what
   it means.

       I was using it to mean values for which no *observable* mutation is
       possible (allowing for CoW, etc). Is there a better term for this than
       purity?

   You're still not making any sense to me. A type for which no observable
   mutation is possible is **immutable**. The “write” part of
   copy-on-write is a pretty clear indicator that it's all about
   **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

This does not make sense, because you’ve got problems either way. You are arguing, essentially, that everything is a value type because references/pointers are a value. If that were the case then the *only* valid way to compare the equality of types would be to compare their values. Overriding the equality operator would inherently violate the property of immutability, i.e. two immutable objects can change their equality even without mutation of their “values".

func ==(lhs, rhs) {
  ...
}

class MyClass {
    var a: Int
    
    ...

}

let x = MyClass(a: 5)
let y = MyClass(a: 5)

x == y // true
y.a = 6
x == y // false

Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

Custom definitions of equality, inherently, decouple immutability from equality, as shown above. Swift makes it appear as though references and values are on the same level in a way that C does not.

let x = MyStruct()
let y = MyClass()

x.myFoo
y.myFoo

vs

my_struct *x = …
my_struct y = …

x.my_foo
y->my_foo

With C it is explicit that you are crossing a reference. Thus there is only *one* type of equality in C, that the values *are equal*. This exactly the type of equality you are referring to, but this does not carry over to Swift for precisely the reason that Swift paves over the difference between value and reference types, and then allows you to redefine equality.

Therefore, in essentially no circumstances does it make sense to compare a type by its reference if it has any associated data in Swift. Basically, if it will be commonplace to override the equality operator to compare the first level of associated values of a reference type, then the comparison of just the reference has no business being the default.

If the default equality for reference types was defined as the equality of the references it would be inconsistent with the Swift’s current apparent surfacing of the first level of associated data for reference types.

   I think perhaps what you mean by “purity” is just, “has value
   semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

       It's the wrong property, IMO.

       Wrong in what sense?

   Wrong in the sense that it rules out using things like Array that are
   logically value types but happen to be implemented with CoW, and if you
   have proper encapsulation there's no way for these types to behave as
   anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

I assume what is meant by "PureValue", is any object A, whose own references form a subgraph, within which a change to any of the values would constitute a change in the value of A (thus impermissible if A is immutable). Thus structs would quality as “PureValues”.

I also assume that enforcing immutability on an object graph, via CoW or otherwise, would be unfeasible. You could enforce it on all values accessible by traversing a single reference for reference types, however.

This is why I don’t really buy the argument that there is no such this as deep vs shallow copy. Deep copy means copying the whole “PureValue” or subgraph, shallow copy means traversing a single reference and copying all accessible values.

···

On May 6, 2016, at 6:54 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:

   On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
   on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 5, 2016, at 10:02 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
       on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson >> <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev >> <swift-evolution@swift.org> >> wrote:

       I don’t mean to imply that it is the *only* valuable
       property. However, it I (and many others) do believe it is an extremely
       valuable
       property in many cases. Do you disagree?

   I think I do. What is valuable about such a protocol? What generic
   algorithms could you write that work on models of PureValue but don't
   work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

       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?

It certainly isn’t irrelevant to that point.

   HTH,

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

       The language outlaws certain kinds of inout aliasing without
       providing static enforcement. This is like that.

       I did not know this. Now you have me curious. Can you give an example of
       where
       we are able to violate law? I ask mostly because it sounds like there is
       a
       possibility of stumbling into dangerous territory, possibly without
       being aware
       that you have done so.

       See “In-out Parameters” in
       The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

       That would be one *consequence* of effectively outlawing it. The library
       could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

   _______________________________________________
   swift-evolution mailing list
   swift-evolution@swift.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

       No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
       not understanding the boundaries of your value. Or, put more
       solicitously: sure, you can look at the world that way, but it just
       makes everything prohibitively complicated, so why would you want to?

       In my world, there's no such thing as a “deep copy” or a “shallow copy;”
       there's just “copy,” which logically creates an independent version of
       everything up to the boundaries of the value. Likewise, there's no
       “deep value semantics” or “shallow value semantics.”

       Equality defines
       value semantics, and the boundaries of an Array value always includes
       the values of its elements. The *only* problem here is that we have no
       way to do equality comparison on some arrays because some types aren't
       Equatable. IMO the costs of not having everything be equatable, in
       complexity-of-programming-model terms, are too high.

       Thank you for clarifying the terminology for me. This is helpful.

       I think I may have misunderstood what you meant by “boundary of the
       value”. Do
       you mean that the boundary of an Array value stops at the reference
       identity for
       elements with reference semantics?

   Yes.

       If you have an Array whose elements are of an immutable reference type
       that has value semantics would you say the boundary extends past the
       reference identity of an element and includes a definition of equality
       defined by that type?

   Yes!

       Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

       I don't know what definition of purity you're using. The only one I
       know of applies to functions and implies no side effects. In that
       world, there is no mutation and value semantics is equivalent to
       reference semantics.

       I was using it in the sense of “PureValue” as discussed in this
       thread.

   Sorry, this is the first mention I can find in the whole thread, honest.
   Oh, it was a different thread. Joe describes it as a protocol for
   “types that represent fully self-contained values,” which is just fuzzy
   enough that everyone reading it can have his own interpretation of what
   it means.

       I was using it to mean values for which no *observable* mutation is
       possible (allowing for CoW, etc). Is there a better term for this than
       purity?

   You're still not making any sense to me. A type for which no observable
   mutation is possible is **immutable**. The “write” part of
   copy-on-write is a pretty clear indicator that it's all about
   **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

I think part of the disconnect here might be the domains in which we work. Maybe you're coming at this primarily from an algorithmic perspective and I'm coming at it primarily from an app development perspective.

For example, I think it is perfectly reasonable to write a generic view controller that works with various data types and is initialized with an Array<T> but only works properly when it isn't possible to observe any mutation in the subgraph of T.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

In application code we are concerned with the objects, not the references.

   I think perhaps what you mean by “purity” is just, “has value
   semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

       It's the wrong property, IMO.

       Wrong in what sense?

   Wrong in the sense that it rules out using things like Array that are
   logically value types but happen to be implemented with CoW, and if you
   have proper encapsulation there's no way for these types to behave as
   anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

I believe it is a purely semantic concept. It means that every name binding is logically and observably distinct, including and objects in the aggregate (if it includes references). This allows for local mutation on the same binding and also for un observable mutation such as CoW in the implementation. But it does not allow for a mutation applied to one name binding having the type to be observed through another name binding having the type.

       I don’t mean to imply that it is the *only* valuable
       property. However, it I (and many others) do believe it is an extremely
       valuable
       property in many cases. Do you disagree?

   I think I do. What is valuable about such a protocol? What generic
   algorithms could you write that work on models of PureValue but don't
   work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

I am not sure. It is possible that it does not apply to purely algorithmic work. That does not mean it is unimportant. It is quite valuable in application level code. It think it would be valuable to reify it with a protocol rather than leaving it to documentation even if the compiler can't always prove our code meets this semantic.

If you don't like the name PureValue for this concept lets bike shed. I only used it because others had already used it. Maybe there is a better name.

       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?

I hope my previous comments have helped to clarify this.

···

Sent from my iPad

On May 6, 2016, at 8:54 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
   On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
   on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 5, 2016, at 10:02 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
       on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >> <dabrahams@apple.com> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson >> <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev >> <swift-evolution@swift.org> >> wrote:

It certainly isn’t irrelevant to that point.

   HTH,

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

       The language outlaws certain kinds of inout aliasing without
       providing static enforcement. This is like that.

       I did not know this. Now you have me curious. Can you give an example of
       where
       we are able to violate law? I ask mostly because it sounds like there is
       a
       possibility of stumbling into dangerous territory, possibly without
       being aware
       that you have done so.

       See “In-out Parameters” in
       The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

       That would be one *consequence* of effectively outlawing it. The library
       could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

   _______________________________________________
   swift-evolution mailing list
   swift-evolution@swift.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

I don’t mean to imply that it is the *only* valuable
property. However, it I (and many others) do believe it is an extremely valuable
property in many cases. Do you disagree?

I think I do. What is valuable about such a protocol? What generic
algorithms could you write that work on models of PureValue but don't
work just as well on Array<Int>?

class Storage {
  var element: Int = 0
}

struct Value {
  var storage: Storage
}

func amIPure(v: Value) -> Int {
  v.storage.element = 3
  return v.storage.element
}

I (the optimizer) want to know if 'amIPure' is a pure function. The developer needs to tell me where the boundaries of the value lie. Does 'storage' lie inside the Value, or outside? If it is inside, then Value is a 'PureValue' and 'amIPure' is a pure function. To enforce that, the developer will need to implement CoW, or we need add some language features.

Thank you for this clear exposition of how PureValue relates to pure functions. This is the exact intuition I have about it but you have stated it much more clearly.

Language features to help automate CoW would be great. It would eliminate boilerplate, but more importantly it would likely provide more information to the compiler.

If I know about every operation inside 'amIPure', and know where the value's boundary is, then I don't really need to know that 'Value' is a 'PureValue'. For example, I know that this function is pure without caring about 'PureValue'.

func IAmPure(v: Value, s: Storage) -> Int {
  var t = v
  t.storage = s
  return t.storage.element
}

However, I might only have summary information. I might know that the function only writes to memory reachable from Value. In that case, it would be nice to have summary information about the storage type. 'PureValue' is another way of saying that it does not contain references to objects outside the value's boundary (I would add that it cannot have a user-defined deinit). The only thing vague about that is that we don't have a general way for the developer to define the value's boundary. It certainly should be consistent with '==', but implementing '==' doesn't tell the optimizer anything.

I think the ability to define the value's boundary would be wonderful. If we added a way to do this it would be a requirement of PureValue.

···

Sent from my iPad

On May 7, 2016, at 2:21 AM, Andrew Trick via swift-evolution <swift-evolution@swift.org> wrote:

On May 6, 2016, at 5:48 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

Anyway, these are only optimizer concerns, and programming model should take precedence in these discussion. But I thought that might help.

-Andy
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

        I don’t mean to imply that it is the *only* valuable
        property. However, it I (and many others) do believe it is an extremely
        valuable
        property in many cases. Do you disagree?

    I think I do. What is valuable about such a protocol? What generic
    algorithms could you write that work on models of PureValue but don't
    work just as well on Array<Int>?

class Storage {
var element: Int = 0
}

struct Value {
var storage: Storage
}

func amIPure(v: Value) -> Int {
v.storage.element = 3
return v.storage.element
}

I (the optimizer) want to know if 'amIPure' is a pure function. The developer
needs to tell me where the boundaries of the value lie. Does 'storage' lie
inside the Value, or outside? If it is inside, then Value is a 'PureValue' and
'amIPure' is a pure function. To enforce that, the developer will need to
implement CoW, or we need add some language features.

If I know about every operation inside 'amIPure', and know where the value's
boundary is, then I don't really need to know that 'Value' is a 'PureValue'. For
example, I know that this function is pure without caring about 'PureValue'.

func IAmPure(v: Value, s: Storage) -> Int {
var t = v
t.storage = s
return t.storage.element
}

How do you know this? t.storage can be a computed property. I think
you're assuming a lot of information is being communicated to me and to
the compiler from the types in the signature (e.g. can Value be a
reference type?)

However, I might only have summary information. I might know that the function
only writes to memory reachable from Value. In that case, it would be nice to
have summary information about the storage type. 'PureValue' is another way of
saying that it does not contain references to objects outside the value's
boundary (I would add that it cannot have a user-defined deinit). The only thing
vague about that is that we don't have a general way for the developer to define
the value's boundary. It certainly should be consistent with '==', but
implementing '==' doesn't tell the optimizer anything.

Anyway, these are only optimizer concerns, and programming model should take
precedence in these discussion.

Indeed, I am arguing from the point of view of the programming model. I
am very wary of introducing protocols that are only there for the use of
the optimizer.

···

on Sat May 07 2016, Andrew Trick <atrick-AT-apple.com> wrote:

    On May 6, 2016, at 5:48 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:

--
-Dave

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

       No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
       not understanding the boundaries of your value. Or, put more
       solicitously: sure, you can look at the world that way, but it just
       makes everything prohibitively complicated, so why would you want to?

       In my world, there's no such thing as a “deep copy” or a “shallow copy;”
       there's just “copy,” which logically creates an independent version of
       everything up to the boundaries of the value. Likewise, there's no
       “deep value semantics” or “shallow value semantics.”

       Equality defines
       value semantics, and the boundaries of an Array value always includes
       the values of its elements. The *only* problem here is that we have no
       way to do equality comparison on some arrays because some types aren't
       Equatable. IMO the costs of not having everything be equatable, in
       complexity-of-programming-model terms, are too high.

       Thank you for clarifying the terminology for me. This is helpful.

       I think I may have misunderstood what you meant by “boundary of the
       value”. Do
       you mean that the boundary of an Array value stops at the reference
       identity for
       elements with reference semantics?

   Yes.

       If you have an Array whose elements are of an immutable reference type
       that has value semantics would you say the boundary extends past the
       reference identity of an element and includes a definition of equality
       defined by that type?

   Yes!

       Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

       I don't know what definition of purity you're using. The only one I
       know of applies to functions and implies no side effects. In that
       world, there is no mutation and value semantics is equivalent to
       reference semantics.

       I was using it in the sense of “PureValue” as discussed in this
       thread.

   Sorry, this is the first mention I can find in the whole thread, honest.
   Oh, it was a different thread. Joe describes it as a protocol for
   “types that represent fully self-contained values,” which is just fuzzy
   enough that everyone reading it can have his own interpretation of what
   it means.

       I was using it to mean values for which no *observable* mutation is
       possible (allowing for CoW, etc). Is there a better term for this than
       purity?

   You're still not making any sense to me. A type for which no observable
   mutation is possible is **immutable**. The “write” part of
   copy-on-write is a pretty clear indicator that it's all about
   **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

This does not make sense, because you’ve got problems either way. You are arguing, essentially, that everything is a value type because references/pointers are a value. If that were the case then the *only* valid way to compare the equality of types would be to compare their values. Overriding the equality operator would inherently violate the property of immutability, i.e. two immutable objects can change their equality even without mutation of their “values".

func ==(lhs, rhs) {
  ...
}

class MyClass {
    var a: Int
    
    ...

}

let x = MyClass(a: 5)
let y = MyClass(a: 5)

x == y // true
y.a = 6
x == y // false

Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

Custom definitions of equality, inherently, decouple immutability from equality, as shown above. Swift makes it appear as though references and values are on the same level in a way that C does not.

let x = MyStruct()
let y = MyClass()

x.myFoo
y.myFoo

vs

my_struct *x = …
my_struct y = …

x.my_foo
y->my_foo

With C it is explicit that you are crossing a reference. Thus there is only *one* type of equality in C, that the values *are equal*. This exactly the type of equality you are referring to, but this does not carry over to Swift for precisely the reason that Swift paves over the difference between value and reference types, and then allows you to redefine equality.

Therefore, in essentially no circumstances does it make sense to compare a type by its reference if it has any associated data in Swift. Basically, if it will be commonplace to override the equality operator to compare the first level of associated values of a reference type, then the comparison of just the reference has no business being the default.

If the default equality for reference types was defined as the equality of the references it would be inconsistent with the Swift’s current apparent surfacing of the first level of associated data for reference types.

   I think perhaps what you mean by “purity” is just, “has value
   semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

       It's the wrong property, IMO.

       Wrong in what sense?

   Wrong in the sense that it rules out using things like Array that are
   logically value types but happen to be implemented with CoW, and if you
   have proper encapsulation there's no way for these types to behave as
   anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

I assume what is meant by "PureValue", is any object A, whose own references form a subgraph, within which a change to any of the values would constitute a change in the value of A (thus impermissible if A is immutable). Thus structs would quality as “PureValues”.

Thus structs *without references would qualify.

···

On May 6, 2016, at 9:19 PM, Tyler Fleming Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

On May 6, 2016, at 6:54 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:

   On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
   on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
       On May 5, 2016, at 10:02 PM, Dave Abrahams >>> <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:
       on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >>> <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/&gt;&gt; wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
       on Wed May 04 2016, Matthew Johnson >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
       on Wed May 04 2016, Adrian Zubarev >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>> wrote:

I also assume that enforcing immutability on an object graph, via CoW or otherwise, would be unfeasible. You could enforce it on all values accessible by traversing a single reference for reference types, however.

This is why I don’t really buy the argument that there is no such this as deep vs shallow copy. Deep copy means copying the whole “PureValue” or subgraph, shallow copy means traversing a single reference and copying all accessible values.

       I don’t mean to imply that it is the *only* valuable
       property. However, it I (and many others) do believe it is an extremely
       valuable
       property in many cases. Do you disagree?

   I think I do. What is valuable about such a protocol? What generic
   algorithms could you write that work on models of PureValue but don't
   work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

       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?

It certainly isn’t irrelevant to that point.

   HTH,

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

       The language outlaws certain kinds of inout aliasing without
       providing static enforcement. This is like that.

       I did not know this. Now you have me curious. Can you give an example of
       where
       we are able to violate law? I ask mostly because it sounds like there is
       a
       possibility of stumbling into dangerous territory, possibly without
       being aware
       that you have done so.

       See “In-out Parameters” in
       The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

       That would be one *consequence* of effectively outlawing it. The library
       could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org <mailto:swift-evolution@swift.org>
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org <mailto:swift-evolution@swift.org>
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org <mailto:swift-evolution@swift.org>
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org <mailto:swift-evolution@swift.org>
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

   _______________________________________________
   swift-evolution mailing list
   swift-evolution@swift.org <mailto:swift-evolution@swift.org>
   https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

       No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
       not understanding the boundaries of your value. Or, put more
       solicitously: sure, you can look at the world that way, but it just
       makes everything prohibitively complicated, so why would you want to?

       In my world, there's no such thing as a “deep copy” or a “shallow copy;”
       there's just “copy,” which logically creates an independent version of
       everything up to the boundaries of the value. Likewise, there's no
       “deep value semantics” or “shallow value semantics.”

       Equality defines
       value semantics, and the boundaries of an Array value always includes
       the values of its elements. The *only* problem here is that we have no
       way to do equality comparison on some arrays because some types aren't
       Equatable. IMO the costs of not having everything be equatable, in
       complexity-of-programming-model terms, are too high.

       Thank you for clarifying the terminology for me. This is helpful.

       I think I may have misunderstood what you meant by “boundary of the
       value”. Do
       you mean that the boundary of an Array value stops at the reference
       identity for
       elements with reference semantics?

   Yes.

       If you have an Array whose elements are of an immutable reference type
       that has value semantics would you say the boundary extends past the
       reference identity of an element and includes a definition of equality
       defined by that type?

   Yes!

       Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

       I don't know what definition of purity you're using. The only one I
       know of applies to functions and implies no side effects. In that
       world, there is no mutation and value semantics is equivalent to
       reference semantics.

       I was using it in the sense of “PureValue” as discussed in this
       thread.

   Sorry, this is the first mention I can find in the whole thread, honest.
   Oh, it was a different thread. Joe describes it as a protocol for
   “types that represent fully self-contained values,” which is just fuzzy
   enough that everyone reading it can have his own interpretation of what
   it means.

       I was using it to mean values for which no *observable* mutation is
       possible (allowing for CoW, etc). Is there a better term for this than
       purity?

   You're still not making any sense to me. A type for which no observable
   mutation is possible is **immutable**. The “write” part of
   copy-on-write is a pretty clear indicator that it's all about
   **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

This does not make sense, because you’ve got problems either way. You are arguing, essentially, that everything is a value type because references/pointers are a value. If that were the case then the *only* valid way to compare the equality of types would be to compare their values. Overriding the equality operator would inherently violate the property of immutability, i.e. two immutable objects can change their equality even without mutation of their “values".

func ==(lhs, rhs) {
  ...
}

class MyClass {
    var a: Int
    
    ...

}

let x = MyClass(a: 5)
let y = MyClass(a: 5)

x == y // true
y.a = 6
x == y // false

Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

Custom definitions of equality, inherently, decouple immutability from equality, as shown above. Swift makes it appear as though references and values are on the same level in a way that C does not.

let x = MyStruct()
let y = MyClass()

x.myFoo
y.myFoo

vs

my_struct *x = …
my_struct y = …

x.my_foo
y->my_foo

With C it is explicit that you are crossing a reference. Thus there is only *one* type of equality in C, that the values *are equal*. This exactly the type of equality you are referring to, but this does not carry over to Swift for precisely the reason that Swift paves over the difference between value and reference types, and then allows you to redefine equality.

Therefore, in essentially no circumstances does it make sense to compare a type by its reference if it has any associated data in Swift. Basically, if it will be commonplace to override the equality operator to compare the first level of associated values of a reference type, then the comparison of just the reference has no business being the default.

If the default equality for reference types was defined as the equality of the references it would be inconsistent with the Swift’s current apparent surfacing of the first level of associated data for reference types.

This depends on the type. For types representing resources, etc it works just fine. But for models it does not work unless the model subgraph is entirely immutable and instances are unique. I agree that it isn't a good idea to provide a default that will certainly be wrong in many cases.

   I think perhaps what you mean by “purity” is just, “has value
   semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

       It's the wrong property, IMO.

       Wrong in what sense?

   Wrong in the sense that it rules out using things like Array that are
   logically value types but happen to be implemented with CoW, and if you
   have proper encapsulation there's no way for these types to behave as
   anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

I assume what is meant by "PureValue", is any object A, whose own references form a subgraph, within which a change to any of the values would constitute a change in the value of A (thus impermissible if A is immutable). Thus structs would quality as “PureValues”.

As you noted in a followup, not all structs qualify. Structs that whose members all qualify will qualify. References to a subgraph that doesn't allow for any observable mutation (i.e. deeply immutable reference types) also qualify.

This means the following qualify:

* primitive structs and enums
* observable immutable object subgraphs
* any type composed from the previous

It follows that generic types often conditionally qualify depending on their type arguments.

···

Sent from my iPad

On May 6, 2016, at 11:19 PM, Tyler Fleming Cloutier <cloutiertyler@aol.com> wrote:

On May 6, 2016, at 6:54 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

   On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
   on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 5, 2016, at 10:02 PM, Dave Abrahams >>> <dabrahams@apple.com> wrote:
       on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >>> <dabrahams@apple.com> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson >>> <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev >>> <swift-evolution@swift.org> >>> wrote:

I also assume that enforcing immutability on an object graph, via CoW or otherwise, would be unfeasible. You could enforce it on all values accessible by traversing a single reference for reference types, however.

This is why I don’t really buy the argument that there is no such this as deep vs shallow copy. Deep copy means copying the whole “PureValue” or subgraph, shallow copy means traversing a single reference and copying all accessible values.

       I don’t mean to imply that it is the *only* valuable
       property. However, it I (and many others) do believe it is an extremely
       valuable
       property in many cases. Do you disagree?

   I think I do. What is valuable about such a protocol? What generic
   algorithms could you write that work on models of PureValue but don't
   work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

       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?

It certainly isn’t irrelevant to that point.

   HTH,

       My expectation is a generic aggregate such as Array would have to
       conditionally conform to AnyValue only when Element also conforms to
       AnyValue.

       I’m also wondering how such a rule would be implemented while still
       allowing for CoW structs that *do* implement value semantics, but do
       so while using references internally.

       I am not talking about any kind of statically-enforceable rule, although
       we could probably make warnings sophisticated enough to help with this.

       You said the you have arrived at the opinion that the language should
       “effectively outlaw” structs and enums that do not have value semantics.
       That
       sounded like static enforcement to me.

       The language outlaws certain kinds of inout aliasing without
       providing static enforcement. This is like that.

       I did not know this. Now you have me curious. Can you give an example of
       where
       we are able to violate law? I ask mostly because it sounds like there is
       a
       possibility of stumbling into dangerous territory, possibly without
       being aware
       that you have done so.

       See “In-out Parameters” in
       The Swift Programming Language: Redirect

       Maybe you meant we should allow the compiler to assume value semantics
       for structs and enums despite the fact that it doesn’t statically
       enforce this?

       That would be one *consequence* of effectively outlawing it. The library
       could make similar assumptions.

       If the compiler can be sophisticated enough to verify value semantics
       statically maybe it would be better to have that mechanism be
       triggered by conformance to AnyValue rather than for all structs and
       enums. Types that conform to AnyValue would receive the benefits of
       the compiler knowing they have value semantics, while other uses of
       structs and enums would remain valid. Best practice would be to
       conform structs and enums to AnyValue whenever possible.

       Another possible advantage of this approach would be allowing
       immutable reference types to conform to AnyValue and receive the
       associated benefits such as the generated implementation of equality,
       etc.

       -Matthew

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

       --
       Dave

       --
       Dave

       _______________________________________________
       swift-evolution mailing list
       swift-evolution@swift.org
       https://lists.swift.org/mailman/listinfo/swift-evolution

   --
   Dave

   _______________________________________________
   swift-evolution mailing list
   swift-evolution@swift.org
   https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

        Swift’s collections also accomplish this through copying, but only when
        the
        elements they contain also have the same property.

    Only if you think mutable class instances are part of the value of the
    array that stores references to those class instances. As I said
    earlier, you can *take* that point of view, but why would you want to?
    Today, we have left that question wide open, which makes the whole
    notion of what is a logical value very indistinct. I am proposing to
    close it.

        On the other hand, it is immediately obvious that non-local mutation
        is quite possibly in the elements of a Swift Array<AnyObject> unless
        they are all uniquely referenced.

    If you interpret the elements of the array as being *references* to
    objects, there is no possibility of non-local mutation. If you
    interpret the elements as being objects *themselves*, then you've got
    problems.

This does not make sense, because you’ve got problems either way. You are
arguing, essentially, that everything is a value type because
references/pointers are a value.

I am arguing that every type can be viewed as a value, allowing us to
preserve a sense in which Array<T> has value semantics irrespective of
the details of T.

If that were the case then the *only* valid way to compare the
equality of types would be to compare their values. Overriding the
equality operator would inherently violate the property of
immutability, i.e. two immutable objects can change their equality
even without mutation of their “values".

Not at all. In my world, you can override equality such that it
includes referenced storage when either:

1. the referenced storage will not be mutated
2. or, the referenced storage will only mutated when uniquely-referenced.

func ==(lhs, rhs) {
...
}

class MyClass {
var a: Int
...

}

let x = MyClass(a: 5)
let y = MyClass(a: 5)

x == y // true
y.a = 6
x == y // false

I don't understand what point you're trying to make, here. I see that x
and y are immutable. Notwithstanding the fact that the language tries to
hide the difference between a reference and the instance to which it
refers from the user (the difference would be clearer if you had to
write y->a = 6 as in C, but it's still there), that immutability doesn't
extend beyond the variable binding. The class instance to which y
refers, as you've ably demonstrated, is mutable.

    Are you arguing that reference types should be equatable by default,
    using
    equality of the reference if the type does not provide a custom
    definition of
    equality?

    Yes!!

Custom definitions of equality, inherently, decouple immutability from
equality,

Not a bit. They certainly *can* do that, if we allow it, but I am
proposing to ban that. There are still useful custom definitions of
equality as I have outlined above.

as shown above. Swift makes it appear as though references and values
are on the same level in a way that C does not.

Yep. It's an illusion that breaks down at the edges and can be really
problematic if users fully embrace it. You can't write a generic
algorithm with well-defined semantics that does mutation-by-part on
instances of T without constraining T to have value or reference semantics.

I am not advocating that we require “y->a” for class member access, but
I *am* suggesting that we should accept the fact that reference and
value semantics are fundamentally different and make design choices
(including language rules) accordingly.

let x = MyStruct()
let y = MyClass()

x.myFoo
y.myFoo

vs

my_struct *x = …
my_struct y = …

x.my_foo
y->my_foo

With C it is explicit that you are crossing a reference. Thus there is only
*one* type of equality in C, that the values *are equal*.

Well, C doesn't even *have* struct equality;

This exactly the type of equality you are referring to, but this does
not carry over to Swift for precisely the reason that Swift paves over
the difference between value and reference types, and then allows you
to redefine equality.

Therefore, in essentially no circumstances does it make sense to
compare a type by its reference if it has any associated data in
Swift.

Disagreed. Instances whose *identity* is significant, i.e. basically
everything that actually ought to be a class, can be very usefully
compared by their references. For example, if equality and hashing were
defined for UIViews, based on their references, you could use a
Set<UIView> to keep track of which views had user interaction during a
given time interval.

Basically, if it will be commonplace to override the equality operator
to compare the first level of associated values of a reference type,
then the comparison of just the reference has no business being the
default.

If the default equality for reference types was defined as the equality of the
references it would be inconsistent with the Swift’s current apparent surfacing
of the first level of associated data for reference types.

Yes, but as I've said, that illusion doesn't work in the presence of
mutability.

        I think perhaps what you mean by “purity” is just, “has value
        semantics.” But I could be wrong.

        No, an array storing instances of reference types that are not immutable
        would
        not be “pure” (or whatever you want to call it).

        is derived from deep value semantics. This is when there is no
        possibility of shared mutable state. This is an extremely important
        property.

        It's the wrong property, IMO.

        Wrong in what sense?

        Wrong in the sense that it rules out using things like Array that are
        logically value types but happen to be implemented with CoW, and if you
        have proper encapsulation there's no way for these types to behave as
        anything other than values, so it would be extremely limiting.

        I’m a big fan of CoW as an implementation detail. We have definitely
        been
        miscommunicating if you thought I was suggesting something that would
        prohibit
        CoW.

    Then what, precisely, are the syntactic and semantic requirements of
    “PureValue?”

I assume what is meant by "PureValue", is any object A, whose own references
form a subgraph, within which a change to any of the values would constitute a
change in the value of A (thus impermissible if A is immutable). Thus structs
would quality as “PureValues”.

OK, one vote for that interpretation noted.

I also assume that enforcing immutability on an object graph, via CoW
or otherwise, would be unfeasible.

I presume by “enforcing” you mean, “enforcing by the compiler.” It's
very easy to enforce that for particular object graphs in library code,
using encapsulation.

You could enforce it on all values accessible by traversing a single
reference for reference types, however.

This is why I don’t really buy the argument that there is no such this
as deep vs shallow copy. Deep copy means copying the whole “PureValue”
or subgraph, shallow copy means traversing a single reference and
copying all accessible values.

Well, again, “you can look at the world that way, but why would you want
to?” It makes reasoning about code exponentially more difficult if at
every level you have to ask whether a copy is deep or shallow.

···

on Fri May 06 2016, Tyler Fleming Cloutier <cloutiertyler-AT-aol.com> wrote:

    On May 6, 2016, at 6:54 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:
    on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
        On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:

--
-Dave

I've been thinking about this further and can now state my position more clearly and concisely.

1. If we're going to have reference types with value semantics the boundary of the value must extend through the reference to the value of the object. Two instances may have the same logical value so reference equality is not good enough.

2. Value types are not "pure" values if any part of the aggregate contains a reference whose type does not have value semantics. Purity must include the entire aggregate. Array<UIView> has value semantics but it is not a pure value.

The primary reasons I can think of for creating reference types with value semantics are avoiding copying everything all the time or using inheritance. (I could also list pre-existing types here but am not as concerned with those)

One could argue that you can avoid copying by writing a struct with a handle and one can simulate inheritance by embedding and forwarding. The problem is that this involves a lot of boilerplate and makes your code more complex. For something like the standard library these concerns are far outweighed by the benefit we all gain by having our collections be value types. However, in application code the benefit may not be worth the cost thus it may be reasonable to prefer immutable objects.

I think there is a viable path for enhancing the language such that there is little or not reason to implement a value semantic type as a reference type. If we were able to declare value types as "indirect" and / or have a compiler supported Box (probably with syntactic sugar) that automatically forwarded calls, performed CoW, etc this would allow us much more control over copying without requiring boilerplate. We could also add something along the lines of Go's embedding (or a more general forwarding mechanism which is my preference) which would likely address many of the reasons for using inheritance in a value semantic reference type.

If we do go down that path I think the case that value semantic types should be implemented as value types, thus reference equality should be the default equality for reference types gets much stronger. In that hypothetical future Swift we might even be able to go so far as saying that reference types with value semantics are an anti-pattern and "outlaw" them. This would allow us to simply say "reference types have reference semantics".

We might also be able to get to a place where we can "outlaw" value types that do not have value semantics. I haven't thought deeply about that so I'm not certain of the implications, particularly with regards to C interop. IIRC Dave A indicated he would like to see this happen. If this is possible, we may eventually have a language where "value types have value semantics", "some value types are pure values", and "reference types have reference semantics and are never pure values". If it is achievable it would be a significant step forward in simplicity and clarity.

Matthew

···

Sent from my iPad

On May 7, 2016, at 11:17 AM, Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

On May 7, 2016, at 2:21 AM, Andrew Trick via swift-evolution <swift-evolution@swift.org> wrote:

On May 6, 2016, at 5:48 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

I don’t mean to imply that it is the *only* valuable
property. However, it I (and many others) do believe it is an extremely valuable
property in many cases. Do you disagree?

I think I do. What is valuable about such a protocol? What generic
algorithms could you write that work on models of PureValue but don't
work just as well on Array<Int>?

class Storage {
  var element: Int = 0
}

struct Value {
  var storage: Storage
}

func amIPure(v: Value) -> Int {
  v.storage.element = 3
  return v.storage.element
}

I (the optimizer) want to know if 'amIPure' is a pure function. The developer needs to tell me where the boundaries of the value lie. Does 'storage' lie inside the Value, or outside? If it is inside, then Value is a 'PureValue' and 'amIPure' is a pure function. To enforce that, the developer will need to implement CoW, or we need add some language features.

Thank you for this clear exposition of how PureValue relates to pure functions. This is the exact intuition I have about it but you have stated it much more clearly.

Language features to help automate CoW would be great. It would eliminate boilerplate, but more importantly it would likely provide more information to the compiler.

If I know about every operation inside 'amIPure', and know where the value's boundary is, then I don't really need to know that 'Value' is a 'PureValue'. For example, I know that this function is pure without caring about 'PureValue'.

func IAmPure(v: Value, s: Storage) -> Int {
  var t = v
  t.storage = s
  return t.storage.element
}

However, I might only have summary information. I might know that the function only writes to memory reachable from Value. In that case, it would be nice to have summary information about the storage type. 'PureValue' is another way of saying that it does not contain references to objects outside the value's boundary (I would add that it cannot have a user-defined deinit). The only thing vague about that is that we don't have a general way for the developer to define the value's boundary. It certainly should be consistent with '==', but implementing '==' doesn't tell the optimizer anything.

I think the ability to define the value's boundary would be wonderful. If we added a way to do this it would be a requirement of PureValue.

Anyway, these are only optimizer concerns, and programming model should take precedence in these discussion. But I thought that might help.

-Andy
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my iPad

       Not sure what to think about the enum cases inside a
       protocol (if AnyEnum would
       even exist), it could be a nice addition to the language, but
       this is an own
       proposal I guess.

       We should start by adding AnyValue protocol to which all value
       types
       conforms.

       Having a way to constrain conformance to things with value semantics
       is
       something I've long wanted. *However*, the approach described is too
       simplistic. It's possible to build classes whose instances have
       value
       semantics (just make them immutable) and it's possible to build
       structs
       whose instances have reference semantics (just put the struct's
       storage
       in a mutable class instance that it holds as a property, and don't
       do
       copy-on-write).

       In order for something like AnyValue to have meaning, we need to
       impose
       greater order. After thinking through many approaches over the
       years, I
       have arrived at the (admittedly rather drastic) opinion that the
       language should effectively outlaw the creation of structs and enums
       that don't have value semantics. (I have no problem with the idea
       that
       immutable classes that want to act as values should be wrapped in a
       struct). The language could then do lots of things much more
       intelligently, such as correctly generating implementations of
       equality.

       That is a drastic solution indeed! How would this impact things like
       Array<UIView>? While Array itself has value semantics, the aggregate
       obviously does not as it contains references which usually be mutated
       underneath us.

       Value semantics and mutation can only be measured with respect to
       equality. The definition of == for all class types would be equivalent
       to ===. Problem solved.

       Similar considerations apply to simpler wrapper structs such as Weak.

       Same answer.

       Hmm. If those qualify as “value semantic” then what kind of structs and
       enums
       would not? 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).

       Sure it does.

       public struct Wrap<T: AnyObject> : Equatable {
       init(_ x: T) { self.x = x }
       private x: T
       }

       func == <T>(lhs: Wrap<T>, rhs: Wrap<T>) -> Bool {
       return lhs.x === rhs.x
       }

       I defy you to find any scenario where Wrap<T> doesn't have value
       semantics, whether T is mutable or not.

       Alternately, you can look at the Array implementation. Array is a
       struct wrapping a mutable class. It has value semantics by virtue of
       CoW.

       This goes back to where you draw the line as to the “boundary of the
       value”.
       Wrap and Array are “value semantic” in a shallow sense and are capable
       of deep
       value semantics when T is deeply value semantic.

       No, I'm sorry; this “deep-vs-shallow” thing is a fallacy that comes from
       not understanding the boundaries of your value. Or, put more
       solicitously: sure, you can look at the world that way, but it just
       makes everything prohibitively complicated, so why would you want to?

       In my world, there's no such thing as a “deep copy” or a “shallow copy;”
       there's just “copy,” which logically creates an independent version of
       everything up to the boundaries of the value. Likewise, there's no
       “deep value semantics” or “shallow value semantics.”

       Equality defines
       value semantics, and the boundaries of an Array value always includes
       the values of its elements. The *only* problem here is that we have no
       way to do equality comparison on some arrays because some types aren't
       Equatable. IMO the costs of not having everything be equatable, in
       complexity-of-programming-model terms, are too high.

       Thank you for clarifying the terminology for me. This is helpful.

       I think I may have misunderstood what you meant by “boundary of the
       value”. Do
       you mean that the boundary of an Array value stops at the reference
       identity for
       elements with reference semantics?

   Yes.

       If you have an Array whose elements are of an immutable reference type
       that has value semantics would you say the boundary extends past the
       reference identity of an element and includes a definition of equality
       defined by that type?

   Yes!

       Are you arguing that reference types should be equatable by default,
       using
       equality of the reference if the type does not provide a custom
       definition of
       equality?

   Yes!!

       Both have their place, but the maximum benefit of value semantics
       (purity)

       I don't know what definition of purity you're using. The only one I
       know of applies to functions and implies no side effects. In that
       world, there is no mutation and value semantics is equivalent to
       reference semantics.

       I was using it in the sense of “PureValue” as discussed in this
       thread.

   Sorry, this is the first mention I can find in the whole thread, honest.
   Oh, it was a different thread. Joe describes it as a protocol for
   “types that represent fully self-contained values,” which is just fuzzy
   enough that everyone reading it can have his own interpretation of what
   it means.

       I was using it to mean values for which no *observable* mutation is
       possible (allowing for CoW, etc). Is there a better term for this than
       purity?

   You're still not making any sense to me. A type for which no observable
   mutation is possible is **immutable**. The “write” part of
   copy-on-write is a pretty clear indicator that it's all about
   **mutation**. I don't see how they're compatible.

Sorry, I did not write that very clearly. I should have said no observable
mutation *that happens behind your back*. In other words, the only *observable*
mutation possible is local.

Yeah, but you need to ask the question, “mutation in what?” The answer:
mutation in the value instance. Then you need to ask, “how do you
determine whether there was mutation?”

Immutability accomplishes this by simply prohibiting all
mutation. Primitive value types like Int and structs or enums that
only contain primitive value types accomplish this by getting copied
everywhere.

Swift’s collections also accomplish this through copying, but only when the
elements they contain also have the same property.

Only if you think mutable class instances are part of the value of the
array that stores references to those class instances. As I said
earlier, you can *take* that point of view, but why would you want to?
Today, we have left that question wide open, which makes the whole
notion of what is a logical value very indistinct. I am proposing to
close it.

I think part of the disconnect here might be the domains in which we
work. Maybe you're coming at this primarily from an algorithmic
perspective and I'm coming at it primarily from an app development
perspective.

IMO that's a false distinction. Suggestion: look up the definition of
“algorithm.” Your apps are built out of algorithms. FWIW, I was an app
developer long before I was a library writer. What I discovered, after
many years living with my own software and learning from mistakes, was
that “an algorithmic perspective” is essential to building any piece of
software that you or someone else might have to maintain, that users can
rely on, that doesn't have catastrophic performance problems, etc.

For example, I think it is perfectly reasonable to write a generic
view controller that works with various data types and is initialized
with an Array<T> but only works properly when it isn't possible to
observe any mutation in the subgraph of T.

And my claim is that you have picked a really complicated way of saying
“T has value semantics,” or if there are differences in your intended
constraint, you don't actually care about those differences.

Just taking the nontrivial case where T is a reference type, let's look
at the the phrase “it isn't possible to observe any mutation in the
subgraph of T.” This is still a rather fuzzy notion, but let me try to
nail it down. To me that means, if the behavior of “f” only depends on
data reachable through this array, and f makes no mutations, then in
this code, the two calls to f() are guaranteed have the same effect.

      func g<T>(a: [T]) {
        var vc = MyViewController(a)
        vc.f() // #1
        h()
        vc.f() // #2
     }

But clearly, the only way that can be the case is if T is actually
immutable (and contains no references to mutable data), because
otherwise anybody can write:

    class X { ... }
    let global: = [ X() ]
    func h() { global[0].mutatingMethod() }
    g(global)

Conclusion: your definition of PureValue, as written, implies conforming
reference types must be immutable. I'm not saying that's necessarily
what you meant, but if it isn't, you need to try to define it again.

On the other hand, it is immediately obvious that non-local mutation
is quite possibly in the elements of a Swift Array<AnyObject> unless
they are all uniquely referenced.

If you interpret the elements of the array as being *references* to
objects, there is no possibility of non-local mutation. If you
interpret the elements as being objects *themselves*, then you've got
problems.

In application code we are concerned with the objects, not the
references.

Not necessarily, not at all. A Set<UIView> where you're interested in
the references is totally reasonable.

   I think perhaps what you mean by “purity” is just, “has value
   semantics.” But I could be wrong.

No, an array storing instances of reference types that are not immutable would
not be “pure” (or whatever you want to call it).

       is derived from deep value semantics. This is when there is no
       possibility of shared mutable state. This is an extremely important
       property.

       It's the wrong property, IMO.

       Wrong in what sense?

   Wrong in the sense that it rules out using things like Array that are
   logically value types but happen to be implemented with CoW, and if you
   have proper encapsulation there's no way for these types to behave as
   anything other than values, so it would be extremely limiting.

I’m a big fan of CoW as an implementation detail. We have definitely been
miscommunicating if you thought I was suggesting something that would prohibit
CoW.

Then what, precisely, are the syntactic and semantic requirements of “PureValue?”

I believe it is a purely semantic concept. It means that every name
binding is logically and observably distinct, including and objects in
the aggregate (if it includes references).

That sounds like “value semantics” to me, although I get the sense maybe
you're also adding the restriction that you're *not allowed* to define
the boundary of values as stopping at a reference but not including the
instance it references. IMO that restriction is not actually useful and
probably harmful.

This allows for local mutation on the same binding and also for un
observable mutation such as CoW in the implementation. But it does
not allow for a mutation applied to one name binding having the type
to be observed through another name binding having the type.

It sounds like you're trying to capture some notion of “can't possibly
reach shared mutable state through this instance,” but IMO there's a
false distinction here. Fundamentally, there's no difference between a
reference to an object and an integer that can be used as an index into
a global array that contains a reference to the object, or even an
integer that can be used as an index into a global array that contains
an equivalent struct.

Again, I would like to see some piece of code that *actually depends on
this PureValue property for its correctness*.

       I don’t mean to imply that it is the *only* valuable
       property. However, it I (and many others) do believe it is an extremely
       valuable
       property in many cases. Do you disagree?

   I think I do. What is valuable about such a protocol? What generic
   algorithms could you write that work on models of PureValue but don't
   work just as well on Array<Int>?

Array<Int> provides the semantics I have in mind just fine so there wouldn’t be
any. Array<AnyObject> is a completely different story. With
Array<AnyObject> you cannot rely on a guarantee the objects contained
in the array will not be mutated by code elsewhere that also happens
to have a reference to the same objects.

Okay then, what algorithms can you write that operate on PureValue that
don't work equally well on Array<AnyObject>?

I am not sure. It is possible that it does not apply to purely
algorithmic work. That does not mean it is unimportant.
It is quite valuable in application level code. It think it would be
valuable to reify it with a protocol rather than leaving it to
documentation even if the compiler can't always prove our code meets
this semantic.

For the purposes of library and language design, the ability to produce
use-cases (and solid definitions) is crucial. The ability to show how
it substantively differs from concepts we already have is crucial. If
we can't find these things, it doesn't belong.

If you don't like the name PureValue for this concept lets bike shed.
I only used it because others had already used it. Maybe there is a
better name.

It's not the name that's the problem. I don't even understand what
you're reaching for, or why. Without a demonstration of what this is
for, I'm going to continue to argue against it (though I'm about to be
on vacation so I'll be out of your hair for a week).

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?

I hope my previous comments have helped to clarify this.

I'm afraid not yet.

···

on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

On May 6, 2016, at 8:54 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Fri May 06 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
   On May 6, 2016, at 7:48 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
   on Thu May 05 2016, Matthew Johnson <swift-evolution@swift.org> wrote:
       On May 5, 2016, at 10:02 PM, Dave Abrahams >>> <dabrahams@apple.com> wrote:
       on Thu May 05 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 5, 2016, at 4:59 PM, Dave Abrahams >>> <dabrahams@apple.com> wrote:
       on Wed May 04 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
       On May 4, 2016, at 5:50 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Matthew Johnson >>> <swift-evolution@swift.org> wrote:
       On May 4, 2016, at 1:29 PM, Dave Abrahams via swift-evolution >>> <swift-evolution@swift.org> wrote:
       on Wed May 04 2016, Adrian Zubarev >>> <swift-evolution@swift.org> >>> wrote:

--
-Dave

Whoa; Andy never suggested this would help automate CoW. Are you
suggesting that? How would it work?

···

on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

Sent from my iPad

On May 7, 2016, at 2:21 AM, Andrew Trick via swift-evolution > <swift-evolution@swift.org> wrote:

        On May 6, 2016, at 5:48 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:

                I don’t mean to imply that it is the *only* valuable
            property. However, it I (and many others) do believe it is an
            extremely valuable
            property in many cases. Do you disagree?

        I think I do. What is valuable about such a protocol? What generic
        algorithms could you write that work on models of PureValue but don't
        work just as well on Array<Int>?

    class Storage {
    var element: Int = 0
    }

    struct Value {
    var storage: Storage
    }

    func amIPure(v: Value) -> Int {
    v.storage.element = 3
    return v.storage.element
    }

    I (the optimizer) want to know if 'amIPure' is a pure function. The
    developer needs to tell me where the boundaries of the value lie. Does
    'storage' lie inside the Value, or outside? If it is inside, then Value is a
    'PureValue' and 'amIPure' is a pure function. To enforce that, the developer
    will need to implement CoW, or we need add some language features.

Thank you for this clear exposition of how PureValue relates to pure functions.
This is the exact intuition I have about it but you have stated it much more
clearly.

Language features to help automate CoW would be great. It would eliminate
boilerplate, but more importantly it would likely provide more information to
the compiler.

--
-Dave

This depends on the type. For types representing resources, etc it works just
fine. But for models it does not work unless the model subgraph is entirely
immutable and instances are unique.
I agree that it isn't a good idea to provide a default that will
certainly be wrong in many cases.

Please show an example of a mutable model where such an equality would
be wrong.

    I assume what is meant by "PureValue", is any object A, whose own references
    form a subgraph, within which a change to any of the values would constitute
    a change in the value of A (thus impermissible if A is immutable). Thus
    structs would quality as “PureValues”.

As you noted in a followup, not all structs qualify. Structs that whose members
all qualify will qualify. References to a subgraph that doesn't allow for any
observable mutation (i.e. deeply immutable reference types) also qualify.

This means the following qualify:

* primitive structs and enums
* observable immutable object subgraphs
* any type composed from the previous

It follows that generic types often conditionally qualify depending on their
type arguments.

    I also assume that enforcing immutability on an object graph, via CoW or
    otherwise, would be unfeasible. You could enforce it on all values
    accessible by traversing a single reference for reference types, however.

    This is why I don’t really buy the argument that there is no such this as
    deep vs shallow copy. Deep copy means copying the whole “PureValue” or
    subgraph, shallow copy means traversing a single reference and copying all
    accessible values.

                I don’t mean to imply that it is the *only* valuable
            property. However, it I (and many others) do believe it is an
            extremely
            valuable
            property in many cases. Do you disagree?

            I think I do. What is valuable about such a protocol? What generic
            algorithms could you write that work on models of PureValue but
            don't
            work just as well on Array<Int>?

            Array<Int> provides the semantics I have in mind just fine so there
            wouldn’t be
            any. Array<AnyObject> is a completely different story. With
            Array<AnyObject> you cannot rely on a guarantee the objects
            contained
            in the array will not be mutated by code elsewhere that also happens
            to have a reference to the same objects.

        Okay then, what algorithms can you write that operate on PureValue that
        don't work equally well on Array<AnyObject>?

You haven't answered this question. How would you use this protocol?

            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.

···

on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:

--
-Dave