Swift, Tuples issue #2 - swift

Sorry about the last thread where I posted this question by accident! Here it is. I received a response from someone (Their response is at bottom of page) and unfortunately it did not work. Thanks in advance!
Create a variable named result and assign it the tuple returned from function greeting. (Note: pass the string "Tom" to the greeting function.)
func greeting() -> (language: String, greeting: String, name: String) {
let language = "English"
let greeting = "Hello"
let name = "Tom"
return (language, greeting, name)
}
var result = greeting()
Error = Your function needs to return a tuple with elements named 'greeting' and 'language'.
Now this solution below tells me that my variable has the wrong value in it, but I can't figure out how to pass it "Tom" to the greeting function because I keep getting an error.
func greeting() -> (language: String, greeting: String) {
let language = "English"
let greeting = "Hello"
return (language, greeting)
}
var result = greeting("Tom")
Response I got in the last thread is below. I still get the error message saying that I need to assign the return value of greeting to result.
func greeting(name:String) -> (language: String, greeting: String) {
let language = "English"
let greeting = "Hello " + name + "!"
return (language, greeting)
}
var result = greeting("Tom").greeting

The task is
Create a variable named result and assign it the tuple returned from function greeting.
What you do in the last block is
var result = greeting("Tom").greeting
what I would expect you to do is
var result = greeting("Tom")

Related

Trouble creating a more complex closure

I am trying to get my head around creating closures. I get the simpler ones like:
let squaredNumber = { (num: Int) -> (Int) in
return num * num
}
print( squaredNumber(9) ) // 81
and I understand how the sorting one works:
let team = ["Bob", "Rick", "Peter"]
print( team.sorted() ) // ["Bob", "Peter", "Rick"]
print( team.sorted(by: { $0 > $1 }) ) //["Rick", "Peter", "Bob"]
So now I am trying to create my own version of sorting one, in terms of setup.
In the sorting one, there is a plain function sorted() and a sorted(by:...) option.
The code I am playing with so far is (commented code is just to play with):
struct Person {
let name_given = { (fn: String?, ln: String?) -> String in
// return a different value if a nil is supplied
guard let fn1 = fn else { return "No First Name" }
guard let ln1 = ln else { return "No Last Name" }
// Only returns value if not nil
// if let fn1 = fn { return fn1 }
// if let ln1 = ln { return ln1 }
// returns what has been decided above
return "\(fn!) \(ln!)"
}
let no_name = {() -> String in
return "Hello"
}
}
let dad = Person()
print( dad.name_given("Jeff", "Smith") )
print( dad.no_name() )
but I can only get this to work dad.something() but I would like the option of a parameter closure in a function that is I am guessing an optional.
Am I even on the right track in terms of thinking this through.
Basically I want to create a function that execute different code based on wether they have a parameter or not.
So something like dad() or dad(name: {"Jeff", "Smith"}) or dad(age: {35})
The closures would combine strings or do something with the code and then return the result or something.
There is no story to the code above, I just want to understand how to create it.
/////////////////
Edit for clarity:
So I realise my aim was explained with a lot of confusion, because I am trying to figure this out.
Here is hopefully a better attempt:
So this code still doesn't work, but bare with me.
Take for example this:
static func closure(both: (_ a: String, _ b: String) -> String { a, b in
return "\(a) \(b)"
})
and then this:
static func closure(single: (_ a: String) -> String { a in
return "\(a)"
})
So then I would effectively be able to do something like this:
Person.closure(both: {"First", "Last"}) -> This would output "First Last"
and
Person.closure(single: {"First"}) -> This would output "First"
My outcome would be that I could have a static class that has a bunch of closures, but that are grouped.
So if I want to a bunch of string type closures, it would be easy to find them because you could do something like:
StaticStruct.string(<thing1>: {<closure params>})
StaticStruct.string(<thing2>: {<closure params>})
StaticStruct.string(<thing3>: {<closure params>})
or if I want to do something with numbers, it would be:
StaticStruct.numbers(<thing1>: {<closure params>})
StaticStruct.numbers(<thing2>: {<closure params>})
StaticStruct.numbers(<thing3>: {<closure params>})
I hope this makes more sense.
I like the way it looks when you do an array sort, that is why I started thinking like this.
What you are asking is flawed for Swift:
If you don't provide anything at all, not even nil, how can Swift know what's missing?
Think about this example:
print( dad.name_given("Connor") )
How can Swift know if you provided only the first name, or only the last name? In your example, you will need to be specific on what is not provided:
print( dad.name_given(nil, "Connor") ) // Surely only last name is provided
A function would solve this problem by providing a default value to the parameters, so you don't have to pass nil, but then you would need to specifically tell what you're passing, or Swift will assume:
func person(fn: String? = "", ln: String? = "") -> String {...}
print( dad.person(ln: "Connor")) // Surely passing the second parameter
func person(_ fn: String? = "", _ ln: String? = "") -> String {...}
print( dad.person("Connor")) // It will assume that you are passing the first parameter
But with closures, you can't provide a default value to parameters:
let name_given = { (fn: String? = "", ln: String? = "") -> String in...}
// Error: Default arguments are not allowed in closures
It might not solve your problem, but you can create a function that provides default values to the parameters (no need to pass nil), and accepts a closure to treat those parameters.
func describe(fn: String = "", ln: String = "", _ action: #escaping (String?, String?)->String) -> String {
let first: String? = fn == "" ? nil : fn
let second: String? = ln == "" ? nil : ln
return action(first, second)
}
print( dad.describe(ln: "Connor", dad.name_given)) // No first Name

How to prove "copy-on-write" on String type in Swift

As the title said, I tried to prove myself that COW(copy on write) is supported for String in Swift. But I cannot find a proof. I proved the COW on Array and Dictionary after trying the following codes:
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var xArray = [20, 30, 40, 50, 60]
var yArray = xArray
// These two addresses were the same
address(of: xArray)
address(of: yArray)
yArray[0] = 200
// The address of yArray got changed
address(of: yArray)
But for String type, it was not working.
var xString = "Hello World"
var yString = xString
// These two addresses were different
address(of: xString)
address(of: yString)
And I dumped the test function from the official Swift code repo.
func _rawIdentifier(s: String) -> (UInt, UInt) {
let tripe = unsafeBitCast(s, to: (UInt, UInt, UInt).self)
let minusCount = (tripe.0, tripe.2)
return minusCount
}
But this function seems to only cast the actual value pointed to not the address. So two different String variables with the same value would have the same rawIdentifier. Still cannot prove COW to me.
var xString = "Hello World"
var yString = "Hello" + " World"
// These two rawIdentifiers were the same
_rawIdentifier(s: xString)
_rawIdentifier(s: yString)
So how does COW work on String type in Swift?
The compiler creates only a single storage for both
"Hello World" and "Hello" + " World".
You can verify that for example by examining the assembly code
obtained from
swiftc -emit-assembly cow.swift
which defines only a single string literal
.section __TEXT,__cstring,cstring_literals
L___unnamed_1:
.asciz "Hello World"
As soon as the string is mutated, the address of the string storage
buffer (the first member of that "magic" tuple, actually _baseAddress
of struct _StringCore, defined in StringCore.swift) changes:
var xString = "Hello World"
var yString = "Hello" + " World"
print(_rawIdentifier(s: xString)) // (4300325536, 0)
print(_rawIdentifier(s: yString)) // (4300325536, 0)
yString.append("!")
print(_rawIdentifier(s: yString)) // (4322384560, 4322384528)
And why does your
func address(of object: UnsafeRawPointer) -> String
function show the same values for xArray and yArray, but
not for xString and yString?
Passing an array to a function taking a unsafe pointer passes the
address of the first array element, that is the same for both
arrays if they share the storage.
Passing a string to a function taking an unsafe pointer passes a
pointer to a temporary UTF-8 representation of the string.
That address can be different in each call, even for the same string.
This behavior is documented in the "Using Swift with Cocoa and
Objective-C" reference for UnsafePointer<T> arguments, but apparently
works the same for UnsafeRawPointer arguments.

Trouble converting a string to an Int

The following works in Playground:
func stringToInt(numberStr: String!) -> Int {
print(numberStr)
return Int(numberStr)!
}
let strNum1: String?
strNum1 = "1"
let result = stringToInt(numberStr: strNum1)
It returns 1 as expected.
In Xcode, a similar approach fails:
func stringToInt(numberStr: String!) -> Int {
print("\(numberStr!)")
let str = "\(numberStr!)"
print(Int(str))
return Int(str)!
}
The first print produces: Optional(1)
The second print produces: nil
The return statement fails because it is attempting to create an Int from a nil.
It must be something simple but I haven't been able to determine why it's not working. This is in Swift 3 and Xcode 8 BTW.
#Hamish:
In Xcode, I have a string with a numeric value. This:
print("number: (selectedAlertNumber) - unit: (selectedAlertUnit)")
...produces this:
number: Optional(1) - unit: Day
Then, I'm checking to see if either selectedAlertNumber of selecterAlertUnit != "-"
if selectedAlertNumber != "-" && selectedAlertUnit != "-" {
// set alert text
var unitStr = selectedAlertUnit
let alertNumber = stringToInt(numberStr: selectedAlertNumber)
if alertNumber > 1 {
unitStr.append("s")
}
let alertText = "...\(selectedAlertNumber) \(unitStr) before event."
alertTimeCell.setAlertText(alertText: alertText)
// set alert date/time
}
The let alertNumber = stringToInt... line is how I'm calling the function. I could just attempt the conversion there but I wanted to isolate the problem by wrapping the conversion in it's own function.
Using string interpolation to convert values to a String is usually not advised since the output may differ depending on optional status of the value. For example, consider these two functions:
func stringToInt(numberStr: String!) -> Int
{
print("\(numberStr!)")
let str = "\(numberStr!)"
return Int(str)!
}
func otherStringToInt(numberStr: String!) -> Int
{
print(numberStr)
let str = "\(numberStr)"
return Int(str)!
}
The only difference between these two is the ! in the second function when using string interpolation to get a String type value from numberStr. To be more specific, at the same line in function 1 compared to function 2, the string values are very different depending on whether or not the interpolated value is optional:
let str1: String = "1"
let str2: String! = "1"
let str3: String? = "1"
let otherStr1 = "\(str1)" // value: "1"
let otherStr2 = "\(str2)" // value: "Optional(1)"
let otherStr3 = "\(str2!)" // value: "1"
let otherStr4 = "\(str3)" // value: "Optional(1)"
let otherStr5 = "\(str3!)" // value: "1"
Passing otherStr2 or otherStr4 into the Int initializer will produce nil, since the string "Optional(1)" is not convertible to Int. Additionally, this will cause an error during the force unwrap. Instead of using string interpolation in your function, it would be better to just use the value directly since it's already a String.
func stringToInt(numberStr: String!) -> Int
{
return Int(numberStr)!
}
Let me know if this makes sense.
Also, my own personal feedback: watch out force unwrapping so frequently. In many cases, you're running the risk of getting an error while unwrapping a nil optional.

How to get the string representation of a nested class

In my reflection library EVReflection I have the following problem when class definitions are nested (class within a class). Below is a worked out case which can be found as a unit test here and The location in the library itself where the code needs to change is Here
I need to get the Internal Swift string representation of a nested
class for a property which is an array of that nested class.
Below you can see a unit test where I am able to get the correct type for the property company that is an other object. It will output _TtCC22EVReflection_iOS_Tests13TestIssue114b10Company114 instead of Company114
When I try the same for the friends property my goal is that it outputs something like: Swift.Array<_TtCC22EVReflection_iOS_Tests13TestIssue114b7User114>
What do I have to do to get that?
As you can see in the test I have various assignments to the value valueType. None of these assignments work. I am only able to get an Array<User114> or an Swift._EmptyArrayStorage.
As you also can see in the test is that if I set a breakpoint and do a po in the output window I am able to get the correct output. So what code will accomplish the same in my code?
class TestIssue114b: XCTestCase {
class User114: EVObject {
var company: Company114 = Company114()
var friends: [User114] = []
}
class Company114: EVObject {
var name: String = ""
var address: String?
}
func testIssueNestedObjects() {
let x = User114()
print("type 1 = \(NSStringFromClass(type(of: x.company)))") // output = type 2 = _TtCC22EVReflection_iOS_Tests13TestIssue114b10Company114
print("type 2 = \(testIssueNestedObjects(x.friends))")
}
func testIssueNestedObjects(_ theValue: Any) -> String {
var valueType = ""
let mi = Mirror(reflecting: theValue)
valueType = NSStringFromClass(type(of: (theValue as! [NSObject]).getTypeInstance() as NSObject)) // NSObject
valueType = "\(type(of: theValue))" // Array<User114>
valueType = "\(mi.subjectType)" // Array<User114>
valueType = ObjectIdentifier(mi.subjectType).debugDescription //"ObjectIdentifier(0x0000000118b4a0d8)"
valueType = (theValue as AnyObject).debugDescription // <Swift._EmptyArrayStorage 0x10d860b50>
valueType = NSStringFromClass(type(of: theValue as AnyObject)) // Swift._EmptyArrayStorage
// set breakpont en enter this in output window: (lldb) po type(of: theValue)
// Ouput will be: Swift.Array<EVReflection_iOS_Tests.TestIssue114b.User114>
return valueType
}
}
Background info:
Actually the end goal is that I have to be able to create instances of the object that I can add to the array. Since the array property is only available as a result from a Mirror command the variable will be of type Any. I do have an extension for arrays in place that will return a new array element. however I am only able to get that when the Any is casted to Array<NSObject> and because of that my extension will return an NSObject. So I would like to get a string like Swift.Array<_TtCC22EVReflection_iOS_Tests13TestIssue114b7User114> I can then get the parts between <> and then create an instance for that using NSClassFromString.
String(reflecting: type(of: theValue))
update by Edwin Vermeer:
For the required conversion to the internal string representation i now have the following function (still in draft)
public class func convertToInternalSwiftRepresentation(type: String) -> String {
if type.components(separatedBy: "<").count > 1 {
// Remove the Array or Set prefix
let prefix = type.components(separatedBy: "<") [0] + "<"
var subtype = type.substring(from: prefix.endIndex)
subtype = subtype.substring(to: subtype.characters.index(before: subtype.endIndex))
return prefix + convertToInternalSwiftRepresentation(type: subtype) + ">"
}
if type.contains(".") {
var parts = type.components(separatedBy: ".")
if parts.count == 2 {
return parts[1]
}
let c = String(repeating:"C", count: parts.count - 1)
var rv = "_Tt\(c)\(parts[0].characters.count)\(parts[0])"
parts.remove(at: 0)
for part in parts {
rv = "\(rv)\(part.characters.count)\(part)"
}
return rv
}
return type
}

String replacement not working with Dictionary

I have a mini dictionary that I would like to use in order to replace occurrences of text within a user's inputted string. However, instead of replacing every occurrence of a particular string, it retains the original string. For example, user types:
"The girl went to school"
My program still returns "The girl went to school". It should come out as "The binguel debbo went to jangirde"
func input() -> String {
let keyboard = NSFileHandle.fileHandleWithStandardInput()
let inputData = keyboard.availableData
return (NSString(data: inputData, encoding:NSUTF8StringEncoding)?.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()))! as! String
}
var userInput = "" //Declares original user input
var finalSentence:String = "" //Declares a string variable for the final sentence
var newUserString:String
var fulfuldeWords = ["man":"gorko", "woman":"debbo",
"boy":"binguel gorko", "girl": "binguel debbo", "work":"golle",
"school":"jangirde", "water":"ndiyam", "horse":"puccu", "cow":"na'i",
"hat":"hufunere", "house":"wuro", "courage":"cuusal", "camel":"gelodi",
"milk":"kossam"
]
print("Please enter a sentence to be partially translated: ") //Ask user for input
userInput = input()
var theStringArray = userInput.componentsSeparatedByString(" ")
for (englishWord, fulaniWord) in fulfuldeWords {
finalSentence = userInput.stringByReplacingOccurrencesOfString(englishWord, withString: fulaniWord)
}
print(finalSentence)
This is being done in Swift and I don't get why it's not working. Where did I go wrong in my code. Thanks!
You need to perform the function stringByReplacingOccurencesOfString on the same variable to get your desired result. So, in your code, store the result on userInput and print as the output as well.
for (englishWord, fulaniWord) in fulfuldeWords {
userInput = userInput.stringByReplacingOccurrencesOfString(englishWord, withString: fulaniWord)
}
print(userInput)