Syntax sugar for declaring nested types

I don't think they are semantically equivalent because of unqualified name lookup. In the "struct A.B" case, you would not expect the members of A to be visible.

2 Likes

Why not? I view this as simple syntactic sugar. Can you explain why a more subtle programmer model would make sense?

Consider this example:

struct Outer {
  typealias Alias = Int

  struct Inner {
    var x: Alias
  }
}

Now what if I have this:

struct Outer {
  typealias Alias = Int
}

struct Outer.Inner {
  var x: Alias // is this valid or do I have to write Outer.Alias?
}

With extensions today, an extension of a nested type cannot reference members of an outer type without qualification. So presumably we would want to maintain the same behavior for the "nested type definition" syntax.

It's interesting to see this explanation. I have actually been tripped up by this behavior and expected lookup to work in extensions. I actually found it rather confusing and couldn't understand exactly what was going on. Is there a good reason for preferring lexical scope for lookup rather than symbolic scope?

Given the heavy emphasis in Swift on encouraging the use of extensions (see the final resolution to private vs fileprivate), I think the current behavior is actually counterintuitive. Is there any possibility this is something that could change?

Either way, I agree that lookup in these declarations should behave identically to lookup in extensions.

I second this, it can be quite annoying to have to refer to Inner as Outer.Inner inside extension Outer.Inner { ... }.

1 Like

I also think the same way.

struct Outer {
  typealias Alias = Int

  struct Inner {
    var x: Alias
  }
}

extension Outer {
  struct OtherInner {
    var x: Alias
    var y: Inner
  }
}

/*
// Sugar for the top extension, easy to teach.
struct Outer.OtherInner {
  // Should behave the same in the extension above.
  var x: Alias
  var y: Inner
}
*/

// The following extension is rather confusing today:
extension Outer.OtherInner {
  var z: Alias { // error: Use of undeclared type 'Alias'
    return x
  }
}