What does this warning mean? Is there any way we can avoid this warning? I tried to understand the message from the compiler code here but I couldn't.
frege> native sysin "java.lang.System.in" :: InputStream
native function sysin :: InputStream
3: note that the java expression
java.lang.System.in is supposed to be
constant.
I also tried the code below but got the same warning:
frege> native sysin "java.lang.System.in" :: MutableIO InputStream
native function sysin :: MutableIO InputStream
3: note that the java expression
java.lang.System.in is supposed to be
constant.
It is simply a reminder that the java value could change over the lifetime of the program, but you, the programmer, assume its de-facto immutability by using this notation.
In fact, one can re-assign those fields on the Java level. In this case, Frege code could still return the previous value that it may have cached somewhere. Or it could violate referential transparency, so that sysin does not mean the same everywhere.
If you need to make sure that you get the current value of a mutable field, you need to declare it as IO or ST.
This feature is thought as a relief for the cases when we know that a value won't change, so that we can write:
dosomething sysin
instead of
sysin >>= dosomething
This is used, for example, in frege.java.IO, where stdin, stdout and stderr are defined that way.
The warning cannot be supressed, except by compiling with nowarn. This feature should simply not be used unless you're absolutly sure you're doing the right thing, that is, when a proper IO or ST action would produce the very same value all the time.
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.
I am using the COSMIC compiler in the STVD ide and even though optimization is turned of with -no (documentation says "-no: do not use optimizer") some lines of code get removed and cannot have a breakpoint placed upon them, nor are they to be found in the disassembly.
I tried to set -oc (leave removed instructions as comments) which resulted in not even showing the removed lines as comment.
bool foo(void)
{
uint8_t val;
if (globalvar > 5)
val = 0;
for (val = 0; val < 8; val++)
{
some code...
}
return true;
}
I do know it seems idiotic to set val to 0 prior to the for loop but lets just assume it is for some reason necessary. When I set no optimization I expect it to be not optimized but insted the val = 0; gets removed without any traces.
I am not looking for a workaround like declaring val volatile whitch solves the problem. I am rather looking for a way to prevent the optimization or at least understand/know what changes are made to my code when compiling.
It is not clear from the manual, but it seems that the -no option prevents assembly level optimisation. It seems possible that the code generator stage that runs before assembly optimisation may perform higher level optimisation such as redundant code removal.
From the manual:
-cp
disable the constant propagation optimization. By default,
when a variable is assigned with a constant, any subsequent access to that variable is replaced by the constant
itself until the variable is modified or a flow break is
encountered (function call, loop, label ...).
It seems that it is this constant propagation feature that you must explicitly disable.
It is unusual perhaps, but it appears that this compiler optimises by default, and distinguishes between compiler optimisations and assembler optimisations (performed as the compilation stage), and them makes you switch off each individual optimisation separately.
To avoid this in the code, rather than switching it off globally, you could initialise val to a non-zero value in this case:
int val = -1 ;
Then the later assignment to zero will require explicit code. This has the advantage over volatile perhaps in that it will not block optimisations when you do enable them.
I believe that this behaviour is allowed by the C language specification.
You are effectively writing the same value either once or twice to the same variable on successive lines of code. The compiler could assign this value to either a processor register or a memory location as it sees fit and knows that the value following the initial assignment in the for loop is the same as the value assigned when the if clause is actioned. As a result the language spec allows the compiler to throw the redundant code away.
The way to force the compiler to perform all read and write accesses to the variable is to use the volatile keyword. That is what it is for.
After some discussion on the question found here Correct execution of Final routine in Fortran
I thought it will be useful to know when a function with a pointer result is appropriate to use with a normal or a pointer assignment. For example, given this simple function
function pointer_result(this)
implicit none
type(test_type),intent(in) pointer :: this
type(test_type), pointer :: pointer_result
allocate(pointer_result)
end function
I would normally do test=>pointer_result(test), where test has been declared with the pointer attribute. While the normal assignment test=pointer_result(test) is legal it means something different.
What does the normal assignment imply compared to the pointer assignment?
When does it make sense to use one or the other assignment?
A normal assignment
test = pointer_result()
means that the value of the current target of test will be overwritten by the value pointed to by the resulting pointer. If test points to some invalid address (is undefined or null) the program will crash or produce undefined results. The anonymous target allocated by the function will have no pointer to it any more and the memory will be leaked.
There is hardly any legitimate use for this, but it is likely to happen when one makes a typo and writes = instead of =>. It is a very easy one to make and several style guides recommend to never use pointer functions.
I found this Rust code for getting a line from stdin:
use std::io;
fn main() {
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
println!("Input: {}", line);
}
io::stdin().read_line(&mut line) sets the line variable to a line read from stdin. From my understanding, read_line() returns a Result value, which can be pattern-matched, or .unwrap() can be used to get the inner value if it is not an Err.
However, the returned value of read_line() is never used. Only the line string variable is used, but people use .unwrap() most of the time even if it is not used.
What is the purpose of unwrap() if the returned value is not used? Just to throw an error?
What is the purpose of unwrap() if the returned value is not used? Just to throw an error?
Yes, but that's not all.
Ignoring potential errors is bad; there's a big difference between an empty line and a line that's not been read because of an error; for example in a typical "pipeline" command in a shell, the program needs to stop when it stops receiving input, otherwise the user has to kill it.
In C, ignoring errors is too easy. Many languages solve this by having exceptions, but Rust doesn't.
In order to avoid the issue plaguing C programs that it's too easy to forget to check the return code, normally Rust functions will bundle the expected return value and error in Result, so that you have to check it to get the return value.
There is one potential issue left, however: what if the caller doesn't care about the return value? Most notably, when the value is (), nobody really cares about it.
There is a bit of compiler magic invoked here: the Result structure is tagged with the #[must_use] attribute. This attribute makes it mandatory to do something with Result when it's returned.
Therefore, in your case, not only is unwrapping good, it's also the simplest way to "do something" and avoid a compilation warning.
If you don't want to "elegantly" handle cases where there is a failure to read a line from stdin (e.g. by attempting it once again or picking a default value), you can use unwrap() to trigger a panic; it silences the warning caused by a Result that is not used:
warning: unused result which must be used
--> src/main.rs:5:5
|
5 | io::stdin().read_line(&mut line);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_must_use)] on by default
This is a simplified question for the one I asked here. I'm using VS2010 (CRT v100) and it doesn't complain, in any way ever, when i double free a BSTR.
BSTR s1=SysAllocString(L"test");
SysFreeString(s1);
SysFreeString(s1);
Ok, the question is highly hypothetical (actually, the answer is :).
SysFreeString takes a BSTR, which is a pointer, which actually is a number which has a specific semantic. This means that you can provide any value as an argument to the function, not just a valid BSTR or a BSTR which was valid moments ago. In order for SysFreeString to recognize invalid values, it would need to know all the valid BSTRs and to check against all of them. You can imagine the price of that.
Besides, it is consistent with other C, C++, COM or Windows APIs: free, delete, CloseHandle, IUnknown::Release... all of them expect YOU to know whether the argument is eligible for releasing.
In a nutshell your question is: "I am calling SysFreeString with an invalid argument. Why compiler allows me this".
Visual C++ compiler allows the call and does not issue a warning because the call itself is valid: there is a match of argument type, the API function is good, this can be converted to binary code that executes. The compiler has no knowledge whether your argument is valid or not, you are responsible to track this yourselves.
The API function on the other hand expects that you pass valid argument. It might or might not check its validity. Documentation says about the argument: "The previously allocated string". So the value is okay for the first call, but afterward the pointer value is no longer a valid argument for the second call and behavior is basically undefined.
Nothing to do with the CRT, this is a winapi function. Which is C based, a language that has always given programmers enough lengths of rope to hang themselves by invoking UB with the slightest mistake. Fast and easy-to-port has forever been at odds with safe and secure.
SysFreeString() doesn't win any prizes, clearly it should have had a BOOL return type. But it can't, the IMalloc::Free() interface function was fumbled a long time ago. Nothing you can't fix yourself:
BOOL SafeSysFreeString(BSTR* str) {
if (str == NULL) {
SetLastError(ERROR_INVALID_ARGUMENT);
return FALSE;
}
SysFreeString(*str);
*str = NULL;
return TRUE;
}
Don't hesitate to yell louder, RaiseException() gives a pretty good bang that is hard to ignore. But writing COM code in C is cruel and unusual punishment, outlawed by the Geneva Convention on Programmers Rights. Use the _bstr_t or CComBSTR C++ wrapper types instead.
But do watch out when you slice the BSTR out of them, they can't help when you don't or can't use them consistently. Which is how you got into trouble with that VARIANT. Always pay extra attention when you have to leave the safety of the wrapper, there are C sharks out there.
See this quote from MSDN:
Automation may cache the space allocated for BSTRs. This speeds up
the SysAllocString/SysFreeString sequence.
(...)if the application allocates a BSTR and frees it, the free block
of memory is put into the BSTR cache by Automation(...)
This may explain why calling SysFreeString(...) twice with the same pointer does not produce a crash,since the memory is still available (kind of).