Does Swift have short-circuiting higher-order functions like Any or All? - swift

I'm aware of Swift's higher-order functions like Map, Filter, Reduce and FlatMap, but I'm not aware of any like 'All' or 'Any' which return a boolean that short-circuit on a positive test while enumerating the results.
For instance, consider you having a collection of 10,000 objects, each with a property called isFulfilled and you want to see if any in that collection have isFulfilled set to false. In C#, you could use myObjects.Any(obj -> !obj.isFulfilled) and when that condition was hit, it would short-circuit the rest of the enumeration and immediately return true.
Is there any such thing in Swift?

Sequence (and in particular Collection and Array) has a (short-circuiting) contains(where:) method taking a boolean predicate as argument. For example,
if array.contains(where: { $0 % 2 == 0 })
checks if the array contains any even number.
There is no "all" method, but you can use contains() as well
by negating both the predicate and the result. For example,
if !array.contains(where: { $0 % 2 != 0 })
checks if all numbers in the array are even. Of course you can define a custom extension method:
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
return !contains(where: { !predicate($0) } )
}
}
If you want to allow "throwing" predicates in the same way as the
contains method then it would be defined as
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
return try !contains(where: { try !predicate($0) } )
}
}
Update: As James Shapiro correctly noticed, an allSatisfy method has been added to the Sequence type in Swift 4.2 (currently in beta), see
SE-0027 Add an allSatisfy algorithm to Sequence
(Requires a recent 4.2 developer snapshot.)

One other thing that you can do in Swift that is similar to "short circuiting" in this case is to use the lazy property of a collection, which would change your implementation to something like this:
myObjects.lazy.filter({ !$0.isFulfilled }).first != nil
It's not exactly the same thing you're asking for, but might help provide another option when dealing with these higher-order functions. You can read more about lazy in Apple's docs. As of this edit the docs contain the following:
var lazy: LazyCollection> A view onto this collection
that provides lazy implementations of normally eager operations, such
as map and filter.
var lazy: LazySequence> A sequence containing the same
elements as this sequence, but on which some operations, such as map
and filter, are implemented lazily.

If you had all the objects in that array, they should conform to some protocol, which implements the variable isFulfilled... as you can see, you could make these objects confrom to (let's call it fulFilled protocol)... Now you can cast that array into type [FulfilledItem]... Now you can continue as usually
I am pasting code here for your better understanding:
You see, you cannot extend Any or AnyObject, because AnyObject is protocol and cannot be extended (intended by Apple I guess), but you can ,,sublass" the protocol or as you like to call it professionally - Make protocol inheriting from AnyObject...
protocol FulfilledItem: AnyObject{
var isFulfilled: Bool {get set}
}
class itemWithTrueValue: FulfilledItem{
var isFulfilled: Bool = true
}
class itemWithFalseValue: FulfilledItem{
var isFulfilled: Bool = false
}
var arrayOfFulFilled: [FulfilledItem] = [itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue()]
let boolValue = arrayOfFulFilled.contains(where: {
$0.isFulfilled == false
})
Now we've got ourselves a pretty nice looking custom protocol inheriting all Any properties + our beautiful isFulfilled property, which we will handle now as usually...
According to apple docs:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342
AnyObject is only for reference types (classes), Any is for both value and reference types, so I guess it is prefered to inherit AnyObject...
Now you cast instead AnyObject into Array the protocol Item FulfilledItem and you will have beautiful solution (don't forget every item to conform to that protocol and set the value...)
Wish happy coding :)

Related

How does iOS 15 AttributeContainer function chaining work?

New in iOS 15, we can form a Swift AttributedString like this:
var att = AttributedString("Howdy")
att.font = UIFont(name:"Arial-BoldMT", size:15)
att.foregroundColor = UIColor(red:0.251, green:0.000, blue:0.502, alpha:1)
print(att)
Cool, but there's another way. Instead of successive imperative property setting, we can make an attribute dictionary by way of an AttributeContainer, chaining modifier functions to the AttributeContainer to form the dictionary:
let att2 = AttributedString("Howdy",
attributes: AttributeContainer()
.font(UIFont(name:"Arial-BoldMT", size:15)!)
.foregroundColor(UIColor(red:0.251, green:0.000, blue:0.502, alpha:1))
)
print(att2)
(In real life I'd say .init() instead of AttributeContainer().)
So my question is, how does this work syntactically under the hood? We seem to have here a DSL where we can chain what look like function calls based on the names of the attribute keys. Behind the scenes, there seems to be some combination of dynamic member lookup, callAsFunction, and perhaps some sort of intermediate builder object. I can see that every callAsFunction call is returning the AttributeContainer, which is clearly how the chaining works. But just how would we write our own object that behaves syntactically the way AttributeContainer behaves?
I've made DSLs in the past similar to this.
I can't verify this is exactly what they're doing, but I can describe the way I achieved a similar DSL syntax.
My builder object would have methods like .font and .color return a temporary #dynamicCallable struct. These structs would store their parent build (by analogy, the AttributeContainer), and the keypath they were called originated from (\.font, \.color, etc.). (I don't remember if I used proper keypaths or strings. I can check later and get back to you.)
The implementation of callAsFunction would look something like:
func callAsFunction(_ someParam: SomeType) -> AttributeContainer {
parent[keyPath: keyPath] = someParam
return parent // for further chaining in the fluent interface.
}
Subsequent calls such as .foregroundColor would then repeat that same process.
Here's a bare-bones example:
#dynamicMemberLookup struct DictBuilder<Value> {
struct Helper<Value> {
let key: String
var parent: DictBuilder<Value>
func callAsFunction(_ value: Value) -> DictBuilder<Value> {
var copy = parent
copy.dict[key] = value
return copy
}
}
var dict = [String: Value]()
subscript(dynamicMember key: String) -> Helper<Value> {
return DictBuilder.Helper(key: key, parent: self)
}
}
let dict = DictBuilder<Int>()
.a(1)
.b(2)
.c(3)
.dict
print(dict)
IIRC, you can some generic magic and keypaths (instead of strings) to return different type per keypath, whose callAsFunciton could require arguments of different type, which can be enforced at compile time.
You can use #dynamicCallable instead of #dynamicMemberLookup+callAsFunction, but I don't think worked with the trick I just mentioned.

Why is generic specialization lost inside a generic function

When I create a computed property that depends on a generic type, the specific implementation is "lost" when the instance is passed in a generic function.
For example, I added the isBool on Array that returns true if Array.Element is Bool:
extension Array {
var isBool: Bool {
false
}
}
extension Array where Element == Bool {
var isBool: Bool {
true
}
}
Using it directly on the instance works fine
let boolArray: [Bool] = [true, false]
let intArray: [Int] = [1, 0]
boolArray.isBool // true
intArray.isBool // false
But inside a generic function it always uses the non specialized implementation:
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
isBool(boolArray) // false, instead of true
isBool(intArray) // false
This is not a real use case so I don't really need a way to "fix" this, but I would like to understand why it behave like that.
Specialization is not a replacement for inheritance. It should be used to improve performance, not change behavior.
For example, distance(from:to:) is usually O(k), where k is the distance. For RandomAccessCollection it can be performed in O(1) due to a specialization. But the result is the same either way.
Specialization is done at compile-time based on the information the compiler has. In your example, the compiler can see that boolArray is a [Bool], and so it uses the specialized extension. But inside of isBool, all that the compiler knows is that array is an Array. It doesn't know when compiling the function what kind of Array will be passed. So it picks the more general version to cover all cases.
(The compiler may create multiple versions of isBool in the binary for optimization purposes, but luckily I haven't found any situations where this impacts what extensions or overloads are called. Even if it actually creates an inlined, Bool-specific version of isBool, it will still use the more general Array extension. That's a good thing.)
Leaving your extensions in place, the following would do what you expect (though I don't encourage this):
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
func isBool(_ array: [Bool]) -> Bool {
array.isBool
}
Now isBool is overloaded and the most specific one will be selected. Within the context of the second version, array is known to be [Bool], and so the more specialized extension will be selected.
Even though the above works, I would strongly recommend against using specialized extensions or ambiguous overloads that change behavior. It is fragile and confusing. If isBool() is called in the context of another generic method where Element is not known, it again may not work as you expect.
Since you want to base this on the runtime types, IMO you should query the type at runtime using is. That gets rid of all the ambiguity. For example:
extension Array {
var isBool: Bool { Element.self is Bool.Type }
}
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
You can make this much more flexible and powerful by adding a protocol:
protocol BoolLike {}
extension Array {
var isBool: Bool { Element.self is BoolLike.Type }
}
Now, any types you want to get "bool-like" behavior just need to conform:
extension Bool: BoolLike {}
This allows you all the flexibility of your extensions (i.e. the isBool code doesn't need to know all the types), while ensuring the behavior is applied based on runtime types rather than compile-time types.
Just in case it comes up, remember that protocols do not conform to themselves. So [BoolLike] would return isBool == false. The same is true for an extension with where Element: BoolLike. If you need that kind of thing to work, you need to deal with it explicitly.
extension Array {
var isBool: Bool {
Element.self is BoolLike.Type || Element.self == BoolLike.self
}
}

Generic Extension for Array in Swift

To be very frank, I am totally new to learn Extension creation and usage.
I wanted to create a category (Extension in swift 3.0) which can be used throughout an application to perform repeated operations for Array.
Sample Link 1
This is what I have seen and understand while doing research, I wanted to create an extension with various methods which should be generic, and not on the basis of datatype needed to create separate extensions.
Here in above example, we will need to create single extension if we will go for particular datatype wise extension. I wanted to have a guidance if any way is there to create the generic category (Extension in swift).
extension _ArrayType where Generator.Element == Int
extension Array where Element: Equatable
extension Array where Element == Int
extension _ArrayType where Generator.Element == Float
extension SequenceType where Self.Generator.Element: FloatingPointType
extension Array where Element: DoubleValue
extension Sequence where Iterator.Element == String
,etc...
Sample Link 2
Note : In short, we can consider that I want to perform actions based on Array in single extension instead of just creating the single extension for each of the datatypes as per above requirement.
As mentioned in the comments, one way to accomplish this is to create your own protocol that the types you want to cover adopt (in the comments someone called it Content, used below for this example) (from first source):
protocol Content {
var hash: String { get }
}
extension Array where Element : Content {
func filterWithId(id : String) -> [Element] {
return self.filter { (item) -> Bool in
return item.id == id
}
}
}
It seems, though, that the original question is mainly asking about generic extensions for arrays, which one comment says are not possible but 100% are possible in Swift (it's a big Swift feature, actually) (from second source).
For example, if you want to define a specific extension method for Ints only, you can do that:
extension Sequence where Iterator.Element == Int {
var sum: Int {
return reduce(0, +)
}
}
It seems like the question's original requirements are extension methods that could be agnostic to data type and therefore should be kept in common. If I understand correctly, seems though that these data types in general have some conformance to Equatable and/or Hashable, which is the minimum requirement for this kind of generic-stuff to work. With this element conformance, though, this is possible as such:
extension Sequence where Iterator.Element is Equatable {
func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
// T is now a generic array of equatable items. You can implement whatever extension logic you need with these.
// I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
}
}
The Swift syntax changes quickly, and what's here can quickly go out of date, but this guide is kept fairly up-to-date by Apple and shows the most up to date syntax for Generics used above ^.
My answer pulls from a couple StackOverflow questions/answers, used for example/syntax above ^. Source: (SO Source) (SO Source 2)
In summary, all the methods above can be combined, for a fully custom extension solution that has both generic functions/vars for all your Array types, while still having type-specific extension overrides.
In where clause, you specify "If the Element type has these rules, consider this extension".
You don't need to implement all of the methods in all extensions.
For example:
You want to extend Array<Element> to generally have method foo(_:Element):
extension Array {
func foo(bar: Element) { /*your code goes here */ }
}
You want to extend Array<Element> where Element did implement Equatable (which includes Int,Double and ... or any structs/classes you've marked as Equatable):
extension Array where Element: Equatable {
func find(value: Element) -> Bool {
return index(of: value) != nil
}
}
You want to extend Sequence in cases that Element is Numeric, have get-only variable sum:
extension Sequence where Element: Numeric {
var sum: Element {
return reduce(0, +)
}
}
You want to extend Collection<Collection<Element: Equatable>> to have a method to compare to 2D Collections:
extension Collection
where Iterator.Element: Collection,
Iterator.Element.Iterator.Element: Equatable {
func compare(to: Self) -> Bool {
let flattenSelf = self.reduce([], +)
let flattenTo = to.reduce([], +)
return flattenSelf.count == flattenTo.count &&
zip(flattenSelf, flattenTo).reduce(true) { $0 && $1.0 == $1.1 }
}
}
You don't need to extend Array or collection to have methods like sort, find, etc... Most of these methods are already extended inside the compiler if your Element: Equatable or Element: Comparable. using map, filter and reduce you can achieve more complex structures with not much of a code.

Extension for sequences of dictionaries where the values are Equatable

I tried to implement the following method to remove double entries in an array of dictionaries by comparing their specific keys. However, this extension method will not work due to the error:
Binary operator == cannot be applied to two 'Equatable' operands
These are obviously equatable and same type (Iterator.Element.Value), so why doesn't it work?
I see that it treats Equatable as a specific type, not a constraint. I could not make it work with generic type or by writing where Iterator.Element == [String: Any], Iterator.Element.Value: Equatable.
Do you guys have any clues about how to solve this?
extension Sequence where Iterator.Element == [String: Equatable] {
public func removeDoubles(byKey uniqueKey: String) -> [Iterator.Element] {
var uniqueValues: [Iterator.Element.Value] = []
var noDoubles: [Iterator.Element] = []
for item in self {
if let itemValue = item[uniqueKey] {
if (uniqueValues.contains { element in
return itemValue == element
}) {
uniqueValues.append(itemValue)
noDoubles.append(item)
}
}
}
return noDoubles
}
}
A [String: Equatable] is a mapping of strings to any Equatable type. There is no promise that each value be the same equatable type. That said, it's not actually possible to create such a dictionary (since Equatable has an associated type), so this extension cannot apply to any actual type in Swift. (The fact that you don't receive an error here is IMO a bug in the compiler.)
The feature you'd need to make this work is SE-0142, which is accepted, but not implemented. You currently cannot constrain an extension based on type constraints this way.
There are many ways to achieve what you're trying to do. One straightforward way is to pass your equality function:
extension Sequence {
public func removeDoubles(with equal: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] {
var noDoubles: [Iterator.Element] = []
for item in self {
if !noDoubles.contains(where: { equal($0, item) }) {
noDoubles.append(item)
}
}
return noDoubles
}
}
let noDupes = dict.removeDoubles(with: { $0["name"] == $1["name"] })
This is slightly different than your code in how it behaves when name is missing, but slight tweaks could get what you want.
That said, the need for this strongly suggests an incorrect data model. If you have this sequence of dictionaries, and you're trying to build an extension on that, you almost certainly meant to have a sequence of structs. Then this becomes more straightforward. The point of a dictionary is an arbitrary mapping of keys to values. If you have a small set of known keys that are legal, that's really a struct.

Check if a type implements a protocol

I am writing a library that creates extensions for default Swift types.
I would like to have a check on my Array extensions whether a certain type implements a certain protocol. See this method for example:
extension Array {
/// Compares the items using the given comparer and only returns non-equal values
/// :returns: the first items that are unique according to the comparer
func distinct(comparer: (T, T) -> Bool) -> [T] {
var result: [T] = []
outerLoop: for item in self {
for resultItem in result {
if comparer(item, resultItem) {
continue outerLoop
}
}
result.append(item)
}
return result
}
}
Now I'd like to rewrite this method to check if T is Equatable as such:
/// Compares the items using the given comparer and only returns non-equal values
/// :returns: the first items that are unique according to the comparer
func distinct(comparer: ((T, T) -> Bool)?) -> [T] {
var result: [T] = []
outerLoop: for item in self {
for resultItem in result {
if isEquatable ? comparer!(item, resultItem) : item == resultItem {
continue outerLoop
}
}
result.append(item)
}
return result
}
where isEquatable is a Bool value that tells me if T is Equatable. How can I find this out?
There isn’t a good way to do this in Swift at the moment.* This is why functions like sorted are either free-functions, or in the case of the member, take a predicate. The main problem with the test-and-cast approach you’re looking for is that Equatable and similar protocols have an associated type or rely on Self, and so can only be used inside a generic function as a constraint.
I’m guessing your goal is that the caller can skip supplying the comparator function, and so it will fall back to Equatable if available? And crash if it isn’t? The problem here is that the function is determining something at run time (the argument is Equatable) when this really ought to be determinable at compile time. This is not great - it’s much better to determine these things fully at compile time.
So you can write a free function that requires Equatable:
func distinct<C: CollectionType where C.Generator.Element: Equatable>
(source: C) -> [C.Generator.Element] {
var seen: [C.Generator.Element] = []
return filter(source) {
if contains(seen, $0) {
return false
}
else {
seen.append($0)
return true
}
}
}
let uniques = distinct([1,2,3,1,1,2]) // [1,2,3]
and then if you tried to call it with something that wasn’t comparable, you’d get a compile-time error:
let incomparable = [1,2,3] as [Any]
distinct(incomparable) // compiler barfs - Any isn’t Equatable
With the runtime approach, you’d only find this out when you ran the program.
The good news is, there are upsides too. The problem with searching an array for each element is the function will be very slow for large arrays, because for every element, the list of already-seen elements must be searched linearly. If you overload distinct with another version that requires the elements be Hashable (which Equatable things often are), you can use a set to track them:
func distinct<C: CollectionType where C.Generator.Element: Hashable>
(source: C) -> [C.Generator.Element] {
var seen: Set<C.Generator.Element> = []
return filter(source) {
if seen.contains($0) {
return false
}
else {
seen.insert($0)
return true
}
}
}
At compile time, the compiler will choose the best possible version of the function and use that. If your thing is hashable, that version gets picked, if it’s only equatable, it’ll use the slower one (this is because Hashable inherits from Equatable, and the compiler picks the more specialized function). Doing this at compile time instead of run time means you pay no penalty for the check, it’s all determined up front.
*there are ugly ways, but since the goal is appealing syntax, what’s the point… Perhaps the next version will allow constraints on methods, which would be nice.