Actionscript - is it better to cast or create a new variable? Or does it matter at all? - apache-flex

I find that in my daily Flex/Flash work, I do this number a lot:
//Calling a function...
MyCustomObject(container.getChildAt(i)).mySpecialFunction();
The question is - is this the best way to do this? Should I do this:
//Calling a function
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
tempItem.mySpecialFunction();
It might be incidental but I'm just wondering if there is an "accepted" way or a preferred way to do this. The second option seems more readable but I wonder if it takes more of a performance hit to create a new variable. Or does it all come down to style and preference?

It's important to remember that there is a difference between explicit casting and using the as keyword. Casting throws an error when it fails, whereas the as keyword does not (it just returns null).
// a casting error
try {
var number:int = 666;
var urlreq:URLRequest = URLRequest( number );
} catch(e:TypeError) {
// TypeError: Error #1034: Type Coercion failed: cannot
// convert 666 to flash.net.URLRequest.
trace(e);
}
Whereas the as keyword fails silently:
var number:int = 666;
var urlreq:URLRequest = number as URLRequest;
trace(urlreq); // prints null to the debug pane
Personally, I bear these behaviours in mind when deciding method to use. Generally, I'd recommend casting explicitly, as you'll know exactly how/when a cast failed. Often, though, you might want to fail silently and continue.

It generally doesn't matter. Creating a var just creates a pointer to the object, so it's not using more memory or anything like that.
The second example is definitely more readable and debuggable and should thus be preferred.
The risk you run from creating temp vars is that you might delay or prevent garbage collection for that object. This generally isn't a problem when it's just a local var in a function; just keep scope in mind when you're creating vars and passing them around.
For in-depth on the subject, read Grant Skinner's series on resource management in AVM2:
http://www.gskinner.com/blog/archives/2006/06/as3_resource_ma.html

for the second example you might want to test for the nullity to avoid a NullPointerException when invoking "mySpecialFunction", e.g.
var tempItem:MyCustomObject = container.getChildAt(i) as MyCustomObject;
if ( tempItem )
{
tempItem.mySpecialFunction();
}
I usually prefer the second approach but you have to remember that you can only use the as operator for casting "Date" and "Array" types.

Related

Pattern for async testing with scalatest and mocking objects with mockito

I am writing unit tests for some async sections of my code (returning Futures) that also involves the need to mock a Scala object.
Following these docs, I can successfully mock the object's functions. My question stems from the fact that withObjectMocked[FooObject.type] returns Unit, where async tests in scalatest require either an Assertion or Future[Assertion] to be returned. To get around this, I'm creating vars in my tests that I reassign within the function sent to withObjectMocked[FooObject.type], which ends up looking something like this:
class SomeTest extends AsyncWordSpec with Matchers with AsyncMockitoSugar with ResetMocksAfterEachAsyncTest {
"wish i didn't need a temp var" in {
var ret: Future[Assertion] = Future.failed(new Exception("this should be something")) // <-- note the need to create the temp var
withObjectMocked[SomeObject.type] {
when(SomeObject.someFunction(any)) thenReturn Left(Error("not found"))
val mockDependency = mock[SomeDependency]
val testClass = ClassBeingTested(mockDependency)
ret = testClass.giveMeAFuture("test_id") map { r =>
r should equal(Error("not found"))
} // <-- set the real Future[Assertion] value here
}
ret // <-- finally, explicitly return the Future
}
}
My question then is, is there a better/cleaner/more idiomatic way to write async tests that mock objects without the need to jump through this bit of a hoop? For some reason, I figured using AsyncMockitoSugar instead of MockitoSugar would have solved that for me, but withObjectMocked still returns Unit. Is this maybe a bug and/or a candidate for a feature request (the async version of withObjectMocked returning the value of the function block rather than Unit)? Or am I missing how to accomplish this sort of task?
You should refrain from using mockObject in a multi-thread environment as it doesn't play well with it.
This is because the object code is stored as a singleton instance, so it's effectively global.
When you use mockObject you're efectibly forcefully overriding this var (the code takes care of restoring the original, hence the syntax of usign it as a "resource" if you want).
Because this var is global/shared, if you have multi-threaded tests you'll endup with random behaviour, this is the main reason why no async API is provided.
In any case, this is a last resort tool, every time you find yourself using it you should stop and ask yourself if there isn't anything wrong with your code first, there are quite a few patterns to help you out here (like injecting the dependency), so you should rarely have to do this.

Kotlin Bundle.putString not explicitly adding "String" but instead is "String?"

val args = Bundle()
args.putString("type", details.type)
navigator.navigate(context!!, findNavController(), Destination.TYPE, args)
I am quite confused as to why in the receiving fragment when I go to access the arguments I have passed through it is responding with...
val type: String = arguments.getString("type")
The arguments.getString is all underlined red and says "Required String Found String?" But how when I called method "putString"?!?
It is resulting in text not being rendered in the new fragment and I assume this is a nullability issue.
It's a matter of knowledge that is available in the receiving Fragment.
The Fragment is not aware of how its arguments were created (or modified) so it has to assume the "type" key you're looking for might not be in the arguments Bundle. That's why it returns a nullable (String?) result (the null value would mean absent in arguments).
Your fragment might be created in many places in your app and its arguments might have been modified in many places. We have no way of tracking that.
There are different solutions for this problem, depending on your approach in other parts of the code and how "confident" you are in creating of your Fragment.
I would usually choose a solution in which I assume setting the type is mandatory. Therefore if the type is absent - I fail fast. That would mean the Fragment was misused.
val type: String = arguments!!.getString("type")!!
The code above will crash if either:
a) arguments weren't set, or
b) String with type wasn't put in the arguments Bundle.
You are right, that is a : null ability issue.
First you should be sure if you are expecting a value, so try adding "?" or "!!", i would recommend "?", or go with the block of if {} else
To read the string safely you can use:
val type: String = arguments?.getString("type").orEmpty()
The orEmpty call at the end ensures that a valid String is returned even if either arguments or getString() returns null.
The method signature for getString() returns a nullable String. This is because at compile time, the compiler can't know if the value exists in the bundle or not. You will have the same issue when retrieving anything from any Map.
If you know for certain that the value in the bundle or map should exist at the time you call getString(), you can use the !! operator. That's what it's there for. When you know something should always be there, it is appropriate to want an exception to be thrown (in this case KNPE) if it's not there so you can easily find any programming error during testing.
isEmpty() or ?.let aren't helpful in this particular case because they would just be masking a programming error and making it harder to discover or debug.

setting CilBody.KeepOldMaxStack or MetadataOptions.Flags

While decompiling .net assembly using de4dot I am getting following message in console:
Error calculating max stack value. If the method's obfuscated, set CilBody.KeepOldMaxStack or MetadataOptions.Flags (KeepOldMaxStack, global option) to ignore this error
How do I set CilBody.KeepOldMaxStack or MetadataOptions.Flags?
Maybe a bit late, but I ran into the same problem today, finding your open question while looking for a solution, and this is how I solved it - I hope it works for you, too:
// Working with an assembly definition
var ass = AssemblyDef.Load("filename.dll");
// Do whatever you want to do with dnLib here
// Create global module writer options
var options = new ModuleWriterOptions(ass.Modules[0]);
options.MetadataOptions.Flags |= MetadataFlags.KeepOldMaxStack;
// Write the new assembly using the global writer options
ass.Write("newfilename.dll", options);
If you want to set the flag only for a selection of methods that produce the problem before writing, just for example:
// Find the type in the first module, then find the method to set the flag for
ass.Modules[0]
.Types.First((type) => type.Name == nameof(TypeToFind))
.FindMethod(nameof(MethodToFind))
.KeepOldMaxStack = true;
CilBody is maybe a bit confusing, if you're not too deep into the internal .NET assembly structures: It simply means the body object of the method that produces the problem, when writing the modified assembly. Obfuscators often try to confuse disassemblers by producing invalid structures, what may cause a problem when calculating the maxstack value before writing the assembly with dnLib. By keeping the original maxstack value, you can step over those invalid method structures.
In the context of de4dot it seems to be a bug, or the application is simply not designed to solve invalid method structures of obfuscated assemblies - in this case there's no solution for you, if the de4net developer won't fix/implement it, and you don't want to write a patch using the source code from GitHub.

Object reference not set to an instance of an object while reading from 2 textboxes

for (int i = 0; i < parts.Count; i++)
{
if (!((part)parts[i]).deleteUsed)
((part)parts[i]).hints = ((TextBox)partsView.Rows[i].Cells[4].FindControl("textBox")).Text;
((part)parts[i]).PartsWaiting = ((TextBox)partsView.Rows[i].Cells[5].FindControl("textBox1")).Text;
}
System.NullReferenceException: Object reference not set to an instance of an object.
Im getting this error for some reason, don't seem to figure out where I'm going wrong.
Your problem is partly due to multiple chained deferences e.g.
a.getB().getC().getD()
and if one of those methods returns null, you can't easily identify what's going on.
Unless you're very sure of what you're doing, I would split the above into either:
separate lines and assign intermediate variables. A null will then become apparent wrt. the line that it's on
a set of functions that dereference and throw a NullPtrException upon resolving a null. Again, your offending line will become apparent immediately.
You'll note that the above isn't particular to your immediate problem. Rather it's a useful practise when you can't be sure that chaining methods won't return null at some stage.
Its likely that FindControl is not getting the TextBoxes. Set breakpoints and watch the FindControl(). Also make sure the IDs you are using ain FindControl are correct.

Any side-effects using SqlParameterCollection.Clear Method?

I have this specific situation where I need to execute a stored procedure 3 times before I declare it failed. Why 3 times because to check if a job that was started earlier finished. I am going to ask a separate question for deciding if there is a better approach. But for now here is what I am doing.
mysqlparametersArray
do{
reader = MyStaticExecuteReader(query,mysqlparametersArray)
Read()
if(field(1)==true){
return field(2);
}
else{
//wait 1 sec
}
}while(field(1)==false);
MyStaticExecuteReader(query,mysqlparametersArray)
{
//declare command
//loop through mysqlparametersArray and add it to command
//ExecuteReader
return reader
}
Now this occasionally gave me this error:
The SqlParameter is already contained by another
SqlParameterCollection.
After doing some search I got this workaround to Clear the parameters collection so I did this:
MyStaticExecuteReader(query,mysqlparametersArray)
{
//declare command
//loop through mysqlparametersArray and add it to command Parameters Collection
//ExecuteReader
command.Parameters.Clear()
return reader
}
Now I am not getting that error.
Question: Is there any side-effect using .Clear() method above?
Note: Above is a sample pseudo code. I actually execute reader and create parameters collection in a separate method in DAL class which is used by others too. So I am not sure if making a check if parameters collection is empty or not before adding any parameters is a good way to go.
I have not ran into any side effects when I have used this method.
Aside from overhead or possibly breaking other code that is shared, there is no issue with clearing parameters.

Resources