I have a desire to satisfy compiler warning level 5. So I have 32 warnings in one file FS0052 The value has been copied to ensure the original is not mutated by this operation
I've followed the only SO post that seems to be related to this warning, but since my type is being type provider generated by Microsoft I can't just go mark the field mutable to quiet the warning. plus making something mutable that actually shouldn't ever be mutated seems like a hack not a fix.
examples:
Nullable .GetValueOrDefault()
Nullable .ToString()
Guid .toString()
struct method calls of any sort I believe
What is the recommended way to deal with this warning from a proper functional perspective?
Not sure if you're still interested.
It seems to me that the compiler emits the warning when it is unsure whether the method call is going to destroy the state of original instance (this should mostly come from any library outside F#).
Explicit copy the value into a variable is, in my case, often mitigate the warning. For example:
open System
// generate the warning due to "ToString()"
let DirSeparator = Path.DirectorySeparatorChar.ToString()
// no warning
let ExplicitCopy = let x = Path.DirectorySeparatorChar in x.ToString()
let Alternative = sprintf "%c" Path.DirectorySeparatorChar
What is the recommended way to deal with this warning from a proper
functional perspective?
I found many questions about the issue, but this particular question I found nowhere else. After having fixed many such warnings, this is my conclusion.
I believe there is no single solution. (Unless you want to resort to silencing the warning all over the place with a compiler directive or something, and I certainly don't want to do that. I have a feeling you agree with me on that, having bumped up the warning level to 5.)
First option
There is frequently another way to code, without having to resort to intermediate values or other complex expressions.
For example, to silence the warning in this case
myStruct.someField <- myRecord.SomeField.ToString()
simply change it to
myStruct.someField <- string myRecord.SomeField
Second option
If you do not find a function or some way to easily rewrite your way out of it, and it is a particular case that repeats frequently in your source, then there is the possibility to create a function or functions that you can use in these cases in order to silence the warning.
For example, I use this function instead of GetValueOrDefault.
let valueOrDefault (v: 'a Nullable) = if v.HasValue then v.Value else Unchecked.defaultof<'a>
Third option
If you have only a single particular case or barely a handful of similar cases, then using an intermediate value is possibly the easiest way to silence the warning. I tend to comment the reason for the verbosity in these cases.
Related
Status: Sort of solved. Switching Lua.Ref (close equivalent to LuaD LuaObject) to struct as suggested in answer has solved most issues related to freeing references, and I changed back to similar mechanism LuaD uses. More about this in the end.
In one of my project, I am working with Lua interface. I have mainly borrowed the ideas from LuaD. The mechanism in LuaD uses lua_ref & lua_unref to be able to move lua table/function references in D space, but this causes heavy problems because the calls to destructors and their order is not guaranteed. LuaD usually segfaults at least at the program exit.
Because it seems that LuaD is not maintained anymore, I decided to write my own interface for my purposes. My Lua interface class is here: https://github.com/mkoskim/games/blob/master/engine/util/lua.d
Usage examples can be found here:
https://github.com/mkoskim/games/blob/master/demo/luasketch/luademo.d
And in case you need, the Lua script used by the example is here:
https://github.com/mkoskim/games/blob/master/demo/luasketch/data/test.lua
The interface works like this:
Lua.opIndex pushes global table and index key to stack, and return Top object. For example, lua["math"] pushes _G and "math" to stack.
Further accesses go through Top object. Top.opIndex goes deeper in the table hierarchy. Other methods (call, get, set) are "final" methods, which perform an operation with the table and key at the top of the stack, and clean the stack afterwards.
Close everything works fine, except this mechanism has nasty quirk/bug that I have no idea how to solve it. If you don't call any of those "final" methods, Top will leave table and key to the stack:
lua["math"]["abs"].call(-1); // Works. Final method (call) called.
lua["math"]["abs"]; // table ref & key left to stack :(
What I know for sure, is that playing with Top() destructor does not work, as it is not called immediately when object is not referenced anymore.
NOTE: If there is some sort of operator to be called when object is accessed as rvalue, I could replace call(), set() and get() methods with operator overloads.
Questions:
Is there any way to prevent users to write such expressions (getting Top object without calling any of "final" methods)? I really don't want users to write e.g. luafunc = lua["math"]["abs"] and then later try to call it, because it won't work at all. Not without starting to play with lua_ref & lua_unref and start fighting with same issues that LuaD has.
Is there any kind of opAccess operator overloading, that is, overloading what happens when object is used as rvalue? That is, expression "a = b" -> "a.opAssign(b.opAccess)"? opCast does not work, it is called only with explicit casts.
Any other suggestions? I internally feel that I am looking solution from wrong direction. I feel that the problem reside in the realm of metaprogramming: I am trying to "scope" things at expression level, which I feel is not that suitable for classes and objects.
So far, I have tried to preserve the LuaD look'n'feel at interface user's side, but I think that if I could change the interface to something like following, I could get it working:
lua.call(["math", "abs"], 1); // call lua.math.abs(2)
lua.get(["table", "x", "y", "z"], 2); // lua table.x.y.z = 2
...
Syntactically that would ensure that reference to lua object fetched by indexing is finally used for something in the expression, and the stack would be cleaned.
UPDATE: Like said, changing Lua.Ref to struct solved problems related to dereferencing, and I am again using reference mechanism similar to LuaD. I personally feel that this mechanism suits the LuaD-style syntax I am using, too, and it can be quite a challenge to make the syntax working correctly with other mechanisms. I am still open to hear if someone has ideas to make it work.
The system I sketched to replace references (to tackle the problem with objects holding references living longer than lua sandbox) would probably need different kind of interface, something similar I sketched above.
You also have an issue when people do
auto math_abs = lua["math"]["abs"];
math_abs.call(1);
math_abs.call(3);
This will double pop.
Make Top a struct that holds the stack index of what they are referencing. That way you can use its known scoping and destruction behavior to your advantage. Make sure you handle this(this) correctly as well.
Only pop in the destructor when the value is the actual top value. You can use a bitset in LuaInterface to track which stack positions are in use and put the values in it using lua_replace if you are worried about excessive stack use.
This is more a simple personal attempt to understand what goes on inside Rascal. There must be better (if not already supported) solution.
Here's the code:
fileLoad = |home:///PHPAnalysis/systems/ApilTestScripts/simple1.php|;
fileAST=loadPHPFile(fileLoad,true,false);
//assign a simple id to each node
public map[value,int] assignID12(node N)
{
myID=();
visit(N)
{
case node M:
{
name=getName(M);
myID[name] =999;
}
}
return myID;
}
ids=assignID12(fileAST);
gives me
|stdin:///|(92,4,<1,92>,<1,96>): Expected str, but got value
loadPHPFile returns a node of type: list[Stmt], where each Stmt is one of the many types of statements that could occur in a program (PHP, in my case). Without going into why I'd do this, why doesn't the above code work? Especially frustrating because a very simple example is worked out in the online documentation. See: http://tutor.rascal-mpl.org/Recipes/Basic/Basic.html#/Recipes/Common/CountConstructors/CountConstructors.html
I started a new console, and it seems to work. Of course, I changed the return type from map[value,int] to map[str,int] as it was originally in the example.
The problem I was having was that I may have erroneously defined the function previously. While I quickly fixed an apparent problem, it kept giving me errors. I realized that in Rascal, when you've started a console and imported certain definitions, it (seems)is impossible to overwrite those definitions. The interpreter keeps making reference to the very first definition that you provided. This could just be the interpreter performing a type-check, and preventing unintentional and/or incompatible assignments further down the road. That makes sense for variables (in the typical program sense), but it doesn't seem like the best idea to enforce that on functions (or methods). I feel it becomes cumbersome, because a user typically has to undergo some iterations before he/she is satisfied with a function definition. Just my opinion though...
Most likely you already had the name ids in scope as having type map[str,int], which would be the direct source of the error. You can look in script https://github.com/cwi-swat/php-analysis/blob/master/src/lang/php/analysis/cfg/LabelState.rsc at the function labelScript to see how this is done in PHP AiR (so you don't need to write this code yourself). What this will give you is a script where all the expressions and statements have an assigned ID, as well as the label state, which just keeps track of some info used in this labeling operation (mainly the counter to generate a unique ID).
As for the earlier response, the best thing to do is to give your definitions in modules which you can import. If you do that, any changes to types, etc will be picked up (automatically if the module is already imported, since Rascal will reimport the module for you if it has changed, or when you next import the module). However, if you define something directly in the console, this won't happen. Think of the console as one large module that you keep adding to. Since we can have overloads of functions, if you define the function again you are really defining a new alternative to the function, but this may not work like you expect.
Given a List, is it possible to test whether the list is growable?
Trying to set the length and catching an UnsupportedError seems like a solution (though it isn't clear what would happen if you just set the length to the same value). Any better solution?
There is no way to detect if a list is growable (short of using reflection to find the implementation type, which is brittle, won't work the same way in dart2js, and increases code size).
The only valid use-case we encountered was to have checks/asserts when a library returns a list. In all other cases a function/library tried to modify an argument without knowing if it was allowed to do that.
If a function/library can work destructively it should require a boolean (or similar) so that the callers can decide if their argument can be changed. The callee should never silently modify its inputs unless it is obvious (for example fillFoo(list)) or an argument tells it so (for instance computeSquares(list, inPlace: true)).
http://dartbug.com/13926 is still open, but I expect it to be closed tomorrow with status "NotPlanned".
It is possible using reflection (not straight-forward either).
I guess this isn't any better than catching the exception.
print(MirrorSystem.getName(reflect(new List.from([0,1,2], growable: true))
.type.simpleName) == ('_GrowableList'));
EDIT
It is discouraged to use the name of a symbol - see Converting a Symbol into a String
According to the documentation for Option.Value<'T>:
Get the value of a Some option. A NullReferenceException is raised if
the option is None.
and
This function is for use by compiled F# code and should not be used
directly.
Does the last sentence imply that it's due to interop? What's the use case if so?
Otherwise it seems very strange since the whole point of the Option type is to make the possibility of undefined values explicit and encourage handling of them, which easily can be circumvented:
let none : int option = None
let value = none.Value
I imagine it is there so that
match v with
|Some(t) -> t
works - without that Value property, you wouldn't be able to get the t with any functions which are available to F# code (Note there are some DU properties which are not accesible from F# which are an alternative here). There may also be some very minor speed benifits if you know that the option is Some as you don't check it if you use value directly
I have been reading up on the c++ auto_ptr and unique_ptr and stuff and thought to try and use them in a class I am playing with... but I was having trouble getting it to work...
How would I convert these pointers to auto pointers or some equivalent so the deletion of the pointers is handled automatically?
Header - http://ideone.com/Z9bc5
Body - http://ideone.com/WfwBY
At the moment it is working using normal pointers but I sometimes get a access violation error. I am pretty sure I know what it causing it.. but the "best" way might be to use the automatic deletion stuff recently added to c++11?
Thanks in advance.
Don't use auto_ptr. Try one of unique_ptr or shared_ptr. Here's Sutter explaining when to use which:
When in doubt, prefer unique_ptr by default, and you can always later move-convert to shared_ptr if you need it. If you know from the start you need shared ownership, however, go directly to shared_ptr via make_shared (see #2 below).
Also from his blog-post:
3. What’s the deal with auto_ptr?
auto_ptr is most charitably characterized as a valiant attempt to
create a unique_ptr before C++ had move semantics.
auto_ptr is now deprecated, and should not be used in new code. When
you get a chance, try doing a global search-and-replace of auto_ptr to
unique_ptr in your code base; the vast majority of uses will work the
same, and it might expose (as a compile-time error) or fix (silently)
a bug or two you didn’t know you had.
So, your member declarations change from:
sf::Texture * tSpriteSheet;
to:
std::unique_ptr<sf::Texture> tSpriteSheet;
As for member functions which return a raw pointer you have but the obvious choice: You cannot return a unique_ptr if the class is not movable. So, you can either:
Keep the signature as-is
Return a const& unique_ptr<T>
Return a reference to the object
Choose the one that suits your needs the best.