Pattern variable binding cannot appear in an expression - swift

I've been looking at The Swift Programming Language guide provided by apple.
Following sample is from the book:
class HTMLElement {
let name :String;
let text: String?;
#lazy var asHTML : () -> String = {
if let text = self.text {
return "<\(self.name)>\(self.text)</\(self.name)>";
} else {
return "<\(self.name) />"
}
}
}
I incorrectly wrote the closure as follow:
#lazy var asHTML : () -> String = {
if (let text = self.text) {
return "<\(self.name)>\(self.text)</\(self.name)>";
} else {
return "<\(self.name) />"
}
}
Notice the parentheses around let text = self.text and compiler complain about:
Pattern variable binding cannot appear in an expression
Just wondering what does Pattern Variable Binding mean, and why it cannot appear in an expression?

A "pattern variable binding" is the thing you're doing, i.e. using let in the middle of some code, not at the top level of a file or enum or struct or class as a way of declaring a constant variable.
What makes it an expression is the parentheses. You've cut the "let" expression off from its surroundings and asked for evaluation of it as an expression separately. But you can't do that: you can't say "let" just anywhere.
Another way of looking at it is simply this: if let is a fixed meaningful pattern, where the condition is an Optional being evaluated into a constant for use inside the if-code. The parenthesis broke up the pattern.
The pattern is called a binding because you're defining this name very temporarily and locally, i.e. solely down into the if-code. I think it goes back to LISP (at least, that's where I've used "let" this way in the past).

Related

How can I have a variable and a function with same name in Swift

I want to have a variable and a function with same name, therefore I have this codes:
var testString: String = "some string from variable!"
// use case: print(testString)
func testString() -> String {
return "some string from function!"
}
// use case: print(testString())
As you can see there is a big difference in both use cases! one like testString and the other with testString(), but xCode complain this to me:
Invalid redeclaration of 'testString()'
Which I do not know why it has to be an issue! one thing is a variable and other is function!
How ever I done a little hack and I deformed the function to this one in down, now it compile and no issue! the use case is still the same like testString()
func testString(_ value: String? = nil) -> String {
return "some string from function!"
}
// use case: print(testString())
Now I have the things I wanted, but I have unwished initializer for function! how can I solve this issue in general?
it's not possible, as they share the same namespace:
https://forums.swift.org/t/why-doesnt-swift-allow-a-variable-and-a-function-with-the-same-name/5038

SwiftUI TextField won't change its contents under weird corner case with Binding<String> computed property

I have a TextField inside a SwiftUI body. I have bound it to a #State var through an intermediary binding which lets me get and set a computed value...
struct ExampleView: View {
#State var symbolToBeValidated: String = ""
var body: some View {
let binding = Binding<String> (get: {
return self.symbolToBeValidated
}, set: {
var newString = $0.uppercased()
self.symbolToBeValidated = newString // <- fig. 1: redundant assignment I wish I didn't have to put
newString = newString.replacingOccurrences(
of: #"[^A-Z]"#,
with: "",
options: .regularExpression
)
self.symbolToBeValidated = newString // <- fig. 2: the final, truly valid assignment
})
let form = Form {
Text("What symbol do you wish to analyze?")
TextField("ex.AAPL", text: binding)
// [...]
I'm using the intermediary Binding so that I can transform the string to always be an Uppercased format only containing letters A-Z (as referenced by my .regularExpression). (I'm trying to make it so that the TextField only shows a validly formatted Stock Symbol on each keypress).
This works, somewhat. The problem I discovered is that if I don't call the assignment twice (as seen in fig 1) the TextField will begin to show numbers and letters (even though it isn't included in the symbolToBeValidated string. This happens, I suspect, because SwiftUI is checking the oldValue against the newValue internally, and because it hasn't changed in the background, it doesn't call a refresh to get the internal value again. The way I've found to thwart this is to include an extra assignment before the .replacingOccurences call.
This results in the number or symbol being flashed on the screen for a blip as it is being typed by the user, then it is correctly removed by the .replacingOccurences call.
There must be a more elegant way to do this. I went down the Formatter class type and tried this alternative only because Formatter resulted in a similar behavior where the errant character would blip on the screen before being removed.
If someone knows a way for this to be intercepted before anything is displayed on the screen, I would appreciate it. This is super nit-picky, but I'm just fishing for the right answer here.
Try this:
extension Binding where Value == String {
public func validated() -> Self {
return .init(
get: { self.wrappedValue },
set: {
var newString = $0.uppercased()
newString = newString.replacingOccurrences(
of: #"[^A-Z]"#,
with: "",
options: .regularExpression
)
self.wrappedValue = newString
}
)
}
}
// ...
TextField("ex.AAPL", text: self.$symbolToBeValidated.validated())
This way also allows you to reuse and test the validation code.

Constant property can be modified during initialization? MODIFIED? What?

Quote from the Swift 3.0 office document of the Chapter: Initialization
For class instances, a constant property can be modified during initialization only by the class that introduces it. It cannot be modified by a subclass.
To my understanding the modified involves the action after the definition, aka the action after declaring and assigning value, aka re-assigning values, therefore I tried the following code.
class SurveryQuestion {
let text: String
var response: String?
init(text: String) {
self.text = "do you like music?"
self.text = text //Got an error here
}
func ask(){
print(text)
}
}
And I got an error at line self.text = text. The compiler asked me to change the property textfrom constant to variable. Isn't it says that the constant property can be modified by the initializer of the class which originally introduced it?
Question: Am I understand the word modified wrongly? Is it means the action after the declaring rather than the definition which would lead to the modified is meant to by passing a value to the constant.
I think that the documentation is not clear enough. You can set a constant property only once during initializing. You also would not be able to set it during initialization if the property's value was defined inline. Here is example.
class SomeClass {
let someProperty: String = "A"
init() {
self.someProperty = "" //ERROR: Immutable value "self.someProperty" may only be initialized once.
}
}
The compile time error //ERROR: Immutable value "self.someProperty" may only be initialized once. actually explains it well.

In Haxe, how do you read a variable name inside of a Macro?

I'm trying to use Macros to convert some variable declarations from this:
function test():Void {
var someComp:Component = __SOME_MACRO__();
// Or...
#getCompById var someComp:Component;
// Or even simpler...
getCompById(someComp, Component); //do some fancy macro magic...
// Also, if it's not possible/easy with a variable ...
getCompById("someComp", Component); //with a string of the variable name.
}
... to this:
function test() {
var someComp:Component = cast container.getCompById("someComp");
}
I'm leaning more toward the 3rd option (shorter syntax, same results).
But I have no idea how to write the macro (should it take a String as parameter? An expression?) and how to properly return that as a macro expression.
This is the (broken) code I've got so far:
macro static function getCompById(someVar:Expr, typeVar:Expr) {
return macro {
var someVar:typeVar = cast container.getCompById("someVar");
};
}
Any ideas?
The issue with the code you posted is first that you'd need reification escaping mechanisms for this to work correctly - so the first change would be to use the macro escapes:
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
Now there will be some problems with this: It's expecting someVar to be of type String, and typeVar to be of type ComplexType. It's easy to get the string component from an Expr. It's not so easy however to transform an Expr into ComplexType. The easiest way to do that is to use the tink_macros library and use asComplexType
So the (untested) code will look something like:
using tink.MacroAPI;
using haxe.macro.Tools;
macro static function getCompById(someVarExpr:Expr, typeVarExpr:Expr)
{
var typeVar = typeVarExpr.toString().asComplexType();
switch (someVarExpr.getIdent())
{
case Success(someVar):
return macro var $someVar:$typeVar = cast container.getCompById($v{someVar});
case Failure(error): throw error;
}
}

Reason for assigning optional to new variable in conditional statement in Swift

I'm going through the swift docs, and in the optional segment, it talks about using the question mark -- ? -- to signify variables that might be nil. This can be used in an if statement to check for nil, but in the docs they assign the optional to a new variable in the conditional. Is there a reason for this?
For Example, it is presented in the docs similar to this:
// Declare an optional string (might be nil)
var optionalString: String? = "Hello"
// Assigns optionalString to new variable before checking if nil
if let string = optionalString {
println("\(optionalString) is not nil!")
}
else {
println("\(optionalString) is nil")
}
However, this runs just fine for me in tests:
var optionalString: String? = "Hello"
// Assigns optionalString to new variable before checking if nil
if optionalString {
println("\(optionalString) is not nil!")
}
else {
println("\(optionalString) is nil")
}
Question
Is there a reason to assign optionalString to a new variable string in the conditional statement?
Take a look at the section on Optional Chaining in the docs. In the example you cite, there's not much difference. But in other cases, an if-let construction lets you get at an unwrapped value that comes from a series of optional references and method calls, without using implicit unwraps that can crash your app if you haven't considered all the possible bindings for a value in a chain.
It's also useful if you want to avoid recomputing a value. You can use it in a lot of the same ways you'd use an assignment in a conditional in (Obj)C (remember if (self = [super init])).
For example, if the optional being tested comes from a computed property:
var optionalName: String? {
get {
if checkTouchID() {
return "John Appleseed"
} else {
return nil
}
}
}
var greeting = "Hello!"
if optionalName != nil {
greeting = "Hello, \(optionalName)"
}
Paste that into a playground, along with a stub implementation of checkTouchID() that returns true, and you'll immediately see in the results area that the optionalName getter is executing twice. (This would be a problem in a more realistic scenario, because you probably don't want code like this to implicitly checkTouchID() or downloadFromServer() or billApplePay() twice.) If you use an if-let construction instead, you'll only execute the getter once.
In a series of chained optionals (like if let johnsStreet = john.residence?.address?.street in the docs linked above), you don't want to rewrite the whole chain in the body of the if statement, much less recompute it.
I think the purpose of that assignment was to demonstrate the use of "let" within the if conditional clause. I don't see a meaningful difference between the provided code and your own.
From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/il/jEUH0.l
“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.”