using functions in swift - swift

I'm new to programming. Please tell me what is wrong in this code! Why am I getting the output "(Function)"?
//first function
func admit(person: String) -> String {
return("\(person) can go")
}
//second function
func deny(person: String) -> String {
return("\(person) can not go")
}
//third function
func screen(onGuestList: String, person: String) -> (String) -> String {
if onGuestList == "yes"{
return admit(person:)
} else {
return deny(person:)
}
}
var outcome = screen(onGuestList: "yes", person: "Sapinder")
print(outcome)
I expect the output of "(person) can go", but the actual output is "(Function)".

Why am I getting the output "(Function)"?
because screen function is not returning a String, it returns (String) -> String instead.
Simply, the fix for it is to implement screen as:
func screen(onGuestList: String, person: String) -> String {
if onGuestList == "yes"{
return admit(person: person)
} else {
return deny(person: person)
}
}
so what is the difference here? Well, first of all now it returns a string instead of a function that takes a string and returns a string. Also, for calling admit and deny you have to mention the label (person) to pass a parameter to them.
Unrelated tip:
func screen(onGuestList: String, person: String) -> String {
return onGuestList == "yes" ? admit(person: person) : deny(person: person)
}
preferably, try to name the functions as verbs instead of nouns, we usually do this for properties (fields) but not methods (behaviors). For example: displayScreen instead of screen.
So what's the meaning of returning (String) -> String?
Briefly, Swift does allow such a thing. Consider the following example:
func sayHello() -> (String) -> String {
let functionToReturn: (String) -> String = { name in
return "Hello \(name)"
}
return functionToReturn
}
func takeMy(function: (String) -> String, name: String) {
print("I am about to print the function:")
print(function(name))
}
takeMy(function: sayHello(), name: "Sappie")
// I am about to print the function:
// Hello Sappie
as you can see, takeMy function is that takes another function as a parameter of type (String) -> String, therefore we passed sayHello() for it since it's signature matches the parameter type.
As a real world example, you could find many methods that parameters as functions when working with collections (for instance). As an example, the filter method:
func returnMoreThanfive(element: Int) -> Bool {
return element > 5
}
let array = [1,2,3,4,5,6,7,8,9]
let filteredArray = array.filter(returnMoreThanfive)
// [6, 7, 8, 9]
we passed to filter a function that takes an element and returns a boolean. Keep in mind It's just an example to make it more clear to you, however we usually do like this:
let filteredArray = array.filter { $0 > 5 }

Try
func admit(person: String) -> String {
return("\(person) can go")
}
//second function
func deny(person: String) -> String {
return("\(person) can not go")
}
//third function
func screen(onGuestList: String, person: String) -> String {
if onGuestList == "yes"{
return admit(person: person)
} else {return deny(person: person)
}
}
var outcome = screen(onGuestList: "yes", person: "Sapinder")
print(outcome)
What you were doing were returning a (String) -> String instead of String
In swift you can return a Function as a return type

Related

How to return Observable<String> based on the conditions of Observable<Bool> RxSwift

I'm quite new to RxSwift.
Is there any way I can create a function that will return Observable based on the conditions of two functions below
func isValidPassword(_ str: PublishSubject<String>) -> Observable<Bool> {
return str.asObservable().map {
validator.isValidPasswordRegex($0) && $0.count >= 8
}
}
func isNotEmpty(_ str: PublishSubject<String>) -> Observable<Bool> {
return str.asObservable().map {
$0.count != 0
}
}
This code below is just an example of what I'm trying to achieve, hoped you got the idea.
func someFunc(_ str:PublishSubject<String>) -> Observable<String> {
if !isValidPassword(str){
return "Not a valid password" //should return as an observable string
}
if isNotEmpty(str){
return "String is not empty" //should return as an observable string
}
}
I'm not sure about what you want to achieve here but I think you should use filter operator and not map. In this way you don't change the type of the starting observable but you remove elements that don't respect your conditions.
func isValidPassword(_ str: String) -> Bool {
validator.isValidPasswordRegex(str) && str.count >= 8
}
func someFunc(_ str: PublishSubject<String>) -> Observable<String> {
str
.filter(isValidPassword)
.filter { !$0.isEmpty }
}
Let me introduce you to zip... It allows you to combine multiple Observables.
func someFunc(_ str: Observable<String>) -> Observable<String> {
Observable.zip(isValidPassword(str), isNotEmpty(str))
.map { isValidPassword, isNotEmpty -> String in
if !isValidPassword {
return "Not a valid password"
}
if isNotEmpty {
return "String is not empty"
}
return "" // you didn't specify what it should return here...
}
}
Note that I updated the type signatures of your existing functions:
func isValidPassword(_ str: Observable<String>) -> Observable<Bool>
func isNotEmpty(_ str: Observable<String>) -> Observable<Bool>
Passing Subjects around like that is a recipe for disaster.
Subjects provide a convenient way to poke around Rx, however they are not recommended for day to day use.
-- Introduction to Rx
UPDATE
I think the code would be better if you implemented like this though:
func errorMessage(text: Observable<String>) -> Observable<String> {
text.map(errorMessage)
}
func errorMessage(_ str: String) -> String {
if !isValidPassword(str) {
return "Not a valid password"
}
if isNotEmpty(str) {
return "String is not empty"
}
return ""
}
func isValidPassword(_ str: String) -> Bool
func isNotEmpty(_ str: String) -> Bool
It's much easier to test this way.

Typescript Generic chained function to Swift

I'm really struggling to comprehend how to (if even possible) to convert a generics function written in Typescript into something I can use in Swift.
export type Filter<T> = (value: T) => boolean
export function isKeyEqualToValue<T>(key: keyof T) {
return function (value: T[keyof T]): Filter<T> {
return (object: T) => object[key] === value
}
}
isKeyEqualToValue<T>('key')(someObject.key)
const filters = userFilters.map(userFilterSet => isEvery(buildAlertFilter(userFilterSet)))
const isMatch = isAny(filters)
return flow.reduce((feed: String[], obj: SomeType) => {
if (!isMatch(obj)) return feed
return [
...feed,
{
...obj
},
]
}, [])
}
I would like to be able to input a struct model in for T and check if the inputted value matches the key. Would greatly appreciate some guidance here!
EDIT:
I've added how the method is being called and used. Essentially I'm trying to avoid doing an algorithm O(n)^2 and so I'm trying to build a list of filters based on our user's choice. Then cross check the bulk of my data (SomeType) with those built filters.
I'm working to translate another function using the similar principles.
export function hasInArray<T>(key: keyof T) {
return function (values: Array<any>): Filter<T> {
return (object: T) => values.includes((object[key] as unknown) as string)
}
}
This is what I have so far.
func notInArray<Root, Value>(for keyPath: KeyPath<Root, Value>) -> (Array<Any>) -> Filter<Root, Value> {
{ values in { object in !values.contains(where: object[keyPath: keyPath]) } } }
You haven't given how you expect to use this, so I need to make some assumptions. I'm assuming the TypeScript that calls this looks like this:
interface Person {
name: string;
age: number;
}
const key: keyof Person = "name";
const nameTester = isKeyEqualToValue(key);
const person = {name: "Alice", age: 23};
const result = nameTester("Alice")(person);
The equivalent to TypeScript's keyof in Swift is KeyPath. Keeping this as close to the TypeScript syntax as possible to make it easier to see how it maps, this would look like:
typealias Filter<T> = (_ value: T) -> Bool
func isKeyEqualToValue<T, Value>(key: KeyPath<T, Value>) -> (Value) -> (T) -> Bool
where Value: Equatable
{
return { (value: Value) -> Filter<T> in
return { (object: T) in object[keyPath: key] == value }
}
}
struct Person: Equatable {
var name: String
var age: Int
}
let key = \Person.name
let nameTester = isKeyEqualToValue(key: key)
let person = Person(name: "Alice", age: 23)
let result = nameTester("Alice")(person)
To make it better Swift (rather than matching the TypeScript so closely), it would look like:
typealias Filter<Root, Value: Equatable> = (Value) -> (Root) -> Bool
func isEqualToValue<Root, Value>(for keyPath: KeyPath<Root, Value>) -> Filter<Root, Value>
{
{ value in { object in object[keyPath: keyPath] == value } }
}
let nameTester = isEqualToValue(for: key)
Your second example is like the first.
func hasInArray<Root, Values>(for keyPath: KeyPath<Root, Values>) -> (Values.Element) -> (Root) -> Bool
where Values: Sequence, Values.Element: Equatable
{
{ value in { object in object[keyPath: keyPath].contains(value) } }
}
You will almost never want Array<Any>. You need an array of the specific element. But in this case you don't need an array at all; you just need any Sequence.
All this said, I wouldn't do it this way. I think it's much easier to understand if you create a Filter type to manage it.
// A Filter object over a specific Target object (for example, a Person)
struct Filter<Target> {
let passes: (Target) -> Bool
}
// Filters can be created many ways
extension Filter {
// By properties equal to a value
static func keyPath<Value>(_ keyPath: KeyPath<Target, Value>, equals value: Value) -> Filter
where Value: Equatable
{
Filter { target in
target[keyPath: keyPath] == value
}
}
// By properties containing a value
static func keyPath<Seq>(_ keyPath: KeyPath<Target, Seq>, contains value: Seq.Element) -> Filter
where Seq: Sequence, Seq.Element: Equatable
{
Filter { target in
target[keyPath: keyPath].contains(value)
}
}
// By a property being a member of a sequence
static func keyPath<Seq>(_ keyPath: KeyPath<Target, Seq.Element>, isElementOf seq: Seq) -> Filter
where Seq: Sequence, Seq.Element: Equatable
{
Filter { target in
seq.contains(target[keyPath: keyPath])
}
}
// By combining other filters
static func all(of filters: [Filter]) -> Filter {
Filter { target in
filters.allSatisfy { filter in filter.passes(target) }
}
}
}
struct Person {
var name: String
var age: Int
var children: [String]
}
let filter: Filter<Person> = .all(of: [
.keyPath(\.name, equals: "Alice"),
.keyPath(\.children, contains: "Bob"),
.keyPath(\.age, isElementOf: [23, 43]),
])
let alice = Person(name: "Alice", age: 23, children: ["Bob"])
let shouldInclude = filter.passes(alice) // true

Swift Generic Functions, Protocols and associatedType - Cannot invoke function with an argument list of type '(from: T)'

I am trying to generalise a functions for different types of objects that does the same things (retrieves a value from the objects using a keyPath).
class GenericOutputParameter<Type>: Equatable {
// Single Line Parameter for the Deal parameters
var path: WritableKeyPathApplicator<Type>
var label: String
var value: Any? // THIS IS OPTIONAL
var format: Int
var columnID: String
var order: Int
init(path: WritableKeyPathApplicator<Type>, label: String, value: Any?, format: Int, order: Int, columnID: String) {
self.path = path
self.label = label
self.value = value
self.format = format
self.order = order
self.columnID = columnID
}
}
protocol haveOutputs {
associatedtype containerType
var dictionary: [String : (path: WritableKeyPathApplicator<containerType>,label: String, value: Any, format: Int, order: Int)] { get set }
var outputs: [GenericOutputParameter<containerType>] { get set }
}
func fillOutputs<T: haveOutputs>(container: inout T) {
container.outputs.removeAll()
for (columnID, valueTuple) in container.dictionary {
container.outputs.append(GenericOutputParameter(path: valueTuple.path, label: valueTuple.label, value: valueTuple.path.retrieve(from: container), format: valueTuple.format,order: valueTuple.order, columnID: columnID))
}
container.outputs.sort(by: { $0.order < $1.order })
} // END OF FILLOUTPUTS
I am using associatedType in the protocol as each object has its own different dictionary.
The function fillOutputs(container: inout T) retrieves the value from the object for the parameter specified by the key paths and appends it to an array.
I am getting an error in the container.outputs.append line towards the end of the code, as follows: Cannot invoke 'retrieve' with an argument list of type '(from: T)'. This refers to retrieve(from: container). Before attempting to generalise, this function was a method of each object (container) and using retrieve(from: self) worked.
For reference, the retrieve method is part of another generic function:
class WritableKeyPathApplicator<Type> {
private let applicator: (Type, Any) -> Type
private let retriever: (Type) -> Any
init<ValueType>(_ keyPath: WritableKeyPath<Type, ValueType>) {
applicator = {
...
}
retriever = {
...
}
}
func apply(value: Any, to: Type) -> Type {
return applicator(to, value)
}
func retrieve(from: Type) -> Any {
return retriever(from)
}
}
Given I am not an expert on Swift nor fully comprehend protocols, I may have lost myself in a glass of water and I would appreciate any thought/help. Thanks

How to use buildExpression in Swift 5.2 Function Builders?

I understand that it's a draft proposal. I tried to implement a simple DSL for building a string, like so:
#_functionBuilder
struct StringBuilder {
static func buildExpression(_ string: String) -> [String] {
[string]
}
static func buildBlock(_ children: [String]...) -> [String] {
children.flatMap{ $0 }
}
}
func s(separator: String = "", #StringBuilder _ makeString: () -> [String]) -> String {
makeString().joined(separator: separator)
}
let z = s(separator: " ") {
"this"
"is"
"cool"
}
However, the compiler complains that "'String' is not convertible to '[String]'". This leads me to believe that buildBlock is the only part of the proposal currently implemented. (This is understandable given that in SwiftUI they are building a hierarchy of views, so that's all they need.)
Is this correct or am I doing something wrong? What is the correct way to use buildExpression?
ielyamani's answer shows how to build a working string builder such as I used in my example above. However, that does not solve the actual problem. I'm not trying to build a string builder. I'm trying to figure out function builders. The string builder is just an example. For example, if we wish to have a string builder that accepts integers, we could in theory do the following:
#_functionBuilder
struct StringBuilder {
static func buildExpression(_ int: Int) -> [String] {
["\(int)"]
}
// The rest of it implemented just as above
}
In this case, when the compiler encountered an Int, it would call buildExpression to then spit out our component type, in this case [String]. But as Martin R said in a comment to this question, buildExpression is not currently implemented.
I encountered the same issue today, it seems that buildExpression isn't implemented. I ended up making a workaround by using a protocol "ComponentProtocol" and then creating "Expression: ComponentProtocol" and "Component: ComponentProtocol". That works for me for now. I am hoping it'll be implemented later.
protocol ComponentProtocol: ExpressibleByIntegerLiteral, ExpressibleByStringLiteral {
var value: String { get }
}
struct Expression: ComponentProtocol {
let _value: String
var value: String { _value }
init(_ value: String) { _value = value }
init(integerLiteral value: Int) { self.init(value) }
init(stringLiteral value: String) { self.init(value) }
init<E: CustomStringConvertible>(_ value: E) {_value = String(describing: value) }
}
struct Component: ComponentProtocol {
let _values: [String]
var value: String { _values.joined(separator: ", ") }
init(integerLiteral value: Int) { self.init(value) }
init(stringLiteral value: String) { self.init(value) }
init<E: CustomStringConvertible>(_ value: E) { _values = [String(describing: value)] }
init<T: ComponentProtocol>(_ values: T...) { _values = values.map { $0.value } }
init<T: ComponentProtocol>(_ values: [T]) { _values = values.map { $0.value } }
}
#_functionBuilder struct StringReduceBuilder {
static func buildBlock<T: ComponentProtocol>(_ components: T ...) -> Component { Component(components) }
static func buildEither<T: ComponentProtocol>(first: T) -> Component { Component(first.value) }
static func buildEither<T: ComponentProtocol>(second: T) -> Component { Component(second.value) }
static func buildOptional<T: ComponentProtocol>(_ component: T?) -> Component? {
component == nil ? nil : Component(component!.value)
}
}
func stringsReduce (#StringReduceBuilder block: () -> Component) -> Component {
return block()
}
let result = stringsReduce {
Expression(3)
"one"
Expression(5)
Expression("2")
83
}
let s2 = stringsReduce {
if .random () { // random value Bool
Expression(11)
} else {
Expression("another one")
}
}
Since buildBlock(_:) takes a variadic number of arrays of strings, this would work:
let z = s(separator: " ") {
["this"]
["is"]
["cool"]
}
But that's still clunky. To take strings instead of Arrays of strings, add this function to StringBuilder which takes a variable number of strings:
static func buildBlock(_ strings: String...) -> [String] {
Array(strings)
}
And now you can do this:
let z = s(separator: " ") {
"Hello"
"my"
"friend!"
}
print(z) //Hello my friend!

Swift generics: return type based on parameter type

Say I have a collection of objects inheriting from a common superclass (this is preferable to protocols in this case):
class ObjectSuperClass {
type: ObjectType
}
class ObjectClass1: ObjectSuperClass {
type = .Type1
}
class ObjectClass2: ObjectSuperClass {
type = .Type2
}
I'm looking to create a generic search function like this:
func objectsOfType<T: ObjectSuperClass>(T.class, otherFilter: Any?) -> [T]
Which could be used to search for a given sub-type, returning a more specific array of results:
let result = objectsOfType(ObjectClass2.class, otherFilter: nil) -> [ObjectClass2]
(pseudo-swift)
I feel like this is somewhere generics could help, but cannot see where constraints should be placed. Is it possible?
Well remarkably this works...
func filterType<T>(list: [AnyObject]) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }
}
...provided you assign the result to something that has been explicitly typed, as in the following example:
class ObjectSuperClass: CustomStringConvertible
{
let myType: String
init(aString: String)
{
myType = aString
}
var description: String { return myType }
}
class ObjectClass1: ObjectSuperClass
{
init()
{
super.init(aString: "<t 1>")
}
}
class ObjectClass2: ObjectSuperClass
{
init()
{
super.init(aString: "<t 2>")
}
}
let unfilteredList: [AnyObject] = [ ObjectClass1(), ObjectClass2(), ObjectSuperClass(aString: "<Who knows>")]
let filteredList1: [ObjectClass1] = filterType(list: unfilteredList)
print("\(filteredList1)") // <t 1>
let filteredList2: [ObjectClass2] = filterType(list: unfilteredList)
print("\(filteredList2)") // <t 2>
let filteredList3: [ObjectSuperClass] = filterType(list: unfilteredList)
print("\(filteredList3)") // [<t 1>, <t 2>, <Who knows>]
T is inferred in each case from the requested return type. The function itself filters the original array based on whether the elements are of the required type and then force casts the filtered results to the correct type.
If you want an "extra filter" you don't need to explicitly type the results as long as T can be inferred from your extra filter function.
func extraFilterType<T>(list: [AnyObject], extraFilter: T -> Bool) -> [T]
{
return list.filter{ $0 is T }.map{ $0 as! T }.filter(extraFilter)
}
let filteredList = extraFilterType(unfilteredList){
(element : ObjectClass2) -> Bool in
!element.description.isEmpty
}
print("\(filteredList)") // <t 2>
EDIT
A slicker version of the filterType function would use flatMap()
func filterType<T>(list: [Any]) -> [T]
{
return list.flatMap{ $0 as? T }
}
EDIT 2
Flatmap is deprecated for optionals, since Swift 4.something, use compactMap
func filterType<T>(list: [Any]) -> [T]
{
return list.compactMap{ $0 as? T }
}
This is the closest approximation I can come up with:
func objectsOfType<T: ObjectSuperClass>(type type: T.Type) -> [T] {
// Just returns an array of all objects of given type
}
func objectsOfType<T: ObjectSuperClass>(type type: T.Type, predicate: T -> Bool) -> [T] {
// Uses predicate to filter out objects of given type
}
Usage:
let bar = objectsOfType(type: ObjectClass1.self)
let baz = objectsOfType(type: ObjectClass2.self) {
// Something that returns Bool and uses $0
}
Technically, you can also go without type argument in the above, but then you will need to have explicitly typed receivers (bar and baz in the above example) so that Swift can correctly infer the types for you and use the right version of the generic function.
You can implement the function like this:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
if let otherFilter = otherFilter {
return objects.filter{$0 is T && otherFilter($0 as! T)}.map{$0 as! T}
} else {
return objects.filter{$0 is T}.map{$0 as! T}
}
}
Usage example:
objectsOfType(arrayOfObjects, subclass: ObjectClass1.self, otherFilter: nil)
Note that I'm not a fan of forced casting, however in this scenario it should not cause problems.
Or, the more verbose version of the function, with one less forced cast:
func objectsOfType<T: ObjectSuperClass>(objects: [ObjectSuperClass], subclass: T.Type, otherFilter: (T->Bool)?) -> [T] {
return objects.filter({object in
if let object = object as? T {
if let otherFilter = otherFilter {
return otherFilter(object)
} else {
return true
}
} else {
return false
}
}).map({object in
return object as! T
})
}