Is it possible to add function definitions programmatically in swift - swift

I'm creating a struct that holds 3 float values,
struct Col {
var r: Float
var g: Float
var b: Float
}
and I'd like to add a bunch of function definitions that are equivalent to the built in math functions, but that operate piecewise on the members of my struct
I can do it by hand, eg
func pow(a: Col, b: Col) -> Col {
return Col(r: pow(a.r, b.r), g: pow(a.g, b.g), b: pow(a.b, b.b))
}
but this is tedious and error prone.
What I'd like to do is create a function to turn the original math function into my Col version, so that I could call it like this:
defineColVersion(pow, noArgs: 2)
and it defines the new version, without overwriting the built in function that operates on Doubles
Is there any way to do this in Swift?
Thanks

I actually think this is exactly what you want:
func toCol(f: (Float, Float) -> Float) -> (Col, Col) -> Col {
return { a, b in
Col(r: f(a.r, b.r), g: f(a.g, b.g), b: f(a.b, b.b))
}
}
func toCol(f: Float -> Float) -> Col -> Col {
return { c in
Col(r: f(c.r), g: f(c.g), b: f(c.b))
}
}
let pow = toCol(Darwin.pow)
let sin = toCol(Darwin.sin)
let log = toCol(Darwin.log)
let a = Col(r: 0.4, g: 0.2, b: 0.7)
let b = Col(r: 0.3, g: 0.9, b: 0.3)
pow(a, b)
sin(a)
log(b)
The two overloaded functions toCol take a unary/binary function on Floats and returns a new function which does the same on your Col type. With those two, you can easily create a pow function for your Col type.

It is not possible to programmatically define new functions in a static language like Swift. What you can do, however, is to make a higher-kinded function:
func init(a: Col, b: Col, function: (Float, Float) -> Float) -> Col {
return self.init(r: function(a.r, b.r), g: function(a.g, b.g), b: function(a.b, b.b))
}
Col(Col(1, 2, 3), Col(3, 4, 5)) { $0 * $1 }
Col(Col(1, 2, 3), Col(3, 4, 5)) { pow($0, $1) }

func init(first: Col, second: Col, function: (Float, Float) -> Float ) {
newR = function(first.r,second.r)
newG = function(first.g,second.g)
newB = function(first.b,second.b)
return self.init(r:newR,g:newG,b:newB)
}
I'm not in a position to compile this so it probably has some errors but hopefully it will be useful. You would use it like so:
first = Col(r:1,g:2,b:3)
second = Col(r:1,g:2,b:3)
combined = Col(first:first,second:second) { pow($0,$1) }

Related

Swift functions inside a var

I am learning Swift, and want to know how to add functions to a var,
here the JS example...
function suma (a, b){
return a + b
}
console.log("sua suma::", suma(2,3))
function multiplica (a, b){
return a * b
}
console.log("sua multiplik::", multiplica(2,3))
const operations = {
suma,
multiplica
}
console.log ("sum of first class::", operations.suma(2,3))
console.log ("mult of first class::", operations.multiplica(2,3))
so how do I achieve the same on Swift?
Here what I have tried:
import Foundation
func suma(a:Int, b:Int) -> Int {
return a + b
}
func multiplica(a:Int, b:Int) -> Int {
return a * b
}
print("sua suma", suma(a: 2, b: 3))
print("sua multiplica", multiplica(a: 2, b: 3))
var operations = {
suma
multiplica
}
print("sua operatio", operations.suma(a: 2, b: 3)
So how to edit the Swift code to call the function inside operations?
Cheers
You could use a tuple for this:
let operations = (
suma: suma
multiplica: multiplica
)
print("sua operatio", operations.suma(2, 3)
Note that the names are duplicated. The one before the : is just a label so that you can refer to it with a name, and the one after the : actually refers to the function.
I would advise against writing Swift code in a JS style. You should not group functions together like this. Write a class/struct instead, and declare the functions in there. Use static where necessary.
As Sweeper mentioned in his answer the Swift equivalent of the JS code would probably be a class with static functions.
class Operations {
static func suma(a:Int, b:Int) -> Int {
return a + b
}
static func multiplica(a:Int, b:Int) -> Int {
return a * b
}
}
You would call the functions like this
print("sua operatio \(Operations.suma(a: 2, b: 3))")

Some numeric madness

Recently I wrote some helper functions for standard math operations(+,-,*,/) to process statistics without retardation, so explicit cast of numerics are unneeded
Double(8)/Double(3) // can be written as 8/3
It worked without a hassle, until I spot some erroneous behavior of a division operator, that is:
func / <F: BinaryFloatingPoint, I: BinaryInteger>(lhs: F, rhs: I) -> F {
return lhs / F(rhs)
}
func / <F: BinaryFloatingPoint, I: BinaryInteger>(lhs: I, rhs: F) -> F {
return rhs / F(lhs)
}
let a = 10.0
let b: UInt8 = 8
print(a/b) //outputs 1.25
print(b/a) //THIS is where weird stuff shows because it outputs 1.25 as well, but should 0.8!!
Is there something I missing or could it be a bug?
It was I little skid with position of operands. The valid code is:
func / <F: BinaryFloatingPoint, I: BinaryInteger>(lhs: F, rhs: I) -> F {
return lhs / F(rhs)
}
func / <F: BinaryFloatingPoint, I: BinaryInteger>(lhs: I, rhs: F) -> F {
return F(lhs) / rhs
}
let a = 10.0
let b: UInt8 = 8
print(a/b) //1.25
print(b/a) //0.8

Swift - can not get value of dictionary class extend from class

Simple problem, but i don't know why!!
Create an class - A, and class B extend from B.
Create a collection
public var hm : [B : Int] = [:]
Class A - defined:
class A : Hashable {
var x : Double = 0
var y : Double = 0
init(x : Double, y : Double) {
self.x = x
self.y = y
}
var hashValue : Int {
get {
// IMPORTANT!!! Do some operations to generate a unique hash.
return ObjectIdentifier(self).hashValue
}
}
static func == (lhs: A, rhs: A) -> Bool {
//return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
return (lhs.x == rhs.x && lhs.y == rhs.y)
}
}
class B : A {
}
A function check to get value of collection - hm.
func check(a1 : B, a2 : B){
print("\na1: \(a1.x) \(a1.y)")
if let y1 = hm[a1] {
print(y1)
}else{
print("false a1")
}
print("\na2: \(a2.x) \(a2.y)")
if let y2 = hm[a2] {
print(y2)
}else{
print("false a2")
}
}
and, finally create a function test() is main for testing.
func test() -> Void {
let a1 : B = B(x: 9.0, y: 12.0)
let a2 : B = B(x: 19.0, y: 42.0)
hm[a1] = 99
hm[a2] = 20
let a3 : B = B(x: 9.0, y: 12.0)
let a4 : B = B(x: 19.0, y: 42.0)
print("----Content of hm-----")
for (key, val) in hm {
print("x: \(key.x) | y: \(key.y) | val: = \(val)")
}
check(a1: a3, a2: a4)
}
On main thread call test().
Output is:
----Content of hm-----
x: 19.0 | y: 42.0 | val: = 20
x: 9.0 | y: 12.0 | val: = 99
a1: 9.0 12.0
99
a2: 19.0 42.0
false a2
Why, print "false a2" -> not found a2 inside of collection hm?
For compare 2 objects i use: (lhs.x == rhs.x && lhs.y == rhs.y).
(if use ObjectIdentifier then result always false for compare)
Thank you for explaining.
I don't know why it behaves like that exactly, but I can tell what the issue is: you're implementing Hashable wrong.
One important condition of conforming to Hashable is that "equal objects have the same hashValue", which is not true in your case. Once you break this fundamental assumption, all code that depends on it will likely break (like Dictionary).
In this example you should either make A work on identity (in this case == would be the same as ===), or work on values (in this case hashValue would depend only on x and y).
The important thing to note here is that Hashable doesn't just mean "it's a value that can produce a hash of itself", but it's actually a subprotocol of Equatable. As such, it really means "An object that can be checked for equality, and can also do a preliminary equality check with a hash value that it can produce".
Delete your implementation of hashValue and replace insert this instead:
func hash(into hasher: inout Hasher) {
x.hash(into:&hasher)
y.hash(into:&hasher)
}

Swift 2.1 Closure

At first, I apologize for my English!
Please help me detect when I was wrong.
let arrayInt = [0, 1, 2, 3, 4, 5, 7, 8, 9]
func myF(array: [Int], cl:(n1: Int, n2: Int) -> Bool) -> Int {
var number : Int
for value in array {
if cl(n1: number, n2: value) {
number = value
}
}
return number
}
myF(arrayInt, { cl: (n1: Int, n2: Int) -> Bool in
return n1 < n2
})
The function takes an array of Int and closure returns Int. Closure should take two Int numbers and return Bool yes or no. It is necessary to walk in a loop through the array and compare elements of array with variable using closure . If closure returns yes, you write the value of the array into variable. At the end of the function returns the variable. We need find max and min value in array.
I have 3 issue:
consecutive statements on a line must be separated by ';'
expected expression
contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored
Please don't proposed me use method "sort()". I am learning of "closure".
First of all you need to initialize your number variable: var number : Int -> var number = 0
Second, the function call with closure is not correct. There are several ways to call a closure:
let y = myF(arrayInt, cl: { (n1: Int, n2: Int) -> Bool in
return n1 < n2
})
or
let x = myF(arrayInt) { (n1, n2) -> Bool in
return n1 < n2
}
or even
let z = myF(arrayInt) { n1, n2 in
return n1 < n2
}
and
let w = myF(arrayInt) { $0 < $1 }
This link and this one should help you
Full code sample:
let arrayInt = [1, 2, 3, 0, 4]
func myF(array: [Int], cl: (n1: Int, n2: Int) -> Bool) -> Int {
var number = 0
for i in array {
if cl(n1: number, n2: i) {
number = i
}
}
return number
}
let x = myF(arrayInt) { (n1, n2) -> Bool in
return n1 < n2
}
First replace:
myF(arrayInt, { cl: (n1: Int, n2: Int) -> Bool in
by:
myF(arrayInt, cl: { (n1: Int, n2: Int) -> Bool in
because cl is the parameter name and all included in { } is the closure.
Second initialize number in myF function replacing:
var number : Int
by:
var number = array[0]
if the goal of the closure is to find max or min value.

Would this be the correct syntax for Swift 1.2?

I have seen this method:
func sum(x:Int, y: Int) -> Int {
return x+y
}
would I need to call this via:
let x1 = sum(4, y:11)
because this doesn't seem to work:
let x1 = sum(4, 11)
In your method, y is labelled as y both internally and externally. Therefore, to call the method, you must name the parameter. If you want to call the sum method the way you're describing, add an underscore before y like so:
func sum(x:Int, _ y: Int) -> Int {
var j = x*y
return j
}