From AS3 to C#, Part 15: Loops, Casts, and Operators

Datetime:2016-08-23 02:55:06          Topic: C#  ActionScript           Share

As withtypes and variables, there is a lot of subtlety in the differences between AS3 and C# when it comes to loops, casts, and operators. As core parts of the language, it’s important that we know all the little details of our most fundamental tools. Read on to learn what they have in common, what new operators C# offers, and what operators C# doesn’t have .

Let’s start with loops, which are largely the same in C# as they are in AS3. The standard three-part for loop is exactly the same:

// AS3
for (var i:int = 2; i < 4; ++i)
{
	// ... do something with i
}
// C#
for (int i = 2; i < 4; ++i)
{
	// ... do something with i
}

So is the while loop:

// AS3
var i:int = 2;
while (i < 4)
{
	// ... do something with i
	++i;
}
// C#
int i = 2;
while (i < 4)
{
	// ... do something with i
	++i;
}

So is do-while :

// AS3
var i:int = 2;
do
{
	// ... do something with i
	++i;
}
while (i < 4);
// C#
int i = 2;
do
{
	// ... do something with i
	++i;
}
while (i < 4);

AS3′s for-each loop is only slightly different between the two:

// AS3
for each (var val:int in someIntegers)
{
	// ... do something with val
}
// C#
foreach (int val in someIntegers)
{
	// ... do something with val
}

The for-each loop in AS3 can loop over any Array , Vector , Object , or Proxy that’s implemented the appropriate function. In C#, the foreach loop can loop over any array (e.g. int[] ) or class implementing the IEnumerable interface.

All of these loops in both languages support the break and continue statements. However, C# does not support breaking to a label like you can do in AS3:

var found:Boolean = false;
outerLoop: for (var row:int = 0; row < numRows; ++i)
{
	for (var col:int = 0; col < numCols; ++i)
	{
		if (table[row][col] == valToFind)
		{
			found = true;
			break outerLoop;
		}
	}
}

In C#, break can’t take a label to break to. You need to use goto to do that sort of thing. This leads us to the final kind of “loop” that is possible thanks to goto . Build your own loop!

int i = 0;
LoopStart:
	Debug.Log(i);
	++i;
	if (i < 3)
		goto LoopStart;
 
// output:
// 0
// 1
// 2

Of course you should normally use a normal for , while , do-while , or foreach loop, but goto gives you flexility for those very rare cases where none of them are ideal. More importantly, it restores your ability to break out of nested loops and can be a viable way to jump around functions, such as to consolidate error handling code.

Next we move on to casts. These too are similar to AS3, but with some minor differences. In AS3, you get a function-style cast:

var square:Square = Square(shape);

If the cast fails, a TypeError will be thrown. If you’d rather just get null instead of a thrown Error then you can use the other cast: as

var square:Square = shape as Square;

Instead of a function-style cast, C# moves the parentheses so that they surround the type you’re casting to rather than the object being casted:

Square square = (Square)shape;

This will throw an InvalidCastException if the cast fails. Like in AS3, there is an as keyword that returns null if the cast fails:

Square square = shape as Square;

Unlike AS3, some types in C# can’t be assigned null . This means that the cast can’t be used on basic types like int and float or any struct . It can, however, be used on any nullable type like int? .

Now for the many, many operators in AS3 and C3. Most of them are the same and don’t need any coverage here; you can probably guess what + does in both languages. There are some differences though. For example, there are two operators to shift the bits of an int or uint in AS3:

var signedShift:int = val >> 3;
var unsignedShift:int = val >>> 3;

The difference between the two is that the >>> operator does not preserve the sign value of the integer being shifted. In contrast, C# lacks the >>> operator completely. The same goes for the >>>= operator. Instead, you just use the >> operator on unsigned integers like uint and byte .

Similarly, AS3 has a “strict equality” operator: ===

var nullVal:* = null;
var undefinedVal:* = undefined;
var equal:int = nullVal == undefinedVal; // true
var strictlyEqual:int = nullVal === undefinedVal; // false

C# has no such operator. Instead, you can control type conversion via explicit and implicit conversion operators.

AS3 has two operators for logical comparisons with assignment that are also not present in C#:

myBool &&= otherBool;
myBool ||= otherBool;

Just like with += and + , you can write this without the &&= or ||= operators:

myBool = myBool && otherBool;
myBool = myBool || otherBool;

The in operator is also missing in C#. AS3 provides it so you can check if a value is a property of an object:

var hasProp:Boolean = "first_name" in myJSON;

The in operator only applies to anonymous classes in C#, which are usually rare. Regardless, you’ll have to try accessing the property and catch an exception if it doesn’t exist:

dynamic person = new [] { first_name = "Jackson" };
try
{
	bool hasProp = person.first_name;
}
catch (Exception ex)
{
	// property not found
}

Similarly, in AS3 you can index into any object with yet-another operator that isn’t in C#:

var prop:String = myJSON["first_name"];

Or for plain Object or untyped ( * ) variables, you can use the dot ( . ) operator like you would in C#:

var prop:String = myJSON.first_name;

In AS3, however, you won’t get an exception like you would in C#. You’ll just get undefined returned. This can be a bit misleading if the value of the property is actually undefined . For example:

var hasProp:Object = { first_name: undefined };
var noProp:Object = { };
var propHas:String = hasProp.first_name; // prop found, undefined
var propHasNot:String = noProp.first_name; // prop NOT found, undefined

This is part of why AS3 has the in operator. C# instead throws an exception when the property is not found and returns what it actually is—not undefined —if it isn’t.

Finally, two areas of AS3′s syntax simply don’t exist in C#. First are regular expressions like in AS3:

var regexp:RegExp = /[a-Z]*/;

This has been replaced with the Regex class, much like AS3′s RegExp class. Second is AS3′s inline support for XML:

var doc:XML = <class><students><student><first>Jackson</first><last>Dunstan</last></student></students></class>;

Along with the support for defining XML in code, C# lacks all the XML operators. This includes looping over XML elements, the descendant ( .. ) operator, and the attribute ( @ ) operator with its XML expression support. XML is, in short, not a first-class member of C#.

Before moving on to the few operators in C# that aren’t in AS3, there is one operator that is the similar in both languages but has a few differences. That is the “null coalescing” operator. Here it is in AS3:

name ||= "Unknown";

If name is anything that evaluates to false , it’ll get assigned "Unknown" . Otherwise, it doesn’t change. C# allows you to use this with or without assignment to the first operand like so:

name = name ?? "Unknown";
string otherName = name ?? "Unknown";

As for operators that C# has that AS3 does not, there are only a few. First, you can get the Type —like AS3′s Class —of an object using typeof :

Type type = typeof("Hello"); // System.String

You can also use it with generic type parameters:

T Add<T>(T a, T b)
{
	Type type = typeof(T);
	Debug.Log(type);
	return a + b;
}
 
Add(5u, 10u); // returns 15u, prints System.Uint32
Add(5f, 10f); // returns 15f, prints System.Single

The final operators for today are a pair of operators to control integer overflow. First, you can request a System.OverflowException to be thrown if any integer overflows using the checked keyword. There are two forms:

int twoBillion = 2000000000;
checked(twoBillion + twoBillion); // exception
 
checked
{
	int oneBillion = 1000000000;
	int result = oneBillion + oneBillion; // 2000000000
 
	int twoBillion = 2000000000;
	result = twoBillion + twoBillion; // exception
}

You can also suppress the exception and accept the overflowed value using the unchecked operator. It’s syntax is the same:

int twoBillion = 2000000000;
unchecked(twoBillion + twoBillion); // -294967296
 
unchecked
{
	int oneBillion = 1000000000;
	int result = oneBillion + oneBillion; // 2000000000
 
	int twoBillion = 2000000000;
	result = twoBillion + twoBillion; // -294967296
}

To sum up, the following side-by-side code shows the differences between the two languages’ loops, casts, and operators:

////////
// C# //
////////
 
// Loop over values
foreach (string name in names) {}
 
// Break out of nested loop
while (true)
	while (true)
		goto AfterLoop;
AfterLoop:
 
// Throw exception if cast fails
Square square = (Square)shape;
 
// Unsigned shift
// {unavailable in C#, use normal shift with unsigned int instead}
 
// Logical compare with assignment
// {unavailable in C#, use two operators instead}
 
 
// Check for dynamic property
// {unavailable in C#, get and check for exception instead}
 
// Get dynamic property
dynamicObject.someProperty;
 
 
// Define regular expression
// {unavailable in C#, use Regexp class instead}
 
// Define XML document
// {unavailable in C#, use XmlDocument class instead}
 
// Access XML document
// {unavailable in C#, use XmlDocument class' API instead}
 
 
 
// Get first non-null value
name = name ?? "Default";
 
// Get variable's type
Type t = typeof(someVar);
 
// Throw exception for integer overflow
checked(a + b);
checked { a + b; }
/////////
// AS3 //
/////////
 
// Loop over values
for each (var name:String in names) {}
 
// Break out of nested loop
OuterLoop: while (true)
	while (true)
		break AfterLoop;
 
 
// Throw exception if cast fails
var square:Square = Square(shape);
 
// Unsigned shift
result = val >>> 3;
 
// Logical compare with assignment
myBool &&= otherBool;
myBool ||= otherBool;
 
// Check for dynamic property
var hasFirstName:Boolean = "first_name" in myJSON;
 
// Get dynamic property
dynamicObject.someProperty;
dynamicObject["someProperty"];
 
// Define regular expression
var letters:RegExp = /[a-Z]+/;
 
// Define XML document
var page:XML = /<html><head></head><body><h1 id="title">My Page</h1></body></html>/;
 
// Access XML document
page.body.title.h1;
page.body.title.h1.@id;
// ... and others
 
// Get first non-null value
name||= "Default";
 
// Get variable's type
// {unavailable in AS3, use "prototype" or describeType() instead}
 
// Throw exception for integer overflow
// {unavailable in AS3}
//

Next week we’ll continue the series with even more of the kind of code you can put in your functions. Stay tuned!

Spot a bug? Have a question or suggestion? Post acomment !





About List