Swift REPL Unexpected Behaviour - string

If I use the following code in Swift repl, I get unexpected results:
1> func addA(s: String)->String {
2. return s + "a"
3. }
4.
5. func addB(s: String)->String {
6. return s + "b"
7. }
8>
9> println(addA(""))
a
10> println(addB(""))
b
11> println(addA(addB("")))
ba
12> let p = addA(addB(""))
p: ((String)) = {
_core = {
_baseAddress = 0x0000000100500060
_countAndFlags = 2
_owner = (instance_type = Builtin.RawPointer = 0x0000000100500040)
}
}
13> println(p)
ba
14> let q = "a" + "b"
q: String = "ab"
why does declaring p produce this behaviour, while declaring q does not?

All that's happening here is that the REPL is letting you look inside Swift at some of the underlying efficiencies. p is stored as some sort of function composition. When evaluation is needed, it is evaluated. If you didn't want to see the sausage being made, you should not have entered the sausage factory.

Related

is there a way for me to fix the " Assignments are not expressions, and only expressions are allowed in this context" in this kotlin

This keeps displaying an error
fun main() {
println("Hello, world!")
}
fun coinFlip(timesToFlip: Int){
var heads = 0
var tails = 0
fun flip(): Int{
for(i in 1..timesToFlip){
var randomNumbers = (1..2).random()
if (randomNumbers = 1){
heads += 1
} else {
tails += 1
}
}
return tails
}
}
I assume in randomNumbers = 1 you intended to check if randomNumbers value is 1. In Kotlin, we check for equality using == operator. = is an assignment operator. So you need to replace this line with:
if (randomNumbers == 1) {
You can find the full list of Kotlin operators here: https://kotlinlang.org/docs/keyword-reference.html#operators-and-special-symbols

How can I concatenate multiple optional strings in swift 3.0?

I am trying to concatenate multiple strings in swift 3:
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = a! + b! + c!
When compiling I get the following error:
error: cannot convert value of type 'String' to specified type 'String?'
var d:String? = a! + b! + c!
~~~~~~~~^~~~
This used to work in swift 2. I am not sure why it doesn't work anymore.
Bug report filed by OP:
SR-1122: Failure to typecheck chain of binary operators on force-unwrapped values
Which has been resolved (fix commited to master Jan 3 2017), and should hence no longer be an issue in upcoming Swift 3.1.
This seems to be a bug (not present in Swift 2.2, only 3.0) associated with the case of:
Using the forced unwrapping operator (!) for at least 3 terms in an expression (tested using at least 2 basic operators, e.g. + or -).
For some reason, given the above, Swift messes up type inference of the expression (specifically, for the x! terms themselves, in the expression).
For all the examples below, let:
let a: String? = "a"
let b: String? = "b"
let c: String? = "c"
Bug present:
// example 1
a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 2
var d: String = a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 3
var d: String? = a! + b! + c!
/* error: cannot convert value of type 'String'
to specified type 'String?' */
// example 4
var d: String?
d = a! + b! + c!
/* error: cannot assign value of type 'String'
to specified type 'String?' */
// example 5 (not just for type String and '+' operator)
let a: Int? = 1
let b: Int? = 2
let c: Int? = 3
var d: Int? = a! + b! + c!
/* error: cannot convert value of type 'Int'
to specified type 'Int?' */
var e: Int? = a! - b! - c! // same error
Bug not present:
/* example 1 */
var d: String? = a! + b!
/* example 2 */
let aa = a!
let bb = b!
let cc = c!
var d: String? = aa + bb + cc
var e: String = aa + bb + cc
/* example 3 */
var d: String? = String(a!) + String(b!) + String(c!)
However as this is Swift 3.0-dev, I'm uncertain if this is really a "bug", as well as what's the policy w.r.t. reporting "bugs" in a not-yet-production version of code, but possibly you should file radar for this, just in case.
As for answering your question as how to circumvent this issue:
use e.g. intermediate variables as in Bug not present: Example 2 above,
or explicitly tell Swift all terms in the 3-term expression are strings, as in Bug not present: Example 3 above,
or, better yet, use safe unwrapping of your optional, e.g. using optional binding:
var d: String? = nil
if let a = a, b = b, c = c {
d = a + b + c
} /* if any of a, b or c are 'nil', d will remain as 'nil';
otherwise, the concenation of their unwrapped values */
Swift 3
let q: String? = "Hello"
let w: String? = "World"
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// HelloWorld!
let q: String? = "Hello"
let w: String? = nil
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// Hello!
func getSingleValue(_ value: String?..., seperator: String = " ") -> String? {
return value.reduce("") {
($0) + seperator + ($1 ?? "")
}.trimmingCharacters(in: CharacterSet(charactersIn: seperator) )
}
let val: String? = "nil"
val.flatMap({(str: String) -> String? in
return str + "value"
})
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = ""
let arr = [a,b,c]
arr.compactMap { $0 }.joined(separator: " ")
compactMap be used to filter out nil values from flattened arrays

Swift String.removeRange cannot compile

I don't understand what to do with the issue reported by the compiler. I tried to create a Range, but it says Index is not known:
//let range = matches.first!.range.location
let range = Range(
start:matches.first!.range.location,
end: matches.first!.range.location+matches.first!.range.length
)
id = text[range]
var t = text
t.removeRange(range)
return t
Compiler says: Cannot invoke 'removeRange' with an argument list of type '(Range)' on t.removeRange(range).
I'm pretty sure it's evident, but I lost a great deal of time on such a small issue… any help highly appreciated!
As your error says that:
Cannot invoke 'removeRange' with an argument list of type '(Range)'
Means there is a problem with your range instance type and removeRange function will only accept an argument with type Range<String.Index> and its syntax is :
/// Remove the indicated `subRange` of characters
///
/// Invalidates all indices with respect to `self`.
///
/// Complexity: O(\ `count(self)`\ ).
mutating func removeRange(subRange: Range<String.Index>)
And here is working example with removeRange:
var welcome = "hello there"
let range = advance(welcome.endIndex, -6)..<welcome.endIndex
welcome.removeRange(range)
println(welcome) //hello
Hope this will help.
Swift 2.2 example of removing first 4 characters:
let range = text.startIndex..<text.startIndex.advancedBy(4)
text.removeRange(range)
That first line feels verbose. I hope newer Swift versions improve upon it.
Here is the working equivalent snippet:
static func unitTest() {
let text = "a👿bbbbb🇩🇪c"
let tag = Tag(id: "🇩🇪")
tag.regex = "👿b+"
print ("Unit test tag.foundIn(\(text)) ? = \(tag.foundIn(text))")
}
func foundIn(text: String) -> (id:String, remainingText:String)? {
// if a regex is provided, use it to capture, and keep the capture as a tag ID
if let regex = regex {
let r = Regex(regex) // text =~ regex
let matches = r.matches(text)
if matches.count >= 1 {
let first = matches.first!.range
let start = advance(text.startIndex, first.location)
let end = advance(start, first.length-1)
let range = Range(start: start, end: end)
id = text[range]
var t = text
t.removeRange(range)
return (id, t)
}
return nil
}
else if let range = text.rangeOfString(id) {
var t = text
t.removeRange(range)
return (id, t)
}
else {
return nil
}
}
The unit test returns :
Unit test tag.foundIn(a👿bbbbb🇩🇪c) ? = Optional(("👿bbbbb", "a🇩🇪c"))

do block with flower brackets in ghci throws error

I have a code that works with print inside do block as,
do { print ([(n, 2^n) | n <- [0..19]]) }
Then i tried a much simpler version to print a variable value,
do { let a = 1; print (a) }
It throws error as parse error on input }
What else, i tried with no success ---
ghci> let a = 1; print (a)
And
ghci> :{
| let a = 1;
| print (a)
| :}
Once you start a let statement, the rest of the line is considered to be additional let assignments. Consider this error message:
ghci> do print 1; let c = 2; d = 3
<interactive>:3:13:
The last statement in a 'do' block must be an expression
let c = 2
d = 3
Note that the let keyword is not needed for d = 3.
To add a monadic statement after a let you'll need to put it on a separate line (with the correct indentation):
ghci> :{
| do print 1; let a = 2; b = 3
| print b
| :}
1
3
AFAIK, there is no way to put a monadic statement after a let on the same line.

Selecting a tuple index using a variable in Swift

That is what i am trying to do:
var i = 0
var string = "abcdef"
for value in string
{
value.[Put value of variable i here] = "a"
i++
}
How can i insert the value of i in the code?
Easiest is probably just convert it to an NSMutableString:
let string = "abcdef".mutableCopy() as NSMutableString
println( "\(string)")
for var i = 0; i < string.length; ++i {
string.replaceCharactersInRange(NSMakeRange(i, 1), withString: "a")
}
println( "\(string)")
Yes, it's a bit ugly but it works.
A much cleaner way is to use Swifts map function:
var string = "abcdef"
let result = map(string) { (c) -> Character in
"a"
}
println("\(result)") // aaaaaa
You should just be able to use the following but this doesn't compile:
map(string) { "a" }
In you comments you mention you want to split up the string on a space, you can just use this for that:
let stringWithSpace = "abcdef 012345"
let splitString = stringWithSpace.componentsSeparatedByString(" ")
println("\(splitString[0])") // abcdef
println("\(splitString[1])") // 012345

Resources