[Pitch] Conformance Builders

The main thing this pitch gets right is using method overloading instead of types to express structural concepts ("more like result builders"). However, solving these use-cases one by one can lead to significant complexity in the language, as opposed to implementing a single mechanism for the more general concept of static structural reflection (which I mentioned in this thread).

Here are some thoughts about what a more general solution might look like:

Being able to provide custom overrides to this type of functionality is very important in Swift, functionality designed using this type of mechanism should compose well with types using custom storage (for instance, Capnproto types, which have semantic stored properties but could customize the layout of those fields). Additionally, it is important that types know when changing their structural representation might affect their usage (otherwise even something as simple as changing the order of properties may have unintended consequences).

struct Vector: @VectorEquatableBuilder Equatable

We don't currently have attributes on conformances, and I'm not sure that we need them to achieve this goal. VectorEquatable can simply refine Equatable and use structural reflection to achieve the desired affect:

/// This doesn't need any new semantics, just conformance to a special protocol
public protocol VectorEquatable: Equatable, Structural {
  public static func == (lhs: Self, rhs: Self) {
    // Not necessary the best API, just conveying the general idea
    @EquatableConformanceBuilder var comparator: EquatableConformanceBuilder<Self>.Comparator
    // Hopefully, this can be optimized by the compiler
    return comparator.components.allSatisfy { $0(lhs, rhs) }
  }
}

@structuralBuilder
public struct EquatableConformanceBuilder<U: Structural> {
  public struct Component {
    /// defined as a closure for simplicity, an ideal implementation should use a form that can be properly optimized
    let compare: (U, U) -> Bool
  }
  public static func buildProperty<T: Equatable>(_ keyPath: KeyPath<U, T>) -> Component {
     Component { lhs, rhs in lhs[keyPath: keyPath] == rhs[keyPath: keyPtah] }
  }
  public struct Comparator {
     let components: [Component]
  }
  public static func buildBlock(_ components: Component...) -> Comparator {
     return Comparator(components: components)
  }
}

So you would end up with something like:

struct Vector: VectorEquatable {
  let x, y: Double

  /// == conformance is synthesized from `VectorEquatable`
}

This would also synthesize the correct conformance for Vector3D, as opposed to what you mentioned in your proposal:

struct Vector3D: @VectorEquatableBuilder Equatable {
  // ❌ 'VectorEquatableBuilder' can't synthesize  
  // 'Equatable' conformance for struct with 3 members. 

  let x, y, z: Double 
}

In the case that a property doesn't match a method overload in the builder, you would get an error similar to what we have now for string interpolation.

1 Like