I'm getting the following analyzer warning on this line...
if ([datStartDate compare:now] == NSOrderedDescending) {
Receiver in message expression is an uninitialized value
The line of code occurs in the middle of an IBAction.
What am I doing wrong?
If you expand the disclosure triangle next to the error (in the error navigator on the left side), it'll show you the exact code path that leads to a situation where the value is not initialized.
You may think "But, analyzer, really, that can never happen.". While that may be true, you are creating an assumption in your code that may not hold true in the future due to bug or intentional change. That increases the fragility of your codebase and will lead to maintenance headaches.
Fix the code such that it is explicit and remove the assumption.
There is at least one code path that can lead to this line with datStartDate still being uninitialized. That means you have never assigned an object to datStartDate, not even nil.
Related
I am getting an error only when the code is entered line by line in the repl. It works when the whole program is pasted at once, or from the command line.
class A {
method a () {
return 1;
}
}
class B {
method b () {
return 2;
}
}
This is the error statement:
===SORRY!=== Error while compiling:
Package 'B' already has a method 'b' (did you mean to declare a multi method?)
This screen shot might make it clearer. On the left I just pasted the code, and on the right I entered it line by line. The code is still working but what is causing the error?
For some reason, I could not reproduce this using just one class.
I can reproduce that error, and looks like a REPL bug, or simply something the REPL is not prepared to do. This, for instance, will also raise an exception:
class A {
method a() {
return 1;
}
};
class foo {
has $.bar = 3;
};
In either form, either pasting it directly or in pieces. It's always the second class. It's probably related to the way EVAL works, but I really don't know. At the end of the day, the REPL can only take you so far and I'm not totally sure this is within the use case. You might want to use Comma or any other IDE, like emacs, for anything that's more complicated than a line; Comma also provides help for evaluating expressions, and even grammars.
I think Comma is the bees knees. And I almost never use the repl. But I enjoy:
Golfing Your example is a more than adequate MRE. But I love minimizing bug examples.
Speculating I think I can see what's going on.
Searching issue queues Rakudo has two issue queues on GH: old and new.
Spelunking compiler code Rakudo is mostly written in Raku; maybe we can work out what this problem is in the REPL code (which is part of the compiler)?
Golfing
First, the bug:
Welcome to ๐๐๐ค๐ฎ๐๐จโข v2021.03.
Implementing the ๐๐๐ค๐ฎโข programming language v6.d.
Built on MoarVM version 2021.03.
To exit type 'exit' or '^D'
> # 42
Nil
> { subset a
*
===SORRY!=== Error while compiling:
Redeclaration of symbol 'a'.
at line 3
------> <BOL>โ<EOL>
Commentary:
To get on the fairway, enter any line that's not just whitespace, and press Enter.
Pick the right iron; open a block with {, declare some named type, and press Enter. The REPL indicates you're on the green by displaying the * multi-line prompt.
To sink the ball, just hit Enter.
Second, golfing in aid of speculation:
> # 42
Nil
> { BEGIN say 99
99
* }
99
>
(BEGIN marks code that is to be run during compilation as soon as the compiler encounters it.)
Speculating
Why does the initial # 42 evaluation matter? Presumably the REPL tries to maintain declarations / state (of variables and types etc) during a REPL session.
And as part of that it's presumably remembering all previous code in a session.
And presumably it's seeing anything but blank lines as counting as previous code.
And the mere existence of some/any previous code somehow influences what state the REPL is maintaining and/or what it's asking the compiler to do.
Maybe.
Why does a type declaration matter when, say, a variable declaration doesn't?
Presumably the REPL and/or compiler is distinguishing between these two kinds of declaration.
Ignoring the REPL, when compiling code, a repeated my declaration only raises a warning, whereas a repeated type declaration is an error. Quite plausibly that's why?
Why does a type declaration have this effect?
Presumably the type successfully compiles and only after that an exception is thrown (because the code is incomplete due to the missing closing brace).
Then the REPL asks the compiler to again try to compile the multi-line code thus far entered, with whatever additional code the user has typed (in my golf version I type nothing and just hit Enter, adding no more code).
This repeated compile attempt includes the type declaration again, which type declaration, because the compilation state from the prior attempt to compile the multi-line code is somehow being retained, is seen by the compiler as a repeat declaration, causing it to throw an exception that causes the REPL to exit multi-line mode and report the error.
In other words, the REPL loop is presumably something like:
As each line is entered, pass it to the compiler, which compiles the code and throws an exception if anything goes wrong.
If an exception is thrown:
2.1 If in multi-line mode (with * prompt), then exit multi-line mode (go back to > prompt) and display exception message.
2.2 Else (so not in multi-line mode), if analysis (plausibly very basic) of the exception and/or entered code suggests multi-line mode would be useful, then enter that mode (with * prompt). In multi-line mode, the entire multi-line of code so far is recompiled each time the user presses Enter.
2.3 Else, display exception message.
(Obviously there's something else going on related to initialization given the need to start with some evaluation to manifest this bug, but that may well be a completely distinct issue.)
Searching
I've browsed through all open Rakudo issues in its old and new queues on GH that match 'repl'. I've selected four that illustrate the range of difficulties the REPL has with maintaining the state of a session:
REPL loses custom operators. "Interestingly, if a postfix operator like this is exported by a module which is loaded by the REPL, the REPL can successfully parse that operator just once, after which it will fail with an error similar to the above." Is this related to the way the bug this SO is focused on doesn't manifest until it's a second or later evaluation?
Perl6 REPL forgets the definition of infix sub. Looks like a dupe of the above issue, but includes extra debugging goodies from Brian Duggan. โค๏ธ
REPL messes up namespaces when Foo is used after Foo::Bar.
In REPL cannot bind to scalars declared on earlier lines.
One thing I haven't done is checked whether these bugs all still exist. My guess is they do. And there are many others like them. Perhaps they have a somewhat common cause? I've no idea. Perhaps we need to look at the code...
Spelunking
A search of the Rakudo sources for 'repl' quickly led to a REPL module. Less than 500 lines of high level Raku code! \o/ (For now, let's just pretend we can pretty much ignore digging into the code it calls...)
From my initial browser, I'll draw attention to:
A sub repl:
sub repl(*%_) {
my $repl := REPL.new(nqp::getcomp("Raku"), %_, True);
nqp::bindattr($repl,REPL,'$!save_ctx',nqp::ctxcaller(nqp::ctx));
$repl.repl-loop(:no-exit);
}
Blame shows that Liz added this a couple months ago. It's very tangential to this bug, but I'm guessing methods and variables with ctx in their name are pretty central to things so this is hopefully a nice way to start pondering that.
method repl-eval. 30 lines or so.
REPL: loop { ... }. 60 lines or so.
That'll do for tonight. I'll post this then return to it all another day.
What is the difference between these two lines?
Set MyMsg = MyMsg.Move(MyFolder2)
MyMsg.Move(MyFolder2)
The first one works just fine.
The second one usually gives an "Outlook is not responding" error.
The MailItem.Move method returns the MailItem that has been moved. Usually, properties return values and methods don't return anything. But for several methods, the designers decided it would be handy to have a return value, so they made them return a value (or object).
When you assign a method to a variable, any arguments must be in parentheses or you'll get a syntax error. If you call a method without assigning it to a variable (because you don't care what the method returns or it's one of the methods that doesn't return a value), then the arguments must not be in parentheses (kind of).
Parentheses, when used in places that the compiler does not require them, are the equivalent of saying "evaluate this before doing anything else". It's like how you use parentheses in order of operations so you can say "evaluate this addition operation before you do this multiplication even though that's not the normal order".
The (kind of) remark above is because most of the time when you "incorrectly" put parentheses around something, it doesn't matter.
Application.CreateItem 0
and
Application.CreateItem (0)
are the same. The second one evaluates the argument before it passes it to CreateItem, but evaluating a single integer takes no time and has no ill effects. The parentheses aren't necessary because we're not assigning the results to a variable, but they're not really hurting anything either.
In your second example, you're telling the compiler to evaluate the folder, then send it to the Move method. I don't know what evaluating a folder means, but I gather it's not good. It probably does something like create an array of all the objects in that folder, or something equally intensive. When Outlook is not responding, it means you gave it such a big job that it hasn't checked back in with the operating system in a timely fashion.
So: Use parentheses for arguments when it's on the right side of an equal sign. Don't use them when it's not. There are a few exceptions to that rule, but you may never need to know them.
There is no difference between the two (you just ignore the function result) unless you actually use the MyMsg variable afterwards - after the message is moved, you cannot access it anymore.
Use the first version.
I've made a large program that opens and closes files and databases, perform writes and reads on them etc among other things. Since there no such thing as "exception handling in go", and since I didn't really know about "defer" statement and "recover()" function, I applied error checking after every file-open, read-write, database entry etc. E.g.
_,insert_err := stmt.Run(query)
if insert_err != nil{
mylogs.Error(insert_err.Error())
return db_updation_status
}
For this, I define db_updation_status at the beginning as "false" and do not make it "true" until everything in the program goes right.
I've done this in every function, after every operation which I believe could go wrong.
Do you think there's a better way to do this using defer-panic-recover? I read about these here http://golang.org/doc/articles/defer_panic_recover.html, but can't clearly get how to use them. Do these constructs offer something similar to exception-handling? Am I better off without these constructs?
I would really appreciate if someone could explain this to me in a simple language, and/or provide a use case for these constructs and compare them to the type of error handling I've used above.
It's more handy to return error values - they can carry more information (advantage to the client/user) than a two valued bool.
What concerns panic/recover: There are scenarios where their use is completely sane. For example, in a hand written recursive descent parser, it's quite a PITA to "bubble" up an error condition through all the invocation levels. In this example, it's a welcome simplification if there's a deferred recover at the top most (API) level and one can report any kind of error at any invocation level using, for example
panic(fmt.Errorf("Cannot %v in %v", foo, bar))
If an operation can fail and returns an error, than checking this error immediately and handling it properly is idiomatic in go, simple and nice to check if anything gets handled properly.
Don't use defer/recover for such things: Needed cleanup actions are hard to code, especially if stuff gets nested.
The usual way to report an error to a caller is to return an error as an extra return value. The canonical Read method is a well-known instance; it returns a byte count and an error.
But what if the error is unrecoverable? Sometimes the program simply cannot continue.
For this purpose, there is a built-in function panic that in effect creates a run-time error that will stop the program (but see the next section). The function takes a single argument of arbitrary typeโoften a stringโto be printed as the program dies. It's also a way to indicate that something impossible has happened, such as exiting an infinite loop.
http://golang.org/doc/effective_go.html#errors
I have this code:
id error;
// a bunch of stuff, including using error
Finalization finalization = ^(int status) {
id error; // <--- Declaration shadows a local variable
// a bunch of stuff, using error
}
// a bunch of stuff, using error
I use GCC_WARN_SHADOW because it's what I want in every case in my code except this one. In this case, it gives me a warning that I want to suppress.
Is there a way to suppress this one shadow warning without turning off GCC_WARN_SHADOW or renaming the inner error to something else? Some way to mark that declaration of error?
I'm using clang with Xcode 4, if it matters.
First, as a matter of opinion, it's really bad karma to shadow a local variable within an inner block (its bad enough shadowing a global variable in a function). Now "error" can take two different values within a function, and until whomever is reading your code figures it out, they will bang their head quite incessantly. I have seen this issue in real life among paid professionals developing apps. I really suggest renaming the inner error variable.
Answering your question, you can use the GCC/clang compiler pragma to suppress a warning.
Today I discovered that something I had assumed about VB.NET for many years was not true (worrying!). I assumed that a variable declared within a loop had a lifetime of the iteration it was declared in, but in fact it seems it has a lifetime of the whole procedure.
For example:
For i As Integer = 0 To 1
Dim var1 As Boolean
Console.WriteLine(var1.ToString())
var1 = True
Console.WriteLine(var1.ToString())
Next
Console.ReadKey()
I had assumed an output of False, True, False, True but instead it is actually False, True, True, True.
In C# the equivalent code would not compile as you would get a compile time error of Error "Use of unassigned local variable 'var1'".
I realise there are many ways to fix this and that best practice would be to declare the variable outside of the loop and reset it at the beginning of every loop through.
I find this behaviour so counter-intuitive to me that I would like at least a compile time warning in VB.NET when/if I do this. (I could also then set this on any projects I already have and get warning that would allow me to check that my assumptions aren't causing errors).
Does anyone know how/if I can get this to generate a compile time warning in VB.NET? Am I the only one that finds this counter-intuitive?
We'll have to work on fixing your intuition because getting an error out of the compiler is not an option. It is partially implemented, you can get this warning:
error BC42104: Variable 'mumble' is used before it has been assigned a value. A null reference exception could result at runtime.
And elevate it from a warning to an error with Project + Properties, Compile tab. However, as the warning message indicates, this is only supported for reference type references, it won't budge for a variable of a value type.
Okay, intuition. If the runtime would implement your desired behavior then it would have to allocate a new variable for each iteration of the loop. Which implies that the number of local variables is bounded only by the number of iterations. This is very wasteful and a very easy trigger for StackOverflowException. The JIT compiler doesn't do this, it re-uses the variable. This happens in C# as well, minus the option of letting you not initialize the value explicitly of course.
Fwiw: I very much agree with you that this is unhelpful behavior. You'll probably find receptive ears at connect.microsoft.com, post your feature request there and the VB.NET team will see it. There has been strong backing from customers as well as within MSFT to make VB.NET and C# feature comparable. If you post a link to your feedback report then I'll be happy to vote it up.