Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Alternative implementation of StaticStructural #10

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions Sources/StructuralCore/Structural.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,57 +25,59 @@ public protocol Structural {
}

/// Structural representation of a Swift struct.
public struct StructuralStruct<Properties> {
public var type: Any.Type?
public struct StructuralStruct<BaseType, Properties> {
public var type: BaseType.Type?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is type Optional<BaseType.Type> and not simply BaseType.Type? (Note: I realize this was the case before your change too.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at implementation of Zero we need to be able to create an instance StructuralStruct based on known type parameters only.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But don't we now have BaseType? Couldn't we do something like:

extension StructuralStruct: Zero where Properties: Zero {
    public static var zero: Self {
        return StructuralStruct(type: BaseType.self, Properties.zero)
    }
}

public var properties: Properties

public init(_ properties: Properties) {
self.type = nil
self.properties = properties
}

public init(_ type: Any.Type, _ properties: Properties) {
public init(_ type: BaseType.Type, _ properties: Properties) {
self.type = type
self.properties = properties
}
}

/// Structural representation of a Swift property.
public struct StructuralProperty<Value> {
///
/// Value corresponds to the original declared property type.
/// WrappedValue is a declared property type with explicit property
/// wrappers included in the type.
public struct StructuralProperty<BaseType, Value, WrappedValue> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document Value vs WrappedValue. (I only understood the distinction when looking through the examples and seeing one using property wrappers.)

Agreed that this is some unfortunate complexity. :-(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment in b20fb72

public var keyPath: KeyPath<BaseType, Value>?
public var name: String
public var value: Value
public var isMutable: Bool
public var value: WrappedValue
Copy link
Contributor Author

@shabalind shabalind Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we can't get name out of KeyPath in a portable manner (there is a macOS-only solution that relies on NSExpression). This is intended because KeyPaths can express arbitrary multi-step field accesses.

What's even more unsettling is that we use StructuralProperty for both StructuralStruct properties and StructuralEnum associated values. Associated values don't work with KeyPaths at all, so if we unify this even further by removing name, we'll have to add yet another structural representation type StructuralAssociatedValue which is nearly identical to StructuralProperty, only with a name instead of keyPath.


public init(_ value: Value) {
self.name = ""
self.value = value
self.isMutable = false
public var isMutable: Bool {
return keyPath is WritableKeyPath<BaseType, Value>
}

public init(_ name: String, _ value: Value) {
self.name = name
public init(_ value: WrappedValue) {
self.name = ""
self.keyPath = nil
self.value = value
self.isMutable = false
}

public init(_ name: String, _ value: Value, isMutable: Bool) {
public init(_ keyPath: KeyPath<BaseType, Value>, _ name: String, _ value: WrappedValue) {
self.name = name
self.keyPath = keyPath
self.value = value
self.isMutable = isMutable
}
}

/// Structural representation of a Swift enum.
public struct StructuralEnum<Cases> {
public var type: Any.Type?
public struct StructuralEnum<BaseType, Cases> {
public var type: BaseType.Type?
public var cases: Cases

public init(_ cases: Cases) {
self.type = nil
self.cases = cases
}

public init(_ type: Any.Type, _ cases: Cases) {
public init(_ type: BaseType.Type, _ cases: Cases) {
self.type = type
self.cases = cases
}
Expand Down
1 change: 1 addition & 0 deletions Sources/StructuralExamples/ASCII.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extension ASCII: Structural {
// swift-format-ignore
public typealias StructuralRepresentation =
StructuralEnum<
ASCII,
StructuralEither<
StructuralCase<String, StructuralEmpty>,
StructuralEither<
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/Additive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ where AssociatedValues: Additive {
}

extension StructuralProperty: Additive
where Value: Additive {
where WrappedValue: Additive {
public static func + (lhs: Self, rhs: Self) -> Self {
return StructuralProperty(lhs.value + rhs.value)
}
Expand Down
21 changes: 13 additions & 8 deletions Sources/StructuralExamples/BinaryTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@ extension BinaryTree: Structural {
// swift-format-ignore
public typealias StructuralRepresentation =
StructuralEnum<
BinaryTree,
StructuralEither<
StructuralCase<Int, StructuralCons<StructuralProperty<T>, StructuralEmpty>>,
StructuralCase<
Int,
StructuralCons<StructuralProperty<BinaryTree, T, T>,
StructuralEmpty>>,
StructuralCase<
Int,
StructuralCons<
StructuralProperty<BinaryTree<T>>,
StructuralProperty<BinaryTree, BinaryTree<T>, BinaryTree<T>>,
StructuralCons<
StructuralProperty<T>,
StructuralProperty<BinaryTree, T, T>,
StructuralCons<
StructuralProperty<BinaryTree<T>>,
StructuralProperty<BinaryTree, BinaryTree<T>, BinaryTree<T>>,
StructuralEmpty
>
>
Expand All @@ -45,17 +49,18 @@ extension BinaryTree: Structural {
get {
switch self {
case let .leaf(x):
let properties = StructuralCons(StructuralProperty(x), StructuralEmpty())
let properties = StructuralCons(
StructuralProperty<BinaryTree, T, T>(x), StructuralEmpty())
return StructuralEnum(
BinaryTree.self, .left(StructuralCase("leaf", 0, properties)))
case let .branch(left, value, right):
let properties =
StructuralCons(
StructuralProperty(left),
StructuralProperty<BinaryTree, BinaryTree<T>, BinaryTree<T>>(left),
StructuralCons(
StructuralProperty(value),
StructuralProperty<BinaryTree, T, T>(value),
StructuralCons(
StructuralProperty(right),
StructuralProperty<BinaryTree, BinaryTree<T>, BinaryTree<T>>(right),
StructuralEmpty())))
return StructuralEnum(
BinaryTree.self, .right(StructuralCase("branch", 1, properties)))
Expand Down
1 change: 1 addition & 0 deletions Sources/StructuralExamples/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extension Color: Structural {
// swift-format-ignore
public typealias StructuralRepresentation =
StructuralEnum<
Color,
StructuralEither<
StructuralCase<Int, StructuralEmpty>,
StructuralEither<
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/CustomComparable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ where Properties: CustomComparable {
}

extension StructuralProperty: CustomComparable
where Value: CustomComparable {
where WrappedValue: CustomComparable {
public func less(_ other: Self) -> Bool {
return value.less(other.value)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/CustomDebugString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ where Value: CustomDebugString, Next: CustomDebugString {
}

extension StructuralProperty: CustomDebugString
where Value: CustomDebugString {
where WrappedValue: CustomDebugString {
public var debugString: String {
if self.name == "" {
return self.value.debugString
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/CustomEquatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ where AssociatedValues: CustomEquatable {
}

extension StructuralProperty: CustomEquatable
where Value: CustomEquatable {
where WrappedValue: CustomEquatable {
public func customEqual(_ other: Self) -> Bool {
return value.customEqual(other.value)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/CustomHashable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ where RawValue: CustomHashable, AssociatedValues: CustomHashable {
}

extension StructuralProperty: CustomHashable
where Value: CustomHashable {
where WrappedValue: CustomHashable {
public func customHash(into hasher: inout Hasher) {
value.customHash(into: &hasher)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/DecodeJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ where Properties: DecodeJSON {
}

extension StructuralProperty: DecodeJSON
where Value: DecodeJSON {
where WrappedValue: DecodeJSON {
public mutating func decodeJson(_ other: Any) {
let dict = other as! [String: Any]
self.value.decodeJson(dict[self.name]!)
Expand Down
4 changes: 2 additions & 2 deletions Sources/StructuralExamples/DefaultInitializable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ where Properties: DefaultInitializable {
}

extension StructuralProperty: DefaultInitializable
where Value: DefaultInitializable {
where WrappedValue: DefaultInitializable {
public init() {
self.init(Value())
self.init(WrappedValue())
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/StructuralExamples/Differentiable2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ where Properties: Differentiable2 {
}

extension StructuralProperty: Differentiable2
where Value: Differentiable2 {
typealias TangentVector = Value.TangentVector
where WrappedValue: Differentiable2 {
typealias TangentVector = WrappedValue.TangentVector

mutating func move(along direction: TangentVector) {
self.value.move(along: direction)
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/EncodeJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ where Properties: EncodeJSON {
}

extension StructuralProperty: EncodeJSON
where Value: EncodeJSON {
where WrappedValue: EncodeJSON {
public func encodeJson(into builder: inout JSONBuilder) {
builder.appendProperty(name: self.name)
self.value.encodeJson(into: &builder)
Expand Down
2 changes: 1 addition & 1 deletion Sources/StructuralExamples/InplaceAdd.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ where Properties: InplaceAdd {
}

extension StructuralProperty: InplaceAdd
where Value: InplaceAdd {
where WrappedValue: InplaceAdd {
public mutating func inplaceAdd(_ other: Self) {
if isMutable {
self.value.inplaceAdd(other.value)
Expand Down
Loading