Skip to content

Commit

Permalink
Replace <| operator with generic subscript
Browse files Browse the repository at this point in the history
The `<|` operator was necessary when we originally implemented Argo, but Swift
has new capabilities now that reduce the need to use a custom operator.
Additionally, the operator spelling itself actually conflicts with prior-art
that we weren't aware of when we added it. Specifically, `<|` is used in other
languages (and sometimes in Swift) as a "pipe backwards" operator, with the
type `(T -> U) -> T -> U`.

Given these concerns, as well as the additional complexity around fine-tuning
the precedence so that it works in an obvious way, I think it makes sense to
remove the operator in favor of a generic subscript (which only just became
available in Swift 4).
  • Loading branch information
gfontenot committed Apr 27, 2018
1 parent 36f3741 commit 40f2e2e
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 160 deletions.
28 changes: 0 additions & 28 deletions Argo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
809754DA1BADF36D00C409E6 /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; };
809754DB1BADF36D00C409E6 /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */; };
809754DC1BADF36D00C409E6 /* DecodeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84318A71B9A2D7A00165216 /* DecodeError.swift */; };
809754DE1BADF36D00C409E6 /* DecodeOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */; };
809754DF1BADF36D00C409E6 /* (null) in Sources */ = {isa = PBXBuildFile; };
809754E21BADF36D00C409E6 /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69A1ABC5F1300E3B0AB /* decode.swift */; };
809754E31BADF36D00C409E6 /* flatReduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69B1ABC5F1300E3B0AB /* flatReduce.swift */; };
Expand Down Expand Up @@ -63,7 +62,6 @@
D0592EBF1B77DD8E00EFEF39 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69F1ABC5F1300E3B0AB /* JSON.swift */; };
D0592EC01B77DD8E00EFEF39 /* Decodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A01ABC5F1300E3B0AB /* Decodable.swift */; };
D0592EC11B77DD8E00EFEF39 /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB6A11ABC5F1300E3B0AB /* StandardTypes.swift */; };
D0592EC31B77DD9300EFEF39 /* DecodeOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */; };
D0592EC51B77DD9A00EFEF39 /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69A1ABC5F1300E3B0AB /* decode.swift */; };
D0592EC61B77DD9A00EFEF39 /* flatReduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69B1ABC5F1300E3B0AB /* flatReduce.swift */; };
D0592EC71B77DD9A00EFEF39 /* sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87EB69C1ABC5F1300E3B0AB /* sequence.swift */; };
Expand All @@ -83,9 +81,6 @@
EA04D5A11BBF2021001DE23B /* FailureCoalescing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A01BBF2021001DE23B /* FailureCoalescing.swift */; };
EA04D5A21BBF2021001DE23B /* FailureCoalescing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A01BBF2021001DE23B /* FailureCoalescing.swift */; };
EA04D5A31BBF2021001DE23B /* FailureCoalescing.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A01BBF2021001DE23B /* FailureCoalescing.swift */; };
EA04D5A51BBF2047001DE23B /* Argo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A41BBF2047001DE23B /* Argo.swift */; };
EA04D5A61BBF2047001DE23B /* Argo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A41BBF2047001DE23B /* Argo.swift */; };
EA04D5A71BBF2047001DE23B /* Argo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A41BBF2047001DE23B /* Argo.swift */; };
EA08313119D5EEAF003B90D7 /* TypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA08313019D5EEAF003B90D7 /* TypeTests.swift */; };
EA08313319D5EEF2003B90D7 /* post_comments.json in Resources */ = {isa = PBXBuildFile; fileRef = EA08313219D5EEF2003B90D7 /* post_comments.json */; };
EA08313519D5EFC0003B90D7 /* types.json in Resources */ = {isa = PBXBuildFile; fileRef = EA08313419D5EFC0003B90D7 /* types.json */; };
Expand Down Expand Up @@ -120,7 +115,6 @@
EA6DD69D1AB383FB00CA3A5B /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6DD69B1AB383FB00CA3A5B /* PerformanceTests.swift */; };
EA6DD69F1AB384C700CA3A5B /* big_data.json in Resources */ = {isa = PBXBuildFile; fileRef = EA6DD69E1AB384C700CA3A5B /* big_data.json */; };
EA6DD6A01AB384C700CA3A5B /* big_data.json in Resources */ = {isa = PBXBuildFile; fileRef = EA6DD69E1AB384C700CA3A5B /* big_data.json */; };
EA9159F61BDE74BC00D85292 /* Argo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5A41BBF2047001DE23B /* Argo.swift */; };
EA9159F71BDE74C700D85292 /* catDecoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8EF432E1BBC728A001886BA /* catDecoded.swift */; };
EA9159F81BDE74E400D85292 /* Monad.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5901BBF1F40001DE23B /* Monad.swift */; };
EA9159F91BDE74EB00D85292 /* Functor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA04D5941BBF1F80001DE23B /* Functor.swift */; };
Expand All @@ -135,7 +129,6 @@
EABDF6921A9CD4EA00B6CC83 /* types.plist in Resources */ = {isa = PBXBuildFile; fileRef = EABDF68E1A9CD4EA00B6CC83 /* types.plist */; };
EABDF6941A9CD4FC00B6CC83 /* PListDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6931A9CD4FC00B6CC83 /* PListDecodingTests.swift */; };
EABDF6951A9CD4FC00B6CC83 /* PListDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6931A9CD4FC00B6CC83 /* PListDecodingTests.swift */; };
EAD9FAF619D0F7900031E006 /* DecodeOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */; };
EAD9FAFE19D2113C0031E006 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAFD19D2113C0031E006 /* User.swift */; };
EAD9FB0019D211630031E006 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAFF19D211630031E006 /* Comment.swift */; };
EAD9FB0219D211C10031E006 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FB0119D211C10031E006 /* Post.swift */; };
Expand Down Expand Up @@ -185,7 +178,6 @@
F893355F1A4CE83000B88685 /* Argo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F89335541A4CE83000B88685 /* Argo.framework */; };
F893356E1A4CE8FC00B88685 /* Argo.h in Headers */ = {isa = PBXBuildFile; fileRef = F893356D1A4CE8FC00B88685 /* Argo.h */; settings = {ATTRIBUTES = (Public, ); }; };
F893356F1A4CE8FC00B88685 /* Argo.h in Headers */ = {isa = PBXBuildFile; fileRef = F893356D1A4CE8FC00B88685 /* Argo.h */; settings = {ATTRIBUTES = (Public, ); }; };
F89335761A4CE93600B88685 /* DecodeOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */; };
F8ABEBD11D42C67100B4363C /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8ABEBD01D42C67100B4363C /* Runes.framework */; };
F8ABEBD31D42C67800B4363C /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8ABEBD21D42C67800B4363C /* Runes.framework */; };
F8ABEBD51D42C67E00B4363C /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8ABEBD41D42C67E00B4363C /* Runes.framework */; };
Expand Down Expand Up @@ -293,7 +285,6 @@
EA04D5981BBF1FA4001DE23B /* Applicative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Applicative.swift; sourceTree = "<group>"; };
EA04D59C1BBF1FB9001DE23B /* Alternative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alternative.swift; sourceTree = "<group>"; };
EA04D5A01BBF2021001DE23B /* FailureCoalescing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureCoalescing.swift; sourceTree = "<group>"; };
EA04D5A41BBF2047001DE23B /* Argo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Argo.swift; sourceTree = "<group>"; };
EA08313019D5EEAF003B90D7 /* TypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeTests.swift; sourceTree = "<group>"; };
EA08313219D5EEF2003B90D7 /* post_comments.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = post_comments.json; sourceTree = "<group>"; };
EA08313419D5EFC0003B90D7 /* types.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = types.json; sourceTree = "<group>"; };
Expand All @@ -317,7 +308,6 @@
EAD9FACF19D0EAB50031E006 /* Argo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Argo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EAD9FAD319D0EAB50031E006 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
EAD9FADA19D0EAB60031E006 /* ArgoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ArgoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodeOperators.swift; sourceTree = "<group>"; };
EAD9FAFD19D2113C0031E006 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
EAD9FAFF19D211630031E006 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = "<group>"; };
EAD9FB0119D211C10031E006 /* Post.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -477,7 +467,6 @@
isa = PBXGroup;
children = (
F87EB69D1ABC5F1300E3B0AB /* Types */,
EAD9FAE919D0F6480031E006 /* Operators */,
F87EB6981ABC5F1300E3B0AB /* Functions */,
F8CBE6651A6451F800316FBC /* Extensions */,
);
Expand Down Expand Up @@ -506,15 +495,6 @@
path = Resources;
sourceTree = "<group>";
};
EAD9FAE919D0F6480031E006 /* Operators */ = {
isa = PBXGroup;
children = (
EA04D5A41BBF2047001DE23B /* Argo.swift */,
EAD9FAF519D0F7900031E006 /* DecodeOperators.swift */,
);
path = Operators;
sourceTree = "<group>";
};
EAD9FAFC19D2110D0031E006 /* Models */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -992,7 +972,6 @@
809754DB1BADF36D00C409E6 /* StandardTypes.swift in Sources */,
EA9159F91BDE74EB00D85292 /* Functor.swift in Sources */,
809754DA1BADF36D00C409E6 /* Decodable.swift in Sources */,
809754DE1BADF36D00C409E6 /* DecodeOperators.swift in Sources */,
809754D81BADF36D00C409E6 /* Decoded.swift in Sources */,
809754E41BADF36D00C409E6 /* sequence.swift in Sources */,
809754E21BADF36D00C409E6 /* decode.swift in Sources */,
Expand All @@ -1002,7 +981,6 @@
809754E61BADF36D00C409E6 /* RawRepresentable.swift in Sources */,
809754D91BADF36D00C409E6 /* JSON.swift in Sources */,
F8C2561C1C3C855C00B70968 /* NSNumber.swift in Sources */,
EA9159F61BDE74BC00D85292 /* Argo.swift in Sources */,
EA9159FB1BDE74F800D85292 /* Alternative.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1049,12 +1027,10 @@
F84318AA1B9A2D7A00165216 /* DecodeError.swift in Sources */,
D0592EBF1B77DD8E00EFEF39 /* JSON.swift in Sources */,
F8EF43311BBC729F001886BA /* catDecoded.swift in Sources */,
D0592EC31B77DD9300EFEF39 /* DecodeOperators.swift in Sources */,
EA1200CE1BAB621C006DDBD8 /* RawRepresentable.swift in Sources */,
EA04D5931BBF1F40001DE23B /* Monad.swift in Sources */,
EA04D5971BBF1F80001DE23B /* Functor.swift in Sources */,
D0592EC71B77DD9A00EFEF39 /* sequence.swift in Sources */,
EA04D5A71BBF2047001DE23B /* Argo.swift in Sources */,
D0592EC61B77DD9A00EFEF39 /* flatReduce.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -1076,11 +1052,9 @@
F87EB6A81ABC5F1300E3B0AB /* sequence.swift in Sources */,
F84318A81B9A2D7A00165216 /* DecodeError.swift in Sources */,
F8CBE6671A64521000316FBC /* Dictionary.swift in Sources */,
EAD9FAF619D0F7900031E006 /* DecodeOperators.swift in Sources */,
F87EB6B01ABC5F1300E3B0AB /* StandardTypes.swift in Sources */,
EA04D5911BBF1F40001DE23B /* Monad.swift in Sources */,
EA04D5951BBF1F80001DE23B /* Functor.swift in Sources */,
EA04D5A51BBF2047001DE23B /* Argo.swift in Sources */,
F8EF432F1BBC728A001886BA /* catDecoded.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1128,12 +1102,10 @@
F84318A91B9A2D7A00165216 /* DecodeError.swift in Sources */,
F8CBE6681A64526300316FBC /* Dictionary.swift in Sources */,
F8EF43301BBC729F001886BA /* catDecoded.swift in Sources */,
F89335761A4CE93600B88685 /* DecodeOperators.swift in Sources */,
EA1200CD1BAB621C006DDBD8 /* RawRepresentable.swift in Sources */,
EA04D5921BBF1F40001DE23B /* Monad.swift in Sources */,
EA04D5961BBF1F80001DE23B /* Functor.swift in Sources */,
F87EB6B11ABC5F1300E3B0AB /* StandardTypes.swift in Sources */,
EA04D5A61BBF2047001DE23B /* Argo.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Sources/Argo/Functions/decode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public func decode<T: Decodable>(_ object: Any) -> T? where T == T.DecodedType {
- returns: A `Decoded<T>` value where `T` is `Decodable`
*/
public func decode<T: Decodable>(_ dict: [String: Any], rootKey: String) -> Decoded<T> where T == T.DecodedType {
return JSON(dict as Any) <| rootKey
return JSON(dict as Any)[rootKey]
}

/**
Expand Down
10 changes: 0 additions & 10 deletions Sources/Argo/Operators/Argo.swift

This file was deleted.

78 changes: 0 additions & 78 deletions Sources/Argo/Operators/DecodeOperators.swift

This file was deleted.

47 changes: 47 additions & 0 deletions Sources/Argo/Types/JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,53 @@ public extension JSON {
}
}

extension JSON {
/**
Attempt to extract a value at the specified key path and transform it into
the requested type.
This method is used to decode a mandatory value from the `JSON`. If the
decoding fails for any reason, this will result in a `.Failure` being
returned.
- parameter keyPath: The key path for the object to decode, represented by
a variadic list of strings.
- returns: A `Decoded` value representing the success or failure of the
decode operation
*/
public subscript<T: Decodable>(keyPath: String...) -> Decoded<T> where T == T.DecodedType {
return flatReduce(keyPath, initial: self, combine: decodedJSON)
.flatMap(T.decode)
}

/**
Attempt to extract an optional value at the specified key path and
transform it into the requested type.
This method is used to decode an optional value from the `JSON`. If any of
the keys in the key path aren't present in the `JSON`, this will still return
`.success`. However, if the key path exists but the object assigned to the
final key is unable to be decoded into the requested type, this will return
`.failure`.
- parameter keyPath: The key path for the object to decode, represented by
a variadic list of strings.
- returns: A `Decoded` optional value representing the success or failure
of the decode operation
*/
public subscript<T: Decodable>(optional keyPath: String...) -> Decoded<T?> where T == T.DecodedType {
switch flatReduce(keyPath, initial: self, combine: decodedJSON) {
case .failure:
return .success(.none)

case let .success(x):
return T.decode(x)
.flatMap { .success(.some($0)) }
}
}
}

extension JSON: Decodable {
/**
Decode `JSON` into `Decoded<JSON>`.
Expand Down
4 changes: 2 additions & 2 deletions Tests/ArgoTests/Models/Booleans.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct Booleans: Argo.Decodable {

static func decode(_ json: JSON) -> Decoded<Booleans> {
return curry(Booleans.init)
<^> json <| "realBool"
<*> json <| "numberBool"
<^> json["realBool"]
<*> json["numberBool"]
}
}
6 changes: 3 additions & 3 deletions Tests/ArgoTests/Models/Comment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ struct Comment {
extension Comment: Argo.Decodable {
static func decode(_ json: JSON) -> Decoded<Comment> {
return curry(self.init)
<^> json <| "id"
<*> json <| "text"
<*> json <| ["author", "name"]
<^> json["id"]
<*> json["text"]
<*> json["author", "name"]
}
}
24 changes: 12 additions & 12 deletions Tests/ArgoTests/Models/Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ struct Post {
extension Post: Argo.Decodable {
static func decode(_ json: JSON) -> Decoded<Post> {
return curry(self.init)
<^> json <| "id"
<*> json <| "text"
<*> json <| "author"
<*> json <| "comments"
<^> json["id"]
<*> json["text"]
<*> json["author"]
<*> json["comments"]
}
}

Expand All @@ -30,11 +30,11 @@ struct LocationPost {
extension LocationPost: Argo.Decodable {
static func decode(_ json: JSON) -> Decoded<LocationPost> {
return curry(self.init)
<^> json <| "id"
<*> json <| "text"
<*> json <| "author"
<*> json <| "comments"
<*> json <|? "location"
<^> json["id"]
<*> json["text"]
<*> json["author"]
<*> json["comments"]
<*> json[optional: "location"]
}
}

Expand All @@ -47,8 +47,8 @@ struct Location {
extension Location: Argo.Decodable {
static func decode(_ json: JSON) -> Decoded<Location> {
return curry(self.init)
<^> json <| "lat"
<*> json <| "lng"
<*> json <| "title"
<^> json["lat"]
<*> json["lng"]
<*> json["title"]
}
}
Loading

0 comments on commit 40f2e2e

Please sign in to comment.