My program checks if an NSError object exists, and sends it to another method, like this:
if([response isEqualToString:#""]) {
[self handleError:commandError];
}
In handleError:, I try checking the localized description against an expected string like this:
-(void)handleError:(NSError*)error
{
NSString* errorDescription = [error localizedDescription];
NSLog(#"%#",errorDescription); //works fine
if([errorDescription isEqualToString:#"sudo: no tty present and no askpass program specified"]) {
NSLog(#"SO Warning: Attempted to execute sudo command");
}
}
However, the if statement isn't firing. The log outputs precisely the same thing I typed out in the if statement.
Unless you seriously think the If statement structure of iOS is broken, or the isEqualToString method implementation is broken, then the strings aren't the same and there is no mystery:
What you typed out is either using different characters (see: unicode and character encoding types) or there are invisible/nonprinting characters in your log output that you're not typing because you can't see them.
I'd suggest looping through the characters in your string and printing out the byte code values:
for (i=0 to length of string) : print [errorDescription characterAtIndex:i];
You'll find that the byte code sequence of the string you typed is not equal to the byte code sequence returned by localizedDescription method.
As others have said, basing program logic on exact character strings you don't control and which can change without notice is likely not an optimum solution here. What about error codes?
I would suggest using error codes, since you're using a library over which you have no control, usually the exposed interface should tell you what are the error codes associated to every type of expected errors. Using error code would make your code stronger, clear and string independent.
Anyway if you would prefer to continue comparing the strings values, because you have a good reason to do so, I'd suggest being aware of possible punctuation, formatting characters such as newlines for example, or lowercase / uppercase letters .
Related
In C, before using the scanf or gets "stdio.h" functions to get and store user input, the programmer has to manually allocate memory for the data that's read to be stored in. In Rust, the std::io::Stdin.read_line function can seemingly be used without the programmer having to manually allocate memory prior. All it needs is for there to be a mutable String variable to store the data it reads in. How does it do this seemingly without knowledge about how much memory will be required?
Well, if you want a detailed explanation, you can dig a bit into the read_line method which is part of the BufRead trait. Heavily simplified, the function look like this.
fn read_line(&mut self, target: &mut String)
loop {
// That method fills the internal buffer of the reader (here stdin)
// and returns a slice reference to whatever part of the buffer was filled.
// That buffer is actually what you need to allocate in advance in C.
let available = self.fill_buf();
match memchr(b'\n', available) {
Some(i) => {
// A '\n' was found, we can extend the string and return.
target.push_str(&available[..=i]);
return;
}
None => {
// No '\n' found, we just have to extend the string.
target.push_str(available);
},
}
}
}
So basically, that method extends the string as long as it does not find a \n character in stdin.
If you want to allocate a bit of memory in advance for the String that you pass to read_line, you can create it using String::with_capacity. This will not prevent the String to reallocate if it is not large enough though.
I encountered an error in a script I was debugging because somebody had created a variable with a name matching a built-in function, rendering the function inaccessible. I got strange errors when I tried to use the function, like:
incorrect arguments for (-)
incorrect arguments for (by)
incorrect arguments for ([)
incorrect arguments for (=)
Example code:
int length
// ...
// ...
string substr
string str = "big long string with lots of text"
substr = str[0:length(str)-2]
Is there a way to access the original length() function in this situation? I was actually just trying to add debug output to the existing script, not trying to modify the script, when I encountered this error.
For now I have just renamed the variable.
Well, in the case that you had no chance to modify the code, e.g. because it is encrypted you could do sth like
int length_original (string s) { return length s }
<<here is the code of your function>>
int length (string s) {return length_original s }
I am writing code to generate a JavaCC parser, which will read a user's input and check if it is in any one of a set of languages defined in my code.
One condition on allowable input is that it must not be empty - i.e., the user must enter some block of characters (with length greater than or equal to 1) other than white space " ".
I would like to be able to determine if the user's input is empty, so that an error message can be printed out on the screen in that case.
I have written a production (a.k.a rule) that gets the user's input; it's called Input() and is declared to be void.
In the main method, I have tried to write code which determines if the user's input is empty, by writing:
if parser.Input() == null {
// print error message onto the screen
}
However, I get an error message on the terminal when I try to compile, stating that a 'void' type is not allowed here (I am sure this is referring to Input).
Could I please have a hint/hints for getting around this issue?
Write the Input production like this
boolean Input() : {
} {
<EOF>
{return true;}
|
... // other possibilities here
{return false;}
}
Then, in the main method, you can write
if( parser.Input() ) {
... // report error
}
This solves the problem of reporting the error.
However you may also want to report the language found. For that you could make an enumeration type and have Input return a member of the enumeration. EMPTY could be one of the possibilities.
Language lang = parser.Input() ;
switch( lang ) {
case EMPTY:
... // report error
break ;
case LANGA:
...
break ;
... // etc.
}
Change your type method so this can return a value and you can validate the result, when you do this but change the comparison like this:
if null==parser.Input(){
//print error message on screen
}
Another option is to validate data inside your Input method so you keep it like void.
Good day,
I have problem. I want to simulate some errors in hacklang.
<?hh
namespace Exsys\HHVM;
class HHVMFacade{
private $vector = Vector {1,2,3};
public function echoProduct() : Vector<string>{
return $this->vector;
}
public function test(Vector<string> $vector) : void{
var_dump($vector);
}
}
Function echoProduct() returns Vector of strings. But private property $vector is Vector of integers. When I call echoFunction and returning value use as argument for function test(). I get
object(HH\Vector)#35357 (3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
Why? I am expecting some error because types mismatch.
There's two things at play here:
Generics aren't reified, so the runtime has no information about them. This means the runtime is only checking that you're returning a Vector.
$this->vector itself isn't typed. This means the type checker (hh_client) treats it as a unknown type. Unknown types match against everything, so there's no problem returning an unknown type where a Vector<string> is expected.
This is to allow you to gradually type your code. Whenever a type isn't known, the type checker just assumes that the developer knows what's happening.
The first thing I'd do is change the file from partial mode to strict mode, which simply involves changing from <?hh to <?hh // strict. This causes the type checker to complain about any missing type information (as well as a couple of other things, like no superglobals and you can't call non-Hack code).
This produces the error:
test.hh:6:13,19: Please add a type hint (Naming[2001])
If you then type $vector as Vector<int> (private Vector<int> $vector), hh_client then produces:
test.hh:9:16,28: Invalid return type (Typing[4110])
test.hh:8:44,49: This is a string
test.hh:6:20,22: It is incompatible with an int
test.hh:8:44,49: Considering that this type argument is invariant with respect to Vector
Which is the error you expected. You can also get this error simply by adding the type to $vector, without switching to strict mode, though I prefer to write my Hack in the strongest mode that the code supports.
With more recent versions of HHVM, the type checker is called whenever Hack code is run (there's an INI flag to turn this off), so causing the type mismatch will also cause execution of the code to fail.
I am doing the project and I am structed in database path. I am using the sqlite database for storing. In this my problems is when I updating the table it showing the error. For database part I am using prewritten classes. I am calling that class method whenever I need. See below you can understand.
This below code is working fine
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:#"MESSAGE_ID='1234'"];
but when I am sending the object to the "where", It showing some error.
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:#"MESSAGE_ID=%#",#"hai"];
i am getting the error:
"too many arguments to methods call expected 3,have 4".
here MESSAGE_ID is VARCHAR TYPE
The issue is clear here. You can not pass string format because compiler compiles parameter before converting into string format. From your method declaration allowed parameters must be 3.
So compiler detect 4 parameter as you pass string with format.
Also in sqlite database for VARCHAR type field use double quotes for field values.
So your string should be like this:
NSString *whereClauseString = [NSString stringWithFormat:#"MESSAGE_ID = \"%#\"",#"hai"];
Or if value is pre known simply create string like this:
NSString *whereClauseString = #"MESSAGE_ID = \"hai\"";
And then use this string as third parameter for updateTable method:
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:whereClauseString];
make this in two step.
NSString *strWhere=[NSString stringWithFormat:#"MESSAGE_ID='%#'",#"hai"];
[DataCachingHelper updateTable:#"sendertable" data:dic3 where:strWhere];