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


(James F) #1

An AnyValue protocol seems long overdue. I'm not sure how useful AnyEnum would be, though I support the idea since it could become useful in the future.

------------ Begin Message ------------
Group: gmane.comp.lang.swift.evolution
MsgID: <etPan.5728ea0f.6ac6505c.f915@DevAndArtist.fritz.box>

I’d love to see Swift go in this direction with protocols:

···

+-------+
                   > Any |
                   +---+---+
                       >
         +-------------+-------------+
         > >
  +------+-------+ +-----+----+
  > AnyReference | | AnyValue |
  +------+-------+ +-----+----+
         > >
+--------+---------+ ....................................

AnyObject (ObjC) | : Optionally Swift could also have :

+------------------+ : | :
                      : +-------+--------+ :
                      : | | :
                      : +----+----+ +-----+-----+ :
                      : | AnyEnum | | AnyStruct | :
                      : +----+----+ +-----+-----+ :
                      ....................................

--
Adrian Zubarev
Sent with Airmail

Am 3. Mai 2016 bei 18:42:15, Adrian Zubarev via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org) schrieb:

+1 Yes please, get rid of the `class` keyword from protocols already and replace it with better implicit protocols.

I posted the idea two weeks ago, but no one answered to it: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160418/015568.html

Replacing `class` with something like `protocol AnyReference` is the first step to add a few more implicit protocols like `AnyValue` to Swift. We could build value or reference type specific libraries and overload correctly.

--
Adrian Zubarev
Am 2. Mai 2016 um 15:55:15, David Sweeris via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org) schrieb:

I was just thinking that:
protocol Foo : reference {}
might be more to the point than:
protocol Foo : class {}

I know that it’s currently a moot point because classes are the only* reference-semantics type of type in Swift, but it’s conceivable that there might some day be others. Anyway, I’m not saying it’s a big deal or anything, I’m just trying to think of any source-breaking changes we might want to make before Swift 3 drops, and this seems like an easy one.

- Dave Sweeris

* I’m not actually sure this is true. I have a very vague recollection about some protocols getting reference semantics in certain circumstances, but the memory is so hazy I’m not sure I trust it. Also I can’t remember if the “indirect” keyword in enums affects the semantics.
_______________________________________________
swift-evolution mailing list
swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org
https://lists.swift.org/mailman/listinfo/swift-evolution

------------- End Message -------------

From James F


Memory initialization and deinitialization best practices
(James F) #2

I was thinking that requiring instance properties would mean the value could only be a struct, but rethinking, I realise computed properties would work fine for protocol conformance, so this isn't actually true.

I agree with your support of focusing on interface. Your implications for AnyObject and AnyValue are interesting - that reference-type and value-type semantics are a kind of interface…

One thing occurs to me, thinking about this: what if protocols could require enum cases? This could allow a Failable protocol with .failure(ErrorType), for example; or Nillable, which could implement NilLiteralConvertible for enums with a .none case… I'm not sure, maybe this wouldn't be so useful in practice?

From James F

···

On 4 May 2016, at 01:01, Patrick Smith <pgwsmith@gmail.com> wrote:

I can see the benefit for AnyValue, however I think AnyEnum and AnyStruct would be misused.

A protocol intended for an enum could be used by a struct that uses an inner enum, for example. If every case had a UUID, then it would be easier to have that a property in a struct, and have the unique associated values for each case in an enum stored in a separate property.

Protocols are fantastic I think because they focus on the interface, not the implementation.

Better to conform to RawRepresentable (which can be an enum or a struct), or some other protocol.

Patrick Smith

On May 4 2016, at 7:16 am, James Froggatt via swift-evolution <swift-evolution@swift.org> wrote:
An AnyValue protocol seems long overdue. I'm not sure how useful AnyEnum would be, though I support the idea since it could become useful in the future.

------------ Begin Message ------------
Group: gmane.comp.lang.swift.evolution
MsgID: <etPan.5728ea0f.6ac6505c.f915@DevAndArtist.fritz.box>

I’d love to see Swift go in this direction with protocols:

                   +-------+
                   > Any |
                   +---+---+
                       >
         +-------------+-------------+
         > >
  +------+-------+ +-----+----+
  > AnyReference | | AnyValue |
  +------+-------+ +-----+----+
         > >
+--------+---------+ ....................................
> AnyObject (ObjC) | : Optionally Swift could also have :
+------------------+ : | :
                      : +-------+--------+ :
                      : | | :
                      : +----+----+ +-----+-----+ :
                      : | AnyEnum | | AnyStruct | :
                      : +----+----+ +-----+-----+ :
                      ....................................

--
Adrian Zubarev
Sent with Airmail

Am 3. Mai 2016 bei 18:42:15, Adrian Zubarev via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org) schrieb:

+1 Yes please, get rid of the `class` keyword from protocols already and replace it with better implicit protocols.

I posted the idea two weeks ago, but no one answered to it: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160418/015568.html

Replacing `class` with something like `protocol AnyReference` is the first step to add a few more implicit protocols like `AnyValue` to Swift. We could build value or reference type specific libraries and overload correctly.

--
Adrian Zubarev
Am 2. Mai 2016 um 15:55:15, David Sweeris via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org) schrieb:

I was just thinking that:
protocol Foo : reference {}
might be more to the point than:
protocol Foo : class {}

I know that it’s currently a moot point because classes are the only* reference-semantics type of type in Swift, but it’s conceivable that there might some day be others. Anyway, I’m not saying it’s a big deal or anything, I’m just trying to think of any source-breaking changes we might want to make before Swift 3 drops, and this seems like an easy one.

- Dave Sweeris

* I’m not actually sure this is true. I have a very vague recollection about some protocols getting reference semantics in certain circumstances, but the memory is so hazy I’m not sure I trust it. Also I can’t remember if the “indirect” keyword in enums affects the semantics.
_______________________________________________
swift-evolution mailing list
swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org
https://lists.swift.org/mailman/listinfo/swift-evolution

------------- End Message -------------

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


(Patrick Smith) #3

I was thinking that requiring instance properties would mean the value could only be a struct, but rethinking, I realise computed properties would work fine for protocol conformance, so this isn’t actually true.

I agree with your support of focusing on interface. Your implications for AnyObject and AnyValue are interesting - that reference-type and value-type semantics are a kind of interface…

One thing occurs to me, thinking about this: what if protocols could require enum cases? This could allow a Failable protocol with .failure(ErrorType), for example; or Nillable, which could implement NilLiteralConvertible for enums with a .none case… I’m not sure, maybe this wouldn’t be so useful in practice?

Basically you are asking to initialize with something, and not read from it later. So better to just have a:

init(error: ErrorType)

I think. And use NilLiteralConvertible!

Enums are tightly coupled to their structure, and I imagine compile down to some sort of bit offset, so you can’t really have a generic .failure case that would work with all enums, as they will be at different offsets in the enum.

From James F

Patrick Smith

···

On May 4 2016, at 5:37 pm, James Froggatt conductator@ntlworld.com wrote:


(Adrian Zubarev) #4

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.

The reason I introduced AnyReference is to distinguish Swift and ObjC classes. The problem with AnyObject is AFAICS that it will bridge the type if possible. I think if you pass a String for AnyObject the type will be bridged to NSString, correct me if I'm wrong. This is what I dislike about the current AnyObject protocol.

Some examples:

protocol A: AnyReference {} // Swift clases == protocol A: class {}

protocol B: AnyValue {} // for all value types; new to the language

protocol C: AnyObject // ObjC classes == protocol C: class {} right now not restricted to ObjC classes

···

--
Adrian Zubarev

Am 4. Mai 2016 um 09:37:29, James Froggatt via swift-evolution (swift-evolution@swift.org(mailto:swift-evolution@swift.org)) schrieb:

I was thinking that requiring instance properties would mean the value could only be a struct, but rethinking, I realise computed properties would work fine for protocol conformance, so this isn't actually true.

I agree with your support of focusing on interface. Your implications for AnyObject and AnyValue are interesting - that reference-type and value-type semantics are a kind of interface…

One thing occurs to me, thinking about this: what if protocols could require enum cases? This could allow a Failable protocol with .failure(ErrorType), for example; or Nillable, which could implement NilLiteralConvertible for enums with a .none case… I'm not sure, maybe this wouldn't be so useful in practice?

From James F

On 4 May 2016, at 01:01, Patrick Smith <pgwsmith@gmail.com(mailto:pgwsmith@gmail.com)> wrote:

> I can see the benefit for AnyValue, however I think AnyEnum and AnyStruct would be misused.
>
> A protocol intended for an enum could be used by a struct that uses an inner enum, for example. If every case had a UUID, then it would be easier to have that a property in a struct, and have the unique associated values for each case in an enum stored in a separate property.
>
> Protocols are fantastic I think because they focus on the interface, not the implementation.
>
> Better to conform to RawRepresentable (which can be an enum or a struct), or some other protocol.
> Patrick Smith
> On May 4 2016, at 7:16 am, James Froggatt via swift-evolution <swift-evolution@swift.org(mailto:swift-evolution@swift.org)> wrote:
> >
> > An AnyValue protocol seems long overdue. I'm not sure how useful AnyEnum would be, though I support the idea since it could become useful in the future.
> >
> >
> > ------------ Begin Message ------------
> > Group: gmane.comp.lang.swift.evolution
> > MsgID: <etPan.5728ea0f.6ac6505c.f915@DevAndArtist.fritz.box(mailto:etPan.5728ea0f.6ac6505c.f915@devandartist.fritz.box)>
> >
> >
> > I’d love to see Swift go in this direction with protocols:
> >
> >
> > +-------+
> > > Any |
> > +---+---+
> > >
> > +-------------+-------------+
> > > >
> > +------+-------+ +-----+----+
> > > AnyReference | | AnyValue |
> > +------+-------+ +-----+----+
> > > >
> > +--------+---------+ ....................................
> > > AnyObject (ObjC) | : Optionally Swift could also have :
> > +------------------+ : | :
> > : +-------+--------+ :
> > : | | :
> > : +----+----+ +-----+-----+ :
> > : | AnyEnum | | AnyStruct | :
> > : +----+----+ +-----+-----+ :
> > ....................................
> >
> >
> > --
> > Adrian Zubarev
> > Sent with Airmail
> >
> >
> > Am 3. Mai 2016 bei 18:42:15, Adrian Zubarev via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org(mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org)) schrieb:
> >
> >
> > +1 Yes please, get rid of the `class` keyword from protocols already and replace it with better implicit protocols.
> >
> >
> > I posted the idea two weeks ago, but no one answered to it: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160418/015568.html
> >
> >
> > Replacing `class` with something like `protocol AnyReference` is the first step to add a few more implicit protocols like `AnyValue` to Swift. We could build value or reference type specific libraries and overload correctly.
> >
> >
> > --
> > Adrian Zubarev
> > Am 2. Mai 2016 um 15:55:15, David Sweeris via swift-evolution (swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org(mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org)) schrieb:
> >
> >
> > I was just thinking that:
> > protocol Foo : reference {}
> > might be more to the point than:
> > protocol Foo : class {}
> >
> >
> > I know that it’s currently a moot point because classes are the only* reference-semantics type of type in Swift, but it’s conceivable that there might some day be others. Anyway, I’m not saying it’s a big deal or anything, I’m just trying to think of any source-breaking changes we might want to make before Swift 3 drops, and this seems like an easy one.
> >
> >
> > - Dave Sweeris
> >
> >
> > * I’m not actually sure this is true. I have a very vague recollection about some protocols getting reference semantics in certain circumstances, but the memory is so hazy I’m not sure I trust it. Also I can’t remember if the “indirect” keyword in enums affects the semantics.
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org(mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org(mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> >
> >
> >
> >
> > ------------- End Message -------------
> >
> >
> >
> >
> >
> > From James F
> > _______________________________________________
> > 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
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #5

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.

···

on Wed May 04 2016, Adrian Zubarev <swift-evolution@swift.org> 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.

--
Dave


(Matthew Johnson) #6

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. Similar considerations apply to simpler wrapper structs such as Weak.

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.

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

···

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

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


(David Sweeris) #7

You mean that a struct's properties would have to have value semantics, too? I think I'm okay with that, especially if it's done through new types of structs/enums.

- Dave Sweeris.

···

On May 4, 2016, at 13:29, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

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.


(Dave Abrahams) #8

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.

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.

···

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:

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


(Adrian Zubarev) #9

I kinda feel my idea went into the wrong direction.

By introducing these implicit protocols (formatted with Source Code Pro font) I didn’t meant them to force a type to have only reference or value semantics.

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

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

AnyObject (ObjC) | : Optionally Swift could also have :

+------------------+ : | :
: +-------+--------+ :
: | | :
: +----+----+ +-----+-----+ :
: | AnyEnum | | AnyStruct | :
: +----+----+ +-----+-----+ :
....................................

Array<UIView> is a great example that `AnyValue` should not restrict your type to contain only value types.

The main idea behind these implicit protocols was the ability to create protocols which only can be applied to a specific type (class, struct or enum, maybe tuples one day) or to distinguish between types.

Here are some simple examples:

protocol MagicValueType: AnyValue {}
extension MagicValueType {

  func expectoPatronum\(\) \{ /\* do some amazing magic \*/ \}
  func getMeAView\(\) \-&gt; UIView \{ return UIView\(\) \} 
  // AnyValue should not forbid value types to work with reference types

}

class A {}
struct B {}

extension A: MagicValueType {} // this should NOT work and produce an error, because MagicValueType is restricted to value types only
extension B: MagicValueType {} // wow we extended our type with an value type protocol (this is new to the language)

Same rules goes to the `AnyReference`.

We already can do something like this:

protocol SomeReferenceProtocol: class {} // restricted to classes only
extension SomeReferenceProtocol {

 func foo\(\) \-&gt; B \{ return B\(\) \} // we can work with value or reference types as we pleased

}

extension A: SomeReferenceProtocol {} // works as expected
extension B: SomeReferenceProtocol {} // this already produces an error which is the way it should work

I’d be great if we change the `class` keyword to `AnyReference` (not @objc protocol AnyObject {} as explained before).

protocol SomeReferenceProtocol: AnyReference {}

Any value type except buildin types (Tuples can’t be extended at the moment anyways) should implicitly conform to AnyValue and any Swift classes should implicitly conform to AnyReference. All ObjC classes should conform to AnyObject.

If these protocols would exist we could use them to overload correctly (an abstract example I used in my post two weeks ago):
func mutate<T: AnyValue>(value: T, scope: @noescape (value: inout T) -> Void) -> T {
      
var mutableValue = value
scope(value: &mutableValue)
return mutableValue
}

func mutate<T: AnyReference>(value: T, scope: @noescape (value: T) -> Void) -> T {
      
scope(value: value)
return value
}
The first `mutate` function will be called if you pass any class to it, including ObjC classes. And finally the second `mutate` function is only called when there is a value type (struct, enum).
I don’t want to restrict the semantics of a type with implicit protocol, but just to constrain protocols if there is a need and correctly detect reference vs. value types.
We could go even further and allow mixing of implicit protocols:
protocol Cocktail: AnyReference, AnyValue {}
this would be equivalent to:
protocol Cocktail: Any {}
or just:
protocol Cocktail {}
Complex restriction might also be possible for whatever desire:
protocol Burger: AnyObject, AnyStruct {}
extension UIView: Burger{} and extension B: Burger {} should work.
I home my English was enough to clarify my idea.
--
Adrian Zubarev
Sent with Airmail

Am 4. Mai 2016 bei 20:46:40, Matthew Johnson via swift-evolution (swift-evolution@swift.org) schrieb:

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:

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. Similar considerations apply to simpler wrapper structs such as Weak.

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.

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 Abrahams) #10

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.

You mean that a struct's properties would have to have value
semantics, too?

Either that, or you'd have to implement CoW, or you'd not use the
storage behind any properties that were references in a way that affects
value semantics.

I think I'm okay with that, especially if it's done through new types
of structs/enums.

New types of structs/enums? What does that mean?

···

on Wed May 04 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

On May 4, 2016, at 13:29, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

--
Dave


(Matthew Johnson) #11

I kinda feel my idea went into the wrong direction.

By introducing these implicit protocols (formatted with Source Code Pro font) I didn’t meant them to force a type to have only reference or value semantics.

                   +-------+
                   > Any |
                   +---+---+
                       >
         +-------------+-------------+
         > >
  +------+-------+ +-----+----+
  > AnyReference | | AnyValue |
  +------+-------+ +-----+----+
         > >
+--------+---------+ ....................................
> AnyObject (ObjC) | : Optionally Swift could also have :
+------------------+ : | :
                      : +-------+--------+ :
                      : | | :
                      : +----+----+ +-----+-----+ :
                      : | AnyEnum | | AnyStruct | :
                      : +----+----+ +-----+-----+ :
                      ....................................

Array<UIView> is a great example that `AnyValue` should not restrict your type to contain only value types.

The main idea behind these implicit protocols was the ability to create protocols which only can be applied to a specific type (class, struct or enum, maybe tuples one day) or to distinguish between types.

And the point others have made is that the value in this is less than it might seem at first glance. Semantic clarity in generic code requires protocols to have semantics attached to them.

Here are some simple examples:

protocol MagicValueType: AnyValue {}
extension MagicValueType {

      func expectoPatronum() { /* do some amazing magic */ }
      func getMeAView() -> UIView { return UIView() }
      // AnyValue should not forbid value types to work with reference types
}

class A {}
struct B {}

extension A: MagicValueType {} // this should NOT work and produce an error, because MagicValueType is restricted to value types only
extension B: MagicValueType {} // wow we extended our type with an value type protocol (this is new to the language)

Same rules goes to the `AnyReference`.

We already can do something like this:

protocol SomeReferenceProtocol: class {} // restricted to classes only
extension SomeReferenceProtocol {

     func foo() -> B { return B() } // we can work with value or reference types as we pleased
}

extension A: SomeReferenceProtocol {} // works as expected
extension B: SomeReferenceProtocol {} // this already produces an error which is the way it should work

I’d be great if we change the `class` keyword to `AnyReference` (not @objc protocol AnyObject {} as explained before).

protocol SomeReferenceProtocol: AnyReference {}

Any value type except buildin types (Tuples can’t be extended at the moment anyways) should implicitly conform to AnyValue and any Swift classes should implicitly conform to AnyReference. All ObjC classes should conform to AnyObject.

If these protocols would exist we could use them to overload correctly (an abstract example I used in my post two weeks ago):
func mutate<T: AnyValue>(value: T, scope: @noescape (value: inout T) -> Void) -> T {
      
    var mutableValue = value
    scope(value: &mutableValue)
    return mutableValue
}

func mutate<T: AnyReference>(value: T, scope: @noescape (value: T) -> Void) -> T {
      
    scope(value: value)
    return value
}
The first `mutate` function will be called if you pass any class to it, including ObjC classes. And finally the second `mutate` function is only called when there is a value type (struct, enum).

You have “first” and “second” backwards here.

I really like that you bring up this example. Ideally two overloads would not be necessary here. I haven’t thought deeply about whether a solution enabling a single implementation is possible and if so what it might look like. If there is a solution it would be much more elegant than requiring the overloads.

I don’t want to restrict the semantics of a type with implicit protocol, but just to constrain protocols if there is a need and correctly detect reference vs. value types.
We could go even further and allow mixing of implicit protocols:
protocol Cocktail: AnyReference, AnyValue {}
this would be equivalent to:
protocol Cocktail: Any {}
or just:
protocol Cocktail {}

No, this under your suggestion this would require conforming types to conform to both AnyReference and AnyValue which would be impossible given your definitions.

Complex restriction might also be possible for whatever desire:
protocol Burger: AnyObject, AnyStruct {}
extension UIView: Burger{} and extension B: Burger {} should work.

This would be a compiler error as UIView clearly would not conform to AnyStruct.

···

On May 4, 2016, at 2:31 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

I home my English was enough to clarify my idea.
--
Adrian Zubarev
Sent with Airmail

Am 4. Mai 2016 bei 20:46:40, Matthew Johnson via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

> 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:
>
>> 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. Similar considerations apply to simpler wrapper structs such as Weak.

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.

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 <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


(Matthew Johnson) #12

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).

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. 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?

···

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 <mailto: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:

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 <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


(David Sweeris) #13

I meant leave `struct` and `enum` the way they are, and introduce a `different_struct` and `different_enum` (placeholder names, of course) which enforced the “no reference-semantics” rules.

I’m inclined to think we should adopt your “no reference-semantics” rule, but I’m not entirely sure what the impact would be. Adding new types side-steps the issue, at the cost of increasing the complexity of the language/compiler. I’m unsure if that'd be a worth-while trade-off.

- Dave Sweeris

···

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

on Wed May 04 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

On May 4, 2016, at 13:29, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

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.

You mean that a struct's properties would have to have value
semantics, too?

Either that, or you'd have to implement CoW, or you'd not use the
storage behind any properties that were references in a way that affects
value semantics.

I think I'm okay with that, especially if it's done through new types
of structs/enums.

New types of structs/enums? What does that mean?


(Tyler Cloutier) #14

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.

Hmm, I get the feeling that I was arguing your own point back at you. Sorry, Dave, I’m a little slow. :slight_smile:

Still, how would you generate an equality operator for a data structure that requires wrapper classes currently, like a LinkedList?

···

On May 4, 2016, at 3:50 PM, Dave Abrahams via swift-evolution <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> wrote:
on Wed May 04 2016, Adrian Zubarev <swift-evolution@swift.org> wrote:

Similar considerations apply to simpler wrapper structs such as Weak.

Same answer.

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.

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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Dave Abrahams) #15

                    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.

        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.

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.

···

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:

        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 Abrahams) #16

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.

You mean that a struct's properties would have to have value
semantics, too?

Either that, or you'd have to implement CoW, or you'd not use the
storage behind any properties that were references in a way that affects
value semantics.

I think I'm okay with that, especially if it's done through new types
of structs/enums.

New types of structs/enums? What does that mean?

I meant leave `struct` and `enum` the way they are, and introduce a
`different_struct` and `different_enum` (placeholder names, of course)
which enforced the “no reference-semantics” rules.

I would be pretty strongly opposed to that. That's almost the opposite
of what I'm proposing.

I’m inclined to think we should adopt your “no reference-semantics”
rule, but I’m not entirely sure what the impact would be. Adding new
types side-steps the issue, at the cost of increasing the complexity
of the language/compiler. I’m unsure if that'd be a worth-while
trade-off.

The whole point of my proposal is to simplify the model.

···

on Thu May 05 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

On May 5, 2016, at 5:01 PM, Dave Abrahams <dabrahams@apple.com> wrote:
on Wed May 04 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

On May 4, 2016, at 13:29, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

--
Dave


(David Sweeris) #17

Oh, ok… I think I got your ends and your means backwards in my head.

- Dave Sweeris

···

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

on Thu May 05 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

I meant leave `struct` and `enum` the way they are, and introduce a
`different_struct` and `different_enum` (placeholder names, of course)
which enforced the “no reference-semantics” rules.

I would be pretty strongly opposed to that. That's almost the opposite
of what I'm proposing.

I’m inclined to think we should adopt your “no reference-semantics”
rule, but I’m not entirely sure what the impact would be. Adding new
types side-steps the issue, at the cost of increasing the complexity
of the language/compiler. I’m unsure if that'd be a worth-while
trade-off.

The whole point of my proposal is to simplify the model.


(Dave Abrahams) #18

I don't think I understand the question. Maybe you should show me the
specific LinkedList you're interested in. When you say “generate,” do
you mean automatically?

FWIWs:

1. I don't intend to make every == operator automatically-generated

2. A LinkedList can be defined using enums and no classes

3. Though it can be done, I am of the opinion that linked lists usually
   make poor value types.

···

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

        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.

Hmm, I get the feeling that I was arguing your own point back at you. Sorry,
Dave, I’m a little slow. :slight_smile:

Still, how would you generate an equality operator for a data structure that
requires wrapper classes currently, like a LinkedList?

--
-Dave


(Matthew Johnson) #19

                   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. Both have their place, but the maximum benefit of value semantics (purity) is derived from deep value semantics. This is when there is no possibility of shared mutable state. This is an extremely important property.

let t = MyClass()
foo.acceptWrapped(Wrap(t))
t.mutate()

In this example, foo had better not depend on the wrapped instance not getting mutated.

       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.

···

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 <http://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:

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 Abrahams) #20

        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.

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

···

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:

        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