Inconsistencies in recursive types


(Dimitri Racordon) #1

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the compiler handles them. Consider the following cases:

1. Swift is right to refuse compiling this, since there’s no way to initialise an instance of `First `:

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references itself

However, the message suggests more a compiler limitation rather than the actual impossibility to initialize the declared type.

2. Swift is also right not to compile this, but the error messages are even less insightful:

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that references itself

The problem isn’t that the value types reference themselves. Instead, the problem is that there’s a cyclic dependency between `First` and `Second` that makes it impossible for neither of these structures to be instantiated.

3. Swift should let me do that:

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there actually is a way to initialise an instance of `First` (e.g. `First(item: nil)`). The message is identical to that of case #1 (maybe it actually is a compiler limitation after all?)

4. Swift shouldn’t compile this:

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s a reference rather than a value doesn’t change the problem.

5. Similarly to case #4, Swift shouldn’t compile this:

indirect enum First {
    case item(First)
}

6. Cases #4 #5 could be written like case #2, and should also raise compilation errors.

Does someone know if these issues have already been discussed and/or addressed?

Thanks,
Dimitri Racordon


(Tony Allevato) #2

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the
compiler handles them. Consider the following cases:

*1. Swift is right to refuse compiling this, since there’s no way to
initialise an instance of `First `:*

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references
itself

However, the message suggests more a compiler limitation rather than the
actual impossibility to initialize the declared type.

*2. Swift is also right not to compile this, but the error messages are
even less insightful:*

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references
itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that
references itself

The problem isn’t that the value types reference *themselves*. Instead,
the problem is that there’s a cyclic dependency between `First` and
`Second` that makes it impossible for neither of these structures to be
instantiated.

*3. Swift should let me do that:*

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there
actually is a way to initialise an instance of `First` (e.g. `First(item:
nil)`). The message is identical to that of case #1 (maybe it actually
*is* a compiler limitation after all?)

The problem with this example is that since Optional<T> is a value type (an
enum), this is a value type that is recursive upon itself. Until indirect
struct fields are possible, this can't be supported—there's *one* valid way
to instantiate it without recursion at runtime, but the compiler can't know
what you might try to pass in there, nor can it (I believe) compute the
layout of that type because of the potential recursion.

*4. Swift shouldn’t compile this:*

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s
a reference rather than a value doesn’t change the problem.

*5. Similarly to case #4, Swift shouldn’t compile this:*

indirect enum First {
    case item(First)
}

Re: #4 and #5, I've been pondering the same thing lately because I've been
tinkering with an implementation of auto-deriving Equatable/Hashable for
enums in my spare time, and I've been using recursive cases like this to
test edge cases. For something like #5, I can generate the bodies of == and
hashValue, but what good are they for a type that you can't actually get
values of?

In general, having noninstantiable types is good—caseless enums are useful
as a way of namespacing static members. But in the specific case where a
type is impossible to instantiate because of infinite recursion, a compiler
diagnostic sounds like a good idea. I'm trying to think of situations where
that would be valid and someone would need that functionality, but I'm
coming up blank. But, I'm no expert on type systems.

···

On Mon, Mar 13, 2017 at 6:38 AM Dimitri Racordon via swift-evolution < swift-evolution@swift.org> wrote:

*6. Cases #4 #5 could be written like case #2, and should also raise
compilation errors.*

Does someone know if these issues have already been discussed and/or
addressed?

Thanks,
Dimitri Racordon

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


(Jaden Geller) #3

Comments inline:

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the compiler handles them. Consider the following cases:

1. Swift is right to refuse compiling this, since there’s no way to initialise an instance of `First `:

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references itself

However, the message suggests more a compiler limitation rather than the actual impossibility to initialize the declared type.

This is a compiler limitation that isn’t going to go away. Structs are value types whose size is equal to the sum of their property sizes. Here, we have a circular dependency, so it is impossible to compute the size.

This is not an arbitrary restriction. Consider:

struct List<T> {
    var head: T
    var tail: List<T>?
}

The size of `List` is infinite! Every `Optional<T>` must be big enough to store the type `T` in case the value is not `nil`. Thus, `List` must be big enough to store a `T` AND another list (of the same size):

size(of: List<T>) = size(of: T) + size(of: List<T>)

It’s easy to see that, assuming `size(of: T)` is non-zero, it is impossible to satisfy this constraint. Yes, Swift could special case the case where there are no other members, but this would be entirely useless (you can’t store state) and would considerably muck up the semantics.

Note that enums allow members to be marked `indirect`. This would be a reasonable feature for Swift to eventually support for structs as well. In this case, the indirect member would be the size of a pointer, so the size would be statically known and satisfied.

2. Swift is also right not to compile this, but the error messages are even less insightful:

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that references itself

The problem isn’t that the value types reference themselves. Instead, the problem is that there’s a cyclic dependency between `First` and `Second` that makes it impossible for neither of these structures to be instantiated.

This is an identical problem to #1. The error message could probably be improved. This isn’t a “reference” in the sense of a pointer, but in the sense that there is literally a dependency.

3. Swift should let me do that:

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there actually is a way to initialise an instance of `First` (e.g. `First(item: nil)`). The message is identical to that of case #1 (maybe it actually is a compiler limitation after all?)

This is an identical problem to #1. An option does *not* introduce any indirection. Swift will however allow the following:

struct First {
    let item: [First]
}

This is because `Array<T>`—if you look at its declaration—does not *directly* store any type `T`. Instead, it stores a pointer to a buffer holding `T`s, allocated at runtime. These semantics may be a big confusing at first, but this is the tradeoff for the better performance value types can sometimes bring.

4. Swift shouldn’t compile this:

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s a reference rather than a value doesn’t change the problem.

This is not a bug IMO. It is not the compiler’s job to prevent you from compiling code that includes a type that cannot be instantiated.

Unlike the previous cases, the compiler actually *can* generate code for these types. You _could_ even unsafely instantiate these types. In the previous cases, the compiler could not compute the size of the types.

5. Similarly to case #4, Swift shouldn’t compile this:

indirect enum First {
    case item(First)
}

Ditto #4.

6. Cases #4 #5 could be written like case #2, and should also raise compilation errors.

Ditto #4.

Does someone know if these issues have already been discussed and/or addressed?

Thanks,
Dimitri Racordon

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

I hope I was able to clear up your confusion. Let me know if you have any other questions.

Cheers,
Jaden Geller

···

On Mar 13, 2017, at 6:38 AM, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:


#4

FWIW, there *is* a way to instantiate #4 case.

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

class Second : First {
    init() {
        super.init(item: self)
    }
}

let a: First = Second()

···

2017-03-13 22:38 GMT+09:00 Dimitri Racordon via swift-evolution < swift-evolution@swift.org>:

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the
compiler handles them. Consider the following cases:

*1. Swift is right to refuse compiling this, since there’s no way to
initialise an instance of `First `:*

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references
itself

However, the message suggests more a compiler limitation rather than the
actual impossibility to initialize the declared type.

*2. Swift is also right not to compile this, but the error messages are
even less insightful:*

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references
itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that
references itself

The problem isn’t that the value types reference *themselves*. Instead,
the problem is that there’s a cyclic dependency between `First` and
`Second` that makes it impossible for neither of these structures to be
instantiated.

*3. Swift should let me do that:*

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there
actually is a way to initialise an instance of `First` (e.g. `First(item:
nil)`). The message is identical to that of case #1 (maybe it actually
*is* a compiler limitation after all?)

*4. Swift shouldn’t compile this:*

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s
a reference rather than a value doesn’t change the problem.

*5. Similarly to case #4, Swift shouldn’t compile this:*

indirect enum First {
    case item(First)
}

*6. Cases #4 #5 could be written like case #2, and should also raise
compilation errors.*

Does someone know if these issues have already been discussed and/or
addressed?

Thanks,
Dimitri Racordon

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


(Dimitri Racordon) #5

Oh yes you’re right.
I didn’t consider that case; thanks.

···

On 13 Mar 2017, at 15:34, rintaro ishizaki <fs.output@gmail.com<mailto:fs.output@gmail.com>> wrote:

FWIW, there *is* a way to instantiate #4 case.

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

class Second : First {
    init() {
        super.init(item: self)
    }
}

let a: First = Second()

2017-03-13 22:38 GMT+09:00 Dimitri Racordon via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>>:
Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the compiler handles them. Consider the following cases:

1. Swift is right to refuse compiling this, since there’s no way to initialise an instance of `First `:

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references itself

However, the message suggests more a compiler limitation rather than the actual impossibility to initialize the declared type.

2. Swift is also right not to compile this, but the error messages are even less insightful:

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that references itself

The problem isn’t that the value types reference themselves. Instead, the problem is that there’s a cyclic dependency between `First` and `Second` that makes it impossible for neither of these structures to be instantiated.

3. Swift should let me do that:

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there actually is a way to initialise an instance of `First` (e.g. `First(item: nil)`). The message is identical to that of case #1 (maybe it actually is a compiler limitation after all?)

4. Swift shouldn’t compile this:

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s a reference rather than a value doesn’t change the problem.

5. Similarly to case #4, Swift shouldn’t compile this:

indirect enum First {
    case item(First)
}

6. Cases #4 #5 could be written like case #2, and should also raise compilation errors.

Does someone know if these issues have already been discussed and/or addressed?

Thanks,
Dimitri Racordon

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


(Dimitri Racordon) #6

But then!

The following still shouldn’t compile:

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}


#7

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

extension First {
    convenience init() {
        self.init(item: self)
    }
}

let a = First()

I'm actually a bit surprised that this compiles.
This should be diagnosed as: "error: 'self' used before self.init call" I
think.

···

2017-03-13 23:42 GMT+09:00 Dimitri Racordon <Dimitri.Racordon@unige.ch>:

But then!

The following still shouldn’t compile:

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}


(Dimitri Racordon) #8

Thanks a lot for your very detailed explanations!

So my only issue regarding #1 #2 and #3 is the error message, which really doesn't suggest the actual underlying problem.

Regarding #5 and #6, I still feel like the compiler should complain about it. I disagree on the fact that it shouldn't be it's role to disallow uninitializable code, unless using unsafe techniques. This imho isn't consistent with some other errors the compiler does emit for ill-defined types.

···

On 13 Mar 2017, at 22:20, Jaden Geller <jaden.geller@gmail.com<mailto:jaden.geller@gmail.com>> wrote:

Comments inline:

On Mar 13, 2017, at 6:38 AM, Dimitri Racordon via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the compiler handles them. Consider the following cases:

1. Swift is right to refuse compiling this, since there’s no way to initialise an instance of `First `:

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references itself

However, the message suggests more a compiler limitation rather than the actual impossibility to initialize the declared type.

This is a compiler limitation that isn’t going to go away. Structs are value types whose size is equal to the sum of their property sizes. Here, we have a circular dependency, so it is impossible to compute the size.

This is not an arbitrary restriction. Consider:

struct List<T> {
    var head: T
    var tail: List<T>?
}

The size of `List` is infinite! Every `Optional<T>` must be big enough to store the type `T` in case the value is not `nil`. Thus, `List` must be big enough to store a `T` AND another list (of the same size):

size(of: List<T>) = size(of: T) + size(of: List<T>)

It’s easy to see that, assuming `size(of: T)` is non-zero, it is impossible to satisfy this constraint. Yes, Swift could special case the case where there are no other members, but this would be entirely useless (you can’t store state) and would considerably muck up the semantics.

Note that enums allow members to be marked `indirect`. This would be a reasonable feature for Swift to eventually support for structs as well. In this case, the indirect member would be the size of a pointer, so the size would be statically known and satisfied.

2. Swift is also right not to compile this, but the error messages are even less insightful:

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that references itself

The problem isn’t that the value types reference themselves. Instead, the problem is that there’s a cyclic dependency between `First` and `Second` that makes it impossible for neither of these structures to be instantiated.

This is an identical problem to #1. The error message could probably be improved. This isn’t a “reference” in the sense of a pointer, but in the sense that there is literally a dependency.

3. Swift should let me do that:

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there actually is a way to initialise an instance of `First` (e.g. `First(item: nil)`). The message is identical to that of case #1 (maybe it actually is a compiler limitation after all?)

This is an identical problem to #1. An option does *not* introduce any indirection. Swift will however allow the following:

struct First {
    let item: [First]
}

This is because `Array<T>`—if you look at its declaration—does not *directly* store any type `T`. Instead, it stores a pointer to a buffer holding `T`s, allocated at runtime. These semantics may be a big confusing at first, but this is the tradeoff for the better performance value types can sometimes bring.

4. Swift shouldn’t compile this:

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s a reference rather than a value doesn’t change the problem.

This is not a bug IMO. It is not the compiler’s job to prevent you from compiling code that includes a type that cannot be instantiated.

Unlike the previous cases, the compiler actually *can* generate code for these types. You _could_ even unsafely instantiate these types. In the previous cases, the compiler could not compute the size of the types.

5. Similarly to case #4, Swift shouldn’t compile this:

indirect enum First {
    case item(First)
}

Ditto #4.

6. Cases #4 #5 could be written like case #2, and should also raise compilation errors.

Ditto #4.

Does someone know if these issues have already been discussed and/or addressed?

Thanks,
Dimitri Racordon

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

I hope I was able to clear up your confusion. Let me know if you have any other questions.

Cheers,
Jaden Geller


(David Sweeris) #9

Interestingly enough, this code:
final class First {
    let item: First
// let int: Int
    let string: String
    init(item: First) {
        self.item = item
// self.int = item.int
        self.string = item.string
    }
}

extension First {
    convenience init() {
        self.init(item: self)
    }
}

let a = First()
//print("a.int:")
//print(a.int)
print("a.string:")
print(a.string)
print("done”)
Outputs
a.string:
fatal error: unsafelyUnwrapped of nil optional
(followed by a trace and lldb prompt)
But if I switch which stored properties are commented out (and printed), it usually outputs:
a.int:
562949953421312
done
Program ended with exit code: 0
or
a.int:
0
done
Program ended with exit code: 0
with the one exception being when `a.int`’s value started with a 7 instead of a 5 (but I didn’t think to copy/paste it). That’s not the interesting part, though. If both properties are uncommented and printed, it seems to always output:
a.int:
0
a.string:

done
Program ended with exit code: 0
(note that `a.string` seems be equal to “” now)

Anyway, I’d assume this is just a demonstration of the dangers of accessing uninitialized memory, but what I don’t know is why having two properties seems to remove the randomness in one’s value and stops the crashing when accessing the other's.

- Dave Sweeris

···

On Mar 13, 2017, at 10:56 AM, rintaro ishizaki via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

extension First {
    convenience init() {
        self.init(item: self)
    }
}

let a = First()

I'm actually a bit surprised that this compiles.
This should be diagnosed as: "error: 'self' used before self.init call" I think.


(John McCall) #10

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

extension First {
    convenience init() {
        self.init(item: self)
    }
}

let a = First()

I'm actually a bit surprised that this compiles.
This should be diagnosed as: "error: 'self' used before self.init call" I think.

Yes, it should.

John.

···

On Mar 13, 2017, at 10:56 AM, rintaro ishizaki via swift-evolution <swift-evolution@swift.org> wrote:

2017-03-13 23:42 GMT+09:00 Dimitri Racordon <Dimitri.Racordon@unige.ch <mailto:Dimitri.Racordon@unige.ch>>:
But then!

The following still shouldn’t compile:

final class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

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


(Jaden Geller) #11

Thanks a lot for your very detailed explanations!

So my only issue regarding #1 #2 and #3 is the error message, which really doesn't suggest the actual underlying problem.

Regarding #5 and #6, I still feel like the compiler should complain about it. I disagree on the fact that it shouldn't be it's role to disallow uninitializable code, unless using unsafe techniques. This imho isn't consistent with some other errors the compiler does emit for ill-defined types.

That’s the thing though, they aren’t ill-defined. Just because a type cannot be initialized does not mean it is not useful.

1. Namespacing

I admit this is a kind of hacky use, but there’s not better way right now.

enum Geometry {
    struct Point {
        var x: Int
        var y: Int
    }
}

let p = Geometry.Point(x: 0, y: 0)

2. Uninhabited Types

Swift uses `Never` as the return types of functions that can never return (e.g. `fatalError`). Since `never` is an enum with no cases, it is not possible to construct one. This indicates to the type system that the function will not return.

func runloop() -> Never {
    while true {
        print("Hello again!")
    }
}

let result: Never = runloop()
// Since a `Never` type cannot be constructed,
// we will not pass this line.

3. Phantom Types

Sometimes an uninhabited type is useful for providing information in the type system without creating an instance of the type itself. These tags can be used to provide additional behavior to the type or to provide additional type safety. Here’s another example <https://gist.github.com/JadenGeller/f39130616846f9bf9879> and some reading <https://wiki.haskell.org/Phantom_type>.

enum Unvalidated { }
enum Validated { }

struct User<V> {
    private(set) var name: String
    private(set) var age: Int
}

extension User where V == Unvalidated {
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    func validated() -> User<Validated>? {
        guard age > 18 else { return nil }
        return User<Validated>(name: name, age: age)
    }
}

func register(_ user: User<Validated>) {
    print("\(user.name) is registered!")
}

if let me = User<Unvalidated>(name: "Jaden Geller", age: 21).validated() {
    register(me)
}

Cheers,
Jaden Geller

···

On Mar 14, 2017, at 2:13 AM, Dimitri Racordon <Dimitri.Racordon@unige.ch> wrote:

On 13 Mar 2017, at 22:20, Jaden Geller <jaden.geller@gmail.com <mailto:jaden.geller@gmail.com>> wrote:

Comments inline:

On Mar 13, 2017, at 6:38 AM, Dimitri Racordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello swift-evolution,

I noticed there’s some inconsistencies with recursive types and how the compiler handles them. Consider the following cases:

1. Swift is right to refuse compiling this, since there’s no way to initialise an instance of `First `:

struct First {
    let item: First
}
// Error: Value type 'First' cannot have a stored property that references itself

However, the message suggests more a compiler limitation rather than the actual impossibility to initialize the declared type.

This is a compiler limitation that isn’t going to go away. Structs are value types whose size is equal to the sum of their property sizes. Here, we have a circular dependency, so it is impossible to compute the size.

This is not an arbitrary restriction. Consider:

struct List<T> {
    var head: T
    var tail: List<T>?
}

The size of `List` is infinite! Every `Optional<T>` must be big enough to store the type `T` in case the value is not `nil`. Thus, `List` must be big enough to store a `T` AND another list (of the same size):

size(of: List<T>) = size(of: T) + size(of: List<T>)

It’s easy to see that, assuming `size(of: T)` is non-zero, it is impossible to satisfy this constraint. Yes, Swift could special case the case where there are no other members, but this would be entirely useless (you can’t store state) and would considerably muck up the semantics.

Note that enums allow members to be marked `indirect`. This would be a reasonable feature for Swift to eventually support for structs as well. In this case, the indirect member would be the size of a pointer, so the size would be statically known and satisfied.

2. Swift is also right not to compile this, but the error messages are even less insightful:

struct First {
    let item: Second
}
// Error: Value type 'First' cannot have a stored property that references itself

struct Second {
    let item: First
}
// Error: Value type 'Second' cannot have a stored property that references itself

The problem isn’t that the value types reference themselves. Instead, the problem is that there’s a cyclic dependency between `First` and `Second` that makes it impossible for neither of these structures to be instantiated.

This is an identical problem to #1. The error message could probably be improved. This isn’t a “reference” in the sense of a pointer, but in the sense that there is literally a dependency.

3. Swift should let me do that:

struct First {
    let item: First?
}

The compiler prevents me to declare the above struct, even if there actually is a way to initialise an instance of `First` (e.g. `First(item: nil)`). The message is identical to that of case #1 (maybe it actually is a compiler limitation after all?)

This is an identical problem to #1. An option does *not* introduce any indirection. Swift will however allow the following:

struct First {
    let item: [First]
}

This is because `Array<T>`—if you look at its declaration—does not *directly* store any type `T`. Instead, it stores a pointer to a buffer holding `T`s, allocated at runtime. These semantics may be a big confusing at first, but this is the tradeoff for the better performance value types can sometimes bring.

4. Swift shouldn’t compile this:

class First {
    let item: First
    init(item: First) {
        self.item = item
    }
}

Like in case #1, there’s no way to instantiate `First`. The fact that it’s a reference rather than a value doesn’t change the problem.

This is not a bug IMO. It is not the compiler’s job to prevent you from compiling code that includes a type that cannot be instantiated.

Unlike the previous cases, the compiler actually *can* generate code for these types. You _could_ even unsafely instantiate these types. In the previous cases, the compiler could not compute the size of the types.

5. Similarly to case #4, Swift shouldn’t compile this:

indirect enum First {
    case item(First)
}

Ditto #4.

6. Cases #4 #5 could be written like case #2, and should also raise compilation errors.

Ditto #4.

Does someone know if these issues have already been discussed and/or addressed?

Thanks,
Dimitri Racordon

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

I hope I was able to clear up your confusion. Let me know if you have any other questions.

Cheers,
Jaden Geller