Why can't typed optional arguments have a default of Null? - actionscript-3

In ActionScript 3, when you declare an optional argument by giving it a default value, the value null cannot be used on typed arguments.
function Action(Param:int=null){
// 1184: Incompatible default value of type Null where int is expected.
}
function Action(Param:int=0){
// No compiler errors
}
Any workarounds for this, or general purpose values that can apply to all data types?

You can change your int to Number and then can set it to NaN which is a special number that means 'not a number' and this can represent your null state for a Number.
To check if something is NaN, you must use the isNaN() function and not val == NaN, or you will not get what you expect.
function Action(param:Number = NaN) : void {
trace(param);
}
For all other objects, you can set them to null, but 'primitive' numbers are handled differently in Actionscript.

int variables cannot be null, that's why you get that error, only reference types like objects can be null
Instead you can use NaN as a special number instead of null. If you want to check if something is NaN you mus use the isNaN function.

you could also include a flag in the method signature to avoid having the parameter promoted from int to number:
function whatever(intProvided:Boolean = false, someInt:int = 0):void
{
if(intProvided)
doSomeStuff();
}

Related

Junit 5 - How to pass in multiple null values for #CsvSource?

I am modifying a test method from single parameter to multiple:
#ParameterizedTest
#NullSource
#ValueSource({"foo", "bar"..})
void shouldReturnFalse(String x) {
assertThat(someMethod(x)).isFalse();
}
#ParameterizedTest
#CsvSource({
"null, null",
"foo, bar"
})
void shouldReturnFalse(String x, String y) {
assertThat(someMethod(x, y)).isFalse();
}
null here is passed in as a String literal instead of a null literal. As a result, this test fails. This test previously works with single argument with #NullSource, but it gives following error when switched to multiple:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter...
I couldn't find a workaround for this and the solutions I saw were rather hacky and cumbersome. Is there a easier way for providing values with null?
#CsvSource has an attribute called nullValues.
See the documentation.
A list of strings that should be interpreted as null references.
#CsvSource(value= {"null, null",
"foo, bar"}
, nullValues={"null"})
The other option is to simply don't pass any value as stated in the previously linked documentation.
Please note that unquoted empty values will always be converted to null references regardless of the value of this nullValues attribute; whereas, a quoted empty string will be treated as an emptyValue().
#CsvSource({",",
"foo, bar"})
You can use nullValues as explained above by #Jan Schmitz, or you can just discard null values like this:
#CsvSource({
",",
"foo, bar"
})

Proper term for 'if (object)' as a non-null test?

In ActionScript 3, you can check if a value exists like this:
if (object) {
trace("This object is not null, undefined, or empty!")
}
I frequently use this as a shorthand for if (object != null)
Is there a proper term for evaluating objects for null in this fashion? I suppose it's a matter of the Boolean typecasting rules for the language but I'm not sure if there's a name for the resulting syntax.
If your object is always an actual object reference, e.g. a variable of any object type, then checking if (object) is a valid way to test for nulls. If it's a property of variant type, or a dynamic property that can potentially contain simple values (ints, strings etc) then the proper way to test for null will be explicit conversion, probably even with a strict type check if (object !== null).
Like most computer languages, Ecma-script supports Boolean data types;
values which can be set to true or false. In addition, everything in
JavaScript has an inherent Boolean value, generally known as either
truthy or falsy
list of falsy values (non truthy)
false
0 (zero)
"" (empty string)
null
undefined
NaN (a special Number value meaning Not-a-Number!)
regularly for checking if a variable is null
you may use : (a == null) this statement returns true if a is null, But also return true for all of the above list, because they'r all falsy values and (a == undefined) returns true, even a is not undefined but null or 0 or false.
so you should use Identity operator in this case. following evaluations just returns true when a is null
(typeof a === "null")
// or
(a === null)

golang return multiple values issue

I was wondering why this is valid go code:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
but this isn't
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
is there a way to avoid the temporary variables?
To elaborate on my comment, the Effective Go mentions that the multi-value assignment from accessing a map key is called the "comma ok" pattern.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false.
Playground demonstrating this
We can see that this differs from calling a regular function where the compiler would tell you that something is wrong:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
On the playground this will output
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
This gives us a hint that it may be something the compiler is doing. Searching the source code for "commaOk" gives us a few places to look, including types.unpack
At the time of writing this it this the method's godoc reads:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
The key bits of this being that this method appears to determine whether or not something is actually a "comma ok" case.
Digging into that method tells us that it will check to see if the mode of the operands is indexing a map or if the mode is set to commaok (where this is defined does give us many hints on when it's used, but searching the source for assignments to commaok we can see it's used when getting a value from a channel and type assertions). Remember the bolded bit for later!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk is a parameter to the function. Checking out where unpack is called in that file we can see that all callers pass false as an argument. Searching the rest of the repository leads us to assignments.go in the Checker.initVars() method.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Since it seems that we can only use the "comma ok" pattern to get two return values when doing a multi-value assignment this seems like the right place to look! In the above code the length of the left hand side is checked, and when unpack is called the allowCommaOk parameter is the result of l == 2 && !returnPos.IsValid(). The !returnPos.IsValid() is somewhat confusing here as that would mean that the position has no file or line information associated with it, but we'll just ignore that.
Further down in that method we've got:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
So what does all of this tell us?
Since the unpack method takes an allowCommaOk parameter that's hardcoded to false everywhere except in assignment.go's Checker.initVars() method, we can probably assume that you will only ever get two values when doing an assignment and have two variables on the left-hand side.
The unpack method will determine whether or not you actually do get an ok value in return by checking if you are indexing a slice, grabbing a value from a channel, or doing a type assertion
Since you can only get the ok value when doing an assignment it looks like in your specific case you will always need to use variables
You may save a couple of key strokes by using named returns:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
But apart from that, I don't think what you want is possible.
Simply put: the reason why your second example isn't valid Go code is because the language specification says so. ;)
Indexing a map only yields a secondary value in an assignment to two variables. Return statement is not an assignment.
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Furthermore, indexing a map is not a "single call to a multi-valued function", which is one of the three ways to return values from a function (the second one, the other two not being relevant here):
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
As for your actual question: the only way to avoid temporary variables would be using non-temporary variables, but usually that would be quite unwise - and probably not much of an optimization even when safe.
So, why doesn't the language specification allow this kind of special use of map indexing (or type assertion or channel receive, both of which can also utilize the "comma ok" idiom) in return statements? That's a good question. My guess: to keep the language specification simple.
I'm no Go expert but I believe you are getting compile time error when you are trying to return the array i.e. return all[id]. The reason could be because the functions return type is specially mentioned as (Info, bool) and when you are doing return all[id] it can't map the return type of all[id] to (Info, bool).
However the solution mentioned above, the variables being returned i and ok are the same that are mentioned in the return type of the function (i Info, ok bool) and hence the compiler knows what it's returning as opposed to just doing (i Info, ok bool).
By default, maps in golang return a single value when accessing a key
https://blog.golang.org/go-maps-in-action
Hence, return all[id] won't compile for a function that expects 2 return values.

if ( object != null ) instead of if ( object ) in AS3

Is there any reason to use if ( object != null ) in a conditional instead of the more concise if ( object ). I see the former more often, but it seems like the two are equivalent and the latter shorter.
different objects are treated differently. there are some values that can never be null and might erroneously trigger false when you don't want it to.
Booleans can never be null.
if a Boolean is defined but not given a value it is treated as false;
var bool:Boolean;
trace(bool); // false
bool = true;
trace(bool); // true
int can never be null as well.
if an int is defined but not given a value, it is treated as 0;
var i:int;
trace(i); // 0
trace(Boolean(i)); // false
i = -1;
trace(Boolean(i)); // true
i = 0;
trace(Boolean(i)); // false
i = 1;
trace(Boolean(i)); // true
Number act similar to int.
if a Number is defined but not given a value, it is treated as NaN
var num:Number;
trace(num); // NaN
trace(Boolean(num)); // false
num = -1.1;
trace(Boolean(num)); // true
num = 0;
trace(Boolean(num)); // false
num = 1.1;
trace(Boolean(num)); // true
Strings are the worst.
if a String is defined but not given a value, it is treated as null!
var str:String;
trace(str); // null
trace(Boolean(str)); // false
str = ""
trace(Boolean(str)); // false
str = "hello";
trace(Boolean(str)); // true
it is very rare in my code that i only do 'if (obj)' since most of the time there is something more specific that i truly care about.
The following code will have an object evaluate to false, even though the object is not null:
class SomeWrapper
{
var value: Object;
SomeWrapper(Object value)
{
this.value = value;
}
/// Overriden method from Object, see ActionScript 3 reference
function valueOf()
{
return value;
}
}
var myWrapper = new SomeWrapper(false);
if(myWrapper)
{
trace("myWrapper evaluates to true.");
}
else
{
trace("myWrapper evaluates to false.");
}
The else block will execute in the example above, because myWrapper evaluates to false (its valueOf method returns whatever value the wrapper contained, in this case false) even though myWrapper is not a null reference. The problem is that the above does not only test nullability of reference, it implicitly invokes valueOf method, courtesy of Flash Player virtual machine. This behavior of course may or may not be what you wanted - do you want to test whether myWrapper is a null value or whether it carries a null value? (or both perhaps).
Verbosity in this case is your friend, otherwise you gain code readability in return for potential runtime errors.
if (expression) tests the truthiness of expression by getting its boolean value. Since null and undefined are both falsy, if (object) "works" for making sure object isn't null.
Problem is, though, 0, false, and '' are also falsy. When you use if (object), the code you're trying to keep from running when it's null would also be ignored when object is zero, an empty string, or the actual boolean false. Often, that's not what you want.
If you can't guarantee that object is either null or a type other than string, number, or boolean (or their respective object types), then if (object != null) is less likely to mean something unintended.

how do I indicate an unset default parameter of type Number in Flex3?

for String and Object type, I can set the default parameter to null to indicate that it was not set by the caller. Is there a mechanism in flex3 to do the same for the Number type?
So for instance:
public function myMethod( stringVar:String=null, ObjectVar:Object=null, numberVar:Number )
{
...
}
I could do the following, but it just feels ugly
public function myMethod( numberVarObj:Object=null )
{
var numberVarSet:Boolean=true;
if( numberVarObj == null ) {
numberVarSet = false;
}
and then everywhere I want to use numberVar I can check for numberVarSet and cast as a Number.
I suppose you could always try:
var numberVar:* = null;
And then set it to a number when you want . . . It would be nice to have a solution that is strongly typed though.
Another option, as specified in Adobe's Docs (scroll down to default values), would be to treat the value NaN as null. However, if your data has ANY chance of containing a NaN value, this is a horrible idea.
I'd recommend the "ugly" solution you have, but if you really want another option you can use NaN and then use isNaN(num) to check the value.