No Errors, But Not Printing the Phrase. Help appreciated

Obvious newbie here. Thank you for any clues.

So this code has no errors. But it is not doing what I want.

I just want to print the phrase that is built.

But what it actually prints is:

(Function)

(Function)

Here is the code in question :

func impossibleBeliefsCount
( pigsFlying: Int,
frogsBecomingPrinces: Int,
multipleLightningStrikes: Int)
-> Int
{
let total = pigsFlying + frogsBecomingPrinces + multipleLightningStrikes
return (total)
}

func impossibleThingsPhrase(
numberOfImpossibleThings : Int,
meal : String )
-> String
{
// let numberOfImpossibleThings = 10
// let meal = "teatime"
return "Why, I've believed as many as \(numberOfImpossibleThings) before \(meal)"
}

let rResult = impossibleBeliefsCount
(pigsFlying: 1,
frogsBecomingPrinces: 2,
multipleLightningStrikes: 3)

let printMe = impossibleThingsPhrase
(numberOfImpossibleThings : rResult,
meal : "TEATIME")

print ( rResult )

print ( printMe )

...

Thanks again.

Code like the above is compiled as if it was:

let printMe = impossibleThingsPhrase ; // <-- statement separator
(numberOfImpossibleThings : rResult, // <-- tuple of 2 elements
meal : "TEATIME")

So, printMe contains a reference to the function, instead of the result of executing the function. A function reference is just printed as "(Function)".

You should be getting a warning on the line beginning with "(", saying that the expression is unused. That's your clue to what went wrong.

To fix this, you will need to move at least the "(" onto the line with the function name:

let printMe = impossibleThingsPhrase(
numberOfImpossibleThings : rResult,
meal : "TEATIME")
2 Likes

Zero warnings were given on the subject code. (I guess this can be seen if thrown into a Playground.)

Thank you, QuinceyMorris!

So, I thought a newline acted like a neutral space character?

But actually newline acts more like a semicolon line delimiter?

(Or sometimes one and sometimes the other based on context?)

...

Here are the fixed code lines for anyone following along:

...

let rResult = impossibleBeliefsCount(
pigsFlying: 1,
frogsBecomingPrinces: 2,
multipleLightningStrikes: 3)

let printMe = impossibleThingsPhrase(
numberOfImpossibleThings : rResult,
meal : "TEATIME")

...

Thanks again!

;M;

In a playground, the warning isn't shown, because it's intended to be an environment where you can just evaluate expressions. The result of the expression is shown over to the right, but if you're new to Swift and playgrounds, it's not obvious how to deduce the behavior from what you see.

This is one of several ways in which playgrounds have become something of a disappointment.

Yes, it's context dependent.

In this case, it would be problematic if an initial "(" on the next line was interpreted as a continuation, since you'd be forced to use a semicolon if you really did want to assign a function reference, and that would conflict with the rule/convention that semicolons are not a required part of syntax.

1 Like

I had to read this a couple times. But I think I get what you mean. Makes me kind of sad. In my C training newline was neutral space. So you could make dense unintelligible code with zero spaces. Or space it out as you like to make it readable. (sigh) the whole "it depends on context" thing is irksome, but at least I know now and will pay attention more carefully. Thanks, again, @QuinceyMorris

Interesting find. Concise version:

func fugazi(x: String, y: String) -> String {
    "\(x) \(y)"
}

let result1 = fugazi
(x: "Hello", y: "World")

let result2 = fugazi(
    x: "Hello", y: "World"
)

print(result1) // (Function)
print(result2) // Hello World

The other known pitfall of the language is:

func bugaga() {
    return
    

    // TODO later
    print("prints bugaga")
}

bugaga() // prints bugaga

Edit: similar scenario:

var elements: [Int] = [1, 2, 3]

let a = elements[
    0
]
let b = elements
[
    0
]
print(a) // 1
print(b) // [1, 2, 3]

1 Like

Thank you for codifying my issue in black and white, @tera . Long ago, in a previous life, and another language, I liked to line up my braces, brackets, and parens on the left, then indent the body for visual clarity. Looks like that is not a good idea with Swift.

How does it "prints bugaga" after the "return" statement? I mean, isn't control supposed to stop and return to after the calling statement with no other lines executed after the "return" statement???

The white space is removed and the whole statement is treated as:

return print("prints bugaga")

It doesn't matter that print() returns Void... as this matches the function Void return type of "bugaga" perfectly... If bugaga was returning "Int" you'd actually get a compilation error: "Cannot convert return expression of type '()' to return type 'Int'".

The situation is not as bad as it could be as there's a warning issued when you compile it in a non playground environment:

Expression following 'return' is treated as an argument of the 'return'

and to "actually" return you could put a semicolon:

func bugaga() {
    return;  // now this is return, no ifs no buts
    

    // TODO later
    print("prints bugaga")
}
2 Likes