ability to derive a class from a struct or other value type


(Mike Kluev) #1

This would be a bit counter-intutivie in my opinion, and it’s already

possible

with the language today. First of all, structs in Swift cannot be built

upon.

Rather, I believe the intention is to use protocols for such a task.

That’s what

the new Swift String and Substring structs do. The following code example
demonstrates the intended behavior, without any additional language

improvements.

protocol Foo {
    func a() -> Any?
}

extension Foo {
    func a() -> Any? {
        return nil
    }
}

struct ValueSemantics: Foo {}

class ReferenceSemantics: Foo {}

while you can use protocols, and protocol extensions specifically, to share
implementation there are two obvious problems with this "workaround":

1) protocol extensions' based implementation is very limited as you have no
storage around. e.g. start with a normal struct method that accesses an
instant variable and try to refactor it into a protocol extension... in
other words try doing anything useful other than "return nil" above,
anything that requires instance variable access. you'll have to be creative
in your protocol implementation, e.g. have a "var storage { get set }" as
part of the protocol and implement that "var storage" inside your struct
(and class), and in case of "struct" it would be strange as the struct
itself is (already) the storage, so you would introduce another level of
indirection for no good reason other than to satisfy this workaround, which
is not nice to begin with and has to be thought upfront (see below)

2) the proposed method works with value types that are already available
(e.g. the OS structs or third party ones) - something you can not change
but still want to wrap into a reference type.

this proposal is purely a syntactic sugar if you will... imagine a value
type "S" that you didn't create that has two hundred methods in it. of
course you can:

class C /* : S */ {

// implement manually:
  var `struct`: S

  // manually put two hundred pass through methods here...

  func method1() {
      `struct`.method1()
  }
  // ...
}

it would be just painful. but the semantic of the proposed solution is
exactly the same, so any question "how it will do this" or "how it will
behave in regards to that" can be immediately answered by looking at the
equivalent "manual" implementation, so no hidden surprises here.

Mike

···

On Wed, 21 Jun 2017 15:04:46 David Moore <mooredev at me.com> wrote:


(Tony Allevato) #2

There's been talk about "protocol forwarding" that I think would achieve a
lot of these goals, without the sharp edges involved trying to define
inheritance between a class and a struct. The proposed feature would
eliminate the boilerplate you're talking about.

I'm on my phone so I can't pull up links to old discussions, but Matthew
Johnson is who was pushing it so you may want to look back at what he's
said on the topic.

···

On Thu, Jun 22, 2017 at 2:28 PM Mike Kluev via swift-evolution < swift-evolution@swift.org> wrote:

On Wed, 21 Jun 2017 15:04:46 David Moore <mooredev at me.com> wrote:

> This would be a bit counter-intutivie in my opinion, and it’s already
possible
> with the language today. First of all, structs in Swift cannot be built
upon.
> Rather, I believe the intention is to use protocols for such a task.
That’s what
> the new Swift String and Substring structs do. The following code
example
> demonstrates the intended behavior, without any additional language
improvements.
>
> protocol Foo {
> func a() -> Any?
> }
>
> extension Foo {
> func a() -> Any? {
> return nil
> }
> }
>
> struct ValueSemantics: Foo {}
>
> class ReferenceSemantics: Foo {}

while you can use protocols, and protocol extensions specifically, to
share implementation there are two obvious problems with this "workaround":

1) protocol extensions' based implementation is very limited as you have
no storage around. e.g. start with a normal struct method that accesses an
instant variable and try to refactor it into a protocol extension... in
other words try doing anything useful other than "return nil" above,
anything that requires instance variable access. you'll have to be creative
in your protocol implementation, e.g. have a "var storage { get set }" as
part of the protocol and implement that "var storage" inside your struct
(and class), and in case of "struct" it would be strange as the struct
itself is (already) the storage, so you would introduce another level of
indirection for no good reason other than to satisfy this workaround, which
is not nice to begin with and has to be thought upfront (see below)

2) the proposed method works with value types that are already available
(e.g. the OS structs or third party ones) - something you can not change
but still want to wrap into a reference type.

this proposal is purely a syntactic sugar if you will... imagine a value
type "S" that you didn't create that has two hundred methods in it. of
course you can:

class C /* : S */ {

// implement manually:
  var `struct`: S

  // manually put two hundred pass through methods here...

  func method1() {
      `struct`.method1()
  }
  // ...
}

it would be just painful. but the semantic of the proposed solution is
exactly the same, so any question "how it will do this" or "how it will
behave in regards to that" can be immediately answered by looking at the
equivalent "manual" implementation, so no hidden surprises here.

Mike

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


(Mike Kluev) #3

thanks, i skimmed through it now and will have a closer look later.
does it address (2) though? (preexisting value types we can't change)

as to the sharp edges: i do not see a single one in the "manual"
implementation of this approach and the idea of this proposal is that it is
equivalent to the manual implementation...

Mike

···

On 23 June 2017 at 02:43, Tony Allevato <tony.allevato at gmail.com <tony.allevato@gmail.com>> wrote:

There's been talk about "protocol forwarding" that I think would achieve a
lot of these goals, without the sharp edges involved trying to define
inheritance between a class and a struct. The proposed feature would
eliminate the boilerplate you're talking about.

I'm on my phone so I can't pull up links to old discussions, but Matthew
Johnson is who was pushing it so you may want to look back at what he's
said on the topic.


(Haravikk) #4

> This would be a bit counter-intutivie in my opinion, and it’s already possible
> with the language today. First of all, structs in Swift cannot be built upon.
> Rather, I believe the intention is to use protocols for such a task. That’s what
> the new Swift String and Substring structs do. The following code example
> demonstrates the intended behavior, without any additional language improvements.
>
> protocol Foo {
> func a() -> Any?
> }
>
> extension Foo {
> func a() -> Any? {
> return nil
> }
> }
>
> struct ValueSemantics: Foo {}
>
> class ReferenceSemantics: Foo {}

while you can use protocols, and protocol extensions specifically, to share implementation there are two obvious problems with this "workaround":

1) protocol extensions' based implementation is very limited as you have no storage around. e.g. start with a normal struct method that accesses an instant variable and try to refactor it into a protocol extension... in other words try doing anything useful other than "return nil" above, anything that requires instance variable access. you'll have to be creative in your protocol implementation, e.g. have a "var storage { get set }" as part of the protocol and implement that "var storage" inside your struct (and class), and in case of "struct" it would be strange as the struct itself is (already) the storage, so you would introduce another level of indirection for no good reason other than to satisfy this workaround, which is not nice to begin with and has to be thought upfront (see below)

Not sure what you mean by added indirection here, the following seems perfectly straightforward to me:

  protocol Foo {
    var someValue:Int { get set }
    func a() -> Any?
  }

  extension Foo {
    func a() -> Any? { return self.someValue }
  }

  struct ValueSemantics:Foo { var someValue:Int }
  class ReferenceSemantics:Foo {
    var someValue:Int { return nil }
  }

There is no added access overhead here, the only difference is that the protocol itself leaves it up to implementations whether someValue is stored or computed.

2) the proposed method works with value types that are already available (e.g. the OS structs or third party ones) - something you can not change but still want to wrap into a reference type.

This sounds to me more like delegation support that's required, which is something that I would like to see for reducing boilerplate. But I'd prefer to see something like:

  struct Foo:SomeProtocol { var someValue:Int }
  class Bar:SomeProtocol, SomeOtherProtocol {
    var foo:Foo implements SomeProtocol, SomeOtherProtocol.someMethod
      // Implements all of SomeProtocol, some of SomeOtherProtocol
  }

Note that's not a specific proposal for syntax, the important point here is that I'm explicitly linking my stored property foo to implementation of a protocol, telling the compiler to automatically use foo's properties/methods to conform to SomeProtocol by default (but leaving me free to customise).

I don't think that masking the behaviour behind something that looks like extension is a good idea, for this reason I prefer explicit delegation. But like I say, I'm not 100% on my preferred syntax for it, I just think it should be its own, distinct feature rather than potentially fooling people into thinking they're extending a struct.

···

On 22 Jun 2017, at 22:28, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:
On Wed, 21 Jun 2017 15:04:46 David Moore <mooredev at me.com <http://me.com/>> wrote:


(Mike Kluev) #5

Not sure what you mean by added indirection here, the following seems

perfectly straightforward to me:

protocol Foo {
var someValue:Int { get set }
func a() -> Any?
}

extension Foo {
func a() -> Any? { return self.someValue }
}

struct ValueSemantics:Foo { var someValue:Int }
class ReferenceSemantics:Foo {
var someValue:Int { return nil }
}

There is no added access overhead here, the only difference is that the

protocol itself leaves it up to

implementations whether someValue is stored or computed.

in real cases there would be more variables:

//============
protocol P1 { // #noise
    var var1: Int { get set } // #noise
    var var2: Int { get set } // #noise
    // ... // #noise x 100
    var var100: Int { get set } // #noise

    func foo1() -> Int // #noise
    func foo2() -> Int // #noise
    // ... // #noise x 100
    func foo100() -> Int // #noise
}

extension P1 { // #noise
    func foo1() -> Int { return var1 * 2 }
    func foo2() -> Int { return var2 * 2 }
    // ...
    func foo100() -> Int { return var100 * 2 }
}

struct S1: P1 {
    var var1: Int // #noise
    var var2: Int // #noise
    // ... // #noise x 100
    var var100: Int // #noise
}

class C1: P1 {
    var var1: Int = 0 // #noise
    var var2: Int = 0 // #noise
    // ... // #noise x 100
    var var100: Int = 0 // #noise
}
//============

lots of noise and violations of DRY. you may try to mitigate it by putting
all those storage into another struct, that was the indirection i was
thinking about:

//============
struct Pimpl { // #noise
    var var1: Int = 0
    var var2: Int = 0
    // ...
    var var100: Int = 0

    func foo1() -> Int { return var1 * 2 }
    func foo2() -> Int { return var2 * 2 }
    // ...
    func foo100() -> Int { return var100 * 2 }
}

protocol P2 { // #noise
    var pimpl: Pimpl { get set } // #noise

    func foo1() -> Int // #noise
    func foo2() -> Int // #noise
    // ... // #noise x 100
    func foo100() -> Int // #noise
}

extension P2 { // #noise
    func foo1() -> Int { return pimpl.var1 * 2 } // #indirection
    func foo2() -> Int { return pimpl.var2 * 2 } // #indirection
    // ... // #indirection x
100
    func foo100() -> Int { return pimpl.var100 * 2 } // #indirection
}

struct S2: P2 {
    var pimpl: Pimpl // #noise

    init() {
        pimpl = Pimpl() // #noise
    }
}

class C2: P2 {
    var pimpl: Pimpl // #noise

    init() {
        pimpl = Pimpl() // #noise
    }
}
//============

while the proposed solution has minimal amount of noise:

//============
struct S3 {
    var var1: Int
    var var2: Int
    // ...
    var var100: Int

    func foo1() -> Int { return var1 * 2 }
    func foo2() -> Int { return var2 * 2 }
    // ...
    func foo100() -> Int { return var100 * 2 }
}

class C3: S3 {
}
// ===========

Mike

···

on Fri Jun 23 05:26:11 CDT 2017 Haravikk swift-evolution at haravikk.me wrote:


(Jay) #6

What you're really after isn't "inheriting" from structs, you want to
easily "compose" your classes (or structs) using the implementation from
other implementation structs (components). I made a separate post all about
this - how to make composition part of the language.

···

On Fri, 23 Jun 2017 at 01:15 Mike Kluev via swift-evolution < swift-evolution@swift.org> wrote:

On 23 June 2017 at 02:43, Tony Allevato <tony.allevato at gmail.com > <tony.allevato@gmail.com>> wrote:

There's been talk about "protocol forwarding" that I think would achieve
a lot of these goals, without the sharp edges involved trying to define
inheritance between a class and a struct. The proposed feature would
eliminate the boilerplate you're talking about.

I'm on my phone so I can't pull up links to old discussions, but Matthew
Johnson is who was pushing it so you may want to look back at what he's
said on the topic.

thanks, i skimmed through it now and will have a closer look later.
does it address (2) though? (preexisting value types we can't change)

as to the sharp edges: i do not see a single one in the "manual"
implementation of this approach and the idea of this proposal is that it is
equivalent to the manual implementation...

Mike

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


(Tony Allevato) #7

There's been talk about "protocol forwarding" that I think would achieve
a lot of these goals, without the sharp edges involved trying to define
inheritance between a class and a struct. The proposed feature would
eliminate the boilerplate you're talking about.

I'm on my phone so I can't pull up links to old discussions, but Matthew
Johnson is who was pushing it so you may want to look back at what he's
said on the topic.

thanks, i skimmed through it now and will have a closer look later.
does it address (2) though? (preexisting value types we can't change)

as to the sharp edges: i do not see a single one in the "manual"
implementation of this approach and the idea of this proposal is that it is
equivalent to the manual implementation...

Imagine something like this:

struct BaseStruct { ... }
class ExtendsStruct: BaseStruct { ... }

func foo(x: BaseStruct) { ... }
func bar(x: inout BaseStruct) { ... }

var x = ExtendsStruct(...)
foo(x)
bar(&x)

What is the behavior in each of these cases? Do foo and bar get a
value-type slice of x? Is that slice the same memory as is occupied by x,
or is it a copy? When bar mutates its argument, does it modify the same
memory occupied by x?

Supporting better composition (such as through protocol forwarding) avoids
all of these issues.

Let's go back to step 1: what's your use case for wanting inheritance
between a class and a struct vs. something like protocol forwarding? You've
proposed a feature in the abstract but it would be more helpful to know
what problem you're trying to solve. Do you just want to create a new type
that contains the same data and methods as a value type, plus others, but
as a reference type? Is it important for your use case that there is an
"is-a" relationship between the two types, or do you just want to reüse the
implementation of the value type? If you do want an "is-a" relationship,
how do you get around the fact that the *identity* of the reference type
would be lost if you used it polymorphically through the base struct type?

···

On Thu, Jun 22, 2017 at 5:15 PM Mike Kluev <mike.kluev@gmail.com> wrote:

On 23 June 2017 at 02:43, Tony Allevato <tony.allevato at gmail.com > <tony.allevato@gmail.com>> wrote:

Mike


(Haravikk) #8

Maybe, but the whole point of the protocol is that it's a contract, it's up to the implementing types how the properties are actually stored (if at all); in that respect it's not noise, as it's necessary.

The shorthand you're proposing is effectively masquerading delegation as extension; I'm not sure making it look like extension is the right way to go, but delegation is absolutely something I support, just not in this style.

Currently there is a lot of boilerplate around things like type-erased wrappers, where you might get a class that looks like:

  class MyWrapper<S:Foo>:Foo {
    struct foo:S

    func someMethodOfFoo() { foo.someMethodOfFoo() }
    func someOtherMethodOfFoo() { foo.someOtherMethodOfFoo() }
  }

It's the same basic problem, except that I don't necessarily want everything to be implemented by my enclosed struct. This is why I'd prefer a solution that's more explicit about the fact that there's delegation going on, and more flexible about how things are delegated. This is what I mean:

  protocol Foo {
    var someValue:Int { get set }
    func someMethod() -> Int
  }

  struct ValueType:Foo {
    var someValue:Int
    func someMethod() { return self.someValue }
  }

  class ReferenceType:Foo {
    var foo:ValueType implements Foo // This is the important bit
  }

It's got one extra step, but is explicit that there's delegation involved, and without suggesting some kind of hierarchy that doesn't exist. In this case ValueType needn't even conform to Foo at all, just as long it has properties and methods that are a match; in this way we could potentially conform to Foo using multiple delegates that each implement a little bit of the protocol.

Another possible syntax is:

  class ReferenceType:Foo {
    delegate(Foo) var foo:ValueType
  }

This may be slightly better as it explicitly references to delegation, but it's the same idea; in the brackets you put one or more types, or members of types, that the property is a delegate for.

···

On 23 Jun 2017, at 16:20, Mike Kluev <mike.kluev@gmail.com> wrote:

on Fri Jun 23 05:26:11 CDT 2017 Haravikk swift-evolution at haravikk.me <http://haravikk.me/> wrote:

> Not sure what you mean by added indirection here, the following seems perfectly straightforward to me:
>
> protocol Foo {
> var someValue:Int { get set }
> func a() -> Any?
> }
>
> extension Foo {
> func a() -> Any? { return self.someValue }
> }
>
> struct ValueSemantics:Foo { var someValue:Int }
> class ReferenceSemantics:Foo {
> var someValue:Int { return nil }
> }
>
> There is no added access overhead here, the only difference is that the protocol itself leaves it up to
> implementations whether someValue is stored or computed.

in real cases there would be more variables:

//============
protocol P1 { // #noise
    var var1: Int { get set } // #noise
    var var2: Int { get set } // #noise
    // ... // #noise x 100
    var var100: Int { get set } // #noise
    
    func foo1() -> Int // #noise
    func foo2() -> Int // #noise
    // ... // #noise x 100
    func foo100() -> Int // #noise
}

extension P1 { // #noise
    func foo1() -> Int { return var1 * 2 }
    func foo2() -> Int { return var2 * 2 }
    // ...
    func foo100() -> Int { return var100 * 2 }
}

struct S1: P1 {
    var var1: Int // #noise
    var var2: Int // #noise
    // ... // #noise x 100
    var var100: Int // #noise
}

class C1: P1 {
    var var1: Int = 0 // #noise
    var var2: Int = 0 // #noise
    // ... // #noise x 100
    var var100: Int = 0 // #noise
}
//============

lots of noise and violations of DRY. you may try to mitigate it by putting all those storage into another struct, that was the indirection i was thinking about:


(Mike Kluev) #9

Imagine something like this:

struct BaseStruct { ... }
class ExtendsStruct: BaseStruct { ... }

func foo(x: BaseStruct) { ... }
func bar(x: inout BaseStruct) { ... }

var x = ExtendsStruct(...)
foo(x)
bar(&x)

would be:

foo(x) // same as foo(x.super) for which it easy to see what's going on
bar(&x) // same as bar(&x.super) for which it is easy to see what's going on

What is the behavior in each of these cases? Do foo and bar get a
value-type slice of x? Is that slice the same memory as is occupied by x,
or is it a copy? When bar mutates its argument, does it modify the same
memory occupied by x?

all these questions are easily answered if you consider the equivalent
manual implementation...

Let's go back to step 1: what's your use case for wanting inheritance
between a class and a struct vs. something like protocol forwarding?

i don't control the preexisting value type in general case, so there is no
protocol around to hijack.

essentially this proposal allows your own or preexisting value type to act
as a reference type without having any code or upfront provisions. no more,
no less. if you ever had a thought similar to: "i need String / Data / Rect
/ etc but the one that's reference type" this device will be for you.

class ClassString: String {}
class ClassData: Data {}
class ClassCGRect: CGRect {}

Mike

···

On 23 June 2017 at 18:31, Tony Allevato <tony.allevato@gmail.com> wrote:


(Goffredo Marocchi) #10

> Not sure what you mean by added indirection here, the following seems perfectly straightforward to me:
>
> protocol Foo {
> var someValue:Int { get set }
> func a() -> Any?
> }
>
> extension Foo {
> func a() -> Any? { return self.someValue }
> }
>
> struct ValueSemantics:Foo { var someValue:Int }
> class ReferenceSemantics:Foo {
> var someValue:Int { return nil }
> }
>
> There is no added access overhead here, the only difference is that the protocol itself leaves it up to
> implementations whether someValue is stored or computed.

in real cases there would be more variables:

//============
protocol P1 { // #noise
    var var1: Int { get set } // #noise
    var var2: Int { get set } // #noise
    // ... // #noise x 100
    var var100: Int { get set } // #noise
    
    func foo1() -> Int // #noise
    func foo2() -> Int // #noise
    // ... // #noise x 100
    func foo100() -> Int // #noise
}

extension P1 { // #noise
    func foo1() -> Int { return var1 * 2 }
    func foo2() -> Int { return var2 * 2 }
    // ...
    func foo100() -> Int { return var100 * 2 }
}

struct S1: P1 {
    var var1: Int // #noise
    var var2: Int // #noise
    // ... // #noise x 100
    var var100: Int // #noise
}

class C1: P1 {
    var var1: Int = 0 // #noise
    var var2: Int = 0 // #noise
    // ... // #noise x 100
    var var100: Int = 0 // #noise
}
//============

lots of noise and violations of DRY. you may try to mitigate it by putting all those storage into another struct, that was the indirection i was thinking about:

Maybe, but the whole point of the protocol is that it's a contract

... and this is why I do not like code in then (see default method in protocol extensions essentially just to allow code sharing across structs) :P.

···

Sent from my iPhone

On 23 Jun 2017, at 21:08, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 23 Jun 2017, at 16:20, Mike Kluev <mike.kluev@gmail.com> wrote:
on Fri Jun 23 05:26:11 CDT 2017 Haravikk swift-evolution at haravikk.me wrote:

, it's up to the implementing types how the properties are actually stored (if at all); in that respect it's not noise, as it's necessary.

The shorthand you're proposing is effectively masquerading delegation as extension; I'm not sure making it look like extension is the right way togo, but delegation is absolutely something I support, just not in this style.

Currently there is a lot of boilerplate around things like type-erased wrappers, where you might get a class that looks like:

  class MyWrapper<S:Foo>:Foo {
    struct foo:S

    func someMethodOfFoo() { foo.someMethodOfFoo() }
    func someOtherMethodOfFoo() { foo.someOtherMethodOfFoo() }
  }

It's the same basic problem, except that I don't necessarily want everything to be implemented by my enclosed struct. This is why I'd prefer a solution that's more explicit about the fact that there's delegation going on, and more flexible about how things are delegated. This is what I mean:

  protocol Foo {
    var someValue:Int { get set }
    func someMethod() -> Int
  }

  struct ValueType:Foo {
    var someValue:Int
    func someMethod() { return self.someValue }
  }

  class ReferenceType:Foo {
    var foo:ValueType implements Foo // This is the important bit
  }

It's got one extra step, but is explicit that there's delegation involved, and without suggesting some kind of hierarchy that doesn't exist. In this case ValueType needn't even conform to Foo at all, just as long it has properties and methods that are a match; in this way we could potentially conform to Foo using multiple delegates that each implement a little bit of the protocol.

Another possible syntax is:

  class ReferenceType:Foo {
    delegate(Foo) var foo:ValueType
  }

This may be slightly better as it explicitly references to delegation, but it's the same idea; in the brackets you put one or more types, or members of types, that the property is a delegate for.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tony Allevato) #11

Imagine something like this:

struct BaseStruct { ... }
class ExtendsStruct: BaseStruct { ... }

func foo(x: BaseStruct) { ... }
func bar(x: inout BaseStruct) { ... }

var x = ExtendsStruct(...)
foo(x)
bar(&x)

would be:

foo(x) // same as foo(x.super) for which it easy to see what's going on
bar(&x) // same as bar(&x.super) for which it is easy to see what's going
on

What is the behavior in each of these cases? Do foo and bar get a
value-type slice of x? Is that slice the same memory as is occupied by x,
or is it a copy? When bar mutates its argument, does it modify the same
memory occupied by x?

all these questions are easily answered if you consider the equivalent
manual implementation...

No, they aren't, because the equivalent manual implementation that uses
composition does not permit you to pass an ExtendsStruct to a function that
expects a BaseStruct because they're different types.

Looking back, I must have missed your earlier message where you said that
`C() is S` would be false and you wouldn't be able to pass C where S is
required. Sorry about that. But if that's true, then you don't *really*
have an inheritance relationship at all. An inheritance relationship
specifically *does* mean that `C() is S` if C extends S. If your proposal
doesn't require that, then you effectively have composition that looks
syntactically like inheritance, and now you have an inconsistency in the
language:

class C1: C2 ==> C1() is C2 == true
class C1: P ==> C1() is P == true
class C1: S ==> C1() is S == false?

Given those statements, I think what you're asking for could be achieved
just as well using protocol forwarding, which makes the composition
relationship explicitly visible instead of hiding it in something that it's
not.

···

On Fri, Jun 23, 2017 at 10:28 AM Mike Kluev <mike.kluev@gmail.com> wrote:

On 23 June 2017 at 18:31, Tony Allevato <tony.allevato@gmail.com> wrote:

Let's go back to step 1: what's your use case for wanting inheritance
between a class and a struct vs. something like protocol forwarding?

i don't control the preexisting value type in general case, so there is no
protocol around to hijack.

essentially this proposal allows your own or preexisting value type to act
as a reference type without having any code or upfront provisions. no more,
no less. if you ever had a thought similar to: "i need String / Data / Rect
/ etc but the one that's reference type" this device will be for you.

class ClassString: String {}
class ClassData: Data {}
class ClassCGRect: CGRect {}

Mike


(Mike Kluev) #12

class C1: C2 ==> C1() is C2 == true

class C1: P ==> C1() is P == true
class C1: S ==> C1() is S == false?

ok. changing the rule then:

C() is S == true

foo(x) acts the same way as foo(x.super)
bar(&x) acts the same way as bar(&x.super)

i am not quite sure i am getting the answers along the lines of "use
protocol forwarding" instead. i have no protocol to begin with. for a
preexisting value type (e.g. OS provided) it would be a nightmare to create
and maintain the corresponding protocol.

Mike

···

On 23 June 2017 at 23:18, Tony Allevato <tony.allevato@gmail.com> wrote:


(Xiaodi Wu) #13

class C1: C2 ==> C1() is C2 == true
class C1: P ==> C1() is P == true
class C1: S ==> C1() is S == false?

ok. changing the rule then:

C() is S == true

foo(x) acts the same way as foo(x.super)
bar(&x) acts the same way as bar(&x.super)

i am not quite sure i am getting the answers along the lines of "use
protocol forwarding" instead. i have no protocol to begin with. for a
preexisting value type (e.g. OS provided)

Value subtyping has many uses and is something which will be very powerful,
if and when it arrives in Swift. The idea of a reference type that can
subtype a value type is intriguing but obviously requires a lot of thought.
Certainly, it is something far into the future.

However, *even at that time*, I'm quite certain that you will not be able
to subtype an OS-provided value type unless it has already been designed
for subtyping, just as you are not able to subtype Swift-native reference
types unless they are already designed for subtyping. At that time, just as
now, the way to accomplish what you wish for would be some sort of
forwarding. The difficulty of maintains a third-party protocol for core
types should be much alleviated with greater API stability.

it would be a nightmare to create and maintain the corresponding protocol.

···

On Fri, Jun 23, 2017 at 17:59 Mike Kluev via swift-evolution < swift-evolution@swift.org> wrote:

On 23 June 2017 at 23:18, Tony Allevato <tony.allevato@gmail.com> wrote:

Mike

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