I decided to change things up and jump ship here at blogger. I'll leave the archives up for as long as they let me, but I've already imported all the old posts into the new blog at:
http://rezoant.wordpress.com/.
Tuesday, March 24, 2009
Sunday, March 22, 2009
Loops and bugkilling
I investigated some ideas for less common loop types from the Wikipedia article on control flow, and decided to integrate some into the design of Fera.
The first is the concept of a loop with a condition somewhere in the middle of it's body. This can already be done in C# (and indeed any language with a while loop) with:
In Fera, you can do the same thing with a little less typing and a bit more style:
This also allows for the programmer to perform infinite loops, though the compiler will emit a warning, letting you know that you've forgot to put in some kind of condition for your loop. You can also use the 'when' construct with 'next' and 'continue' where ever they can be used. The compiler simply reverses the construct, so 'next when (x);' turns into 'if (x) next;'.
Originally I went with 'break if (x);'. Some languages allow if() tails on any instruction, but they are usually not whitespace-agnostic. I looked at this case to decide against it:
Forgetting semicolons happens all the time, and this error wouldn't even be acknowledged by the compiler, making this bug very hard to find. Adding the 'when' keyword avoids this ambiguity, and fits in nicely with the do{} loop syntax. I'll be further investigating whether it's a good idea to allow this for all instructions (or most anyway).
There are some specific error conditions for the infinite 'do' loop; for one, the construct:
causes a compile-time error, not because we disfavor pure infinite loops, but rather because it looks retarded. Also, only certain instructions are allowed to be put as the action of an infinite do loop. Curly brace groups, standalone expressions which have known/unknown side effects, conditionals, or loops are allowed. So this construct 'do echo "annoying!";' is thankfully not allowed.
If you want a pure infinite loop, just use 'loop;'. This will always emit a warning, telling you it should never be used in production code (unless you explicitly ignore it, or elevate the warning to be treated like an error).
Another type of loop (which is not implemented yet by my compiler) is do/exits.
This is syntactically very different from similar constructs in other languages, as it reuses the switch() syntax and logic and tosses it in with the do loop. The result is a pretty unobscured syntax that is easy to remember once you've learned the nuances of both.
Using 'break' in this loop will cause the exits to be evaluated, before control returns outside the loop. Using 'next' will also cause the exits to be evaluated, except that a lack of any exits will result in a new loop iteration. Within the 'exits' block, the 'continue' and 'break' work exactly like they do in switch/branch.
Owing to the fact that we use 'next' for loops and 'continue' for switches, you can use 'next' within an exit block to have the loop return to iteration. This is a unique property among the loop types that Fera offers, something which must be done with if() in C#.
Naturally the test casing marathon continues. Currently there are a total of 90 tests within the test suite, and 71 of them pass. 10 are expected fails, and the other 9 are regressions. I tested many of the earliest work on this project by hand, so now that I've added testcases for them, I discovered many bugs in the Fera grammar and of course the compiler itself.
One of the most perplexing problems was something I thought was happening in the compiler. The problem was happening in the do/while testcases which used a compound condition like so:
This particular formulation ensures that the compiler isn't creating the FWhileLoop instruction which represents the loop with PostCondition = false. Doing so would result in the loop behaving like a while() loop, in which case it would never do the loop action.
The problem was that it was running infinitely, and there is a Console.Write(x) within it, which resulted in an infinite sea of digits across the console window.
I quickly figured out it was the compound nature of the condition, so I turned my attention to test 'if3', which tested the if() statement with a similar condition. It happened to be 'x == 3 && y == 4'. The testcase failed because the action of the if() never runs though it should.
Inspecting the CIL showed the comparison code to be something like this:
Naturally, there should be a ceq inserted at #2. The way it is now, the first condition would always end up being true. It looked like the FComparison expression operand was not outputting 'ceq'. However upon inspecting that code it was fine and I was able to verify that it in fact was running the branch that emitted the instruction.
Only after much head scratching did I realize that the 'ceq' was there, but was far later in the body then it should be. At a hunch I checked the token listing for the file being compiled and sure enough, it was treating the expression like this:
Which would cause a more complete compiler to yelp but not here. So the tree of expression operands looked like:
I had to add a new level in the expression grammar called 'CValue' which is comprised of a 'Value' term and an optional set of ComparisonTails. Binary logic operations are handled in the level above it, causing comparisons to be treated as children of the binary logic operators. The tree thus became:
Pretty.
The first is the concept of a loop with a condition somewhere in the middle of it's body. This can already be done in C# (and indeed any language with a while loop) with:
while (true) {
// x x x
if (condition) break;
// x x x
}
In Fera, you can do the same thing with a little less typing and a bit more style:
do {
// x x x
break when (condition);
// x x x
}
This also allows for the programmer to perform infinite loops, though the compiler will emit a warning, letting you know that you've forgot to put in some kind of condition for your loop. You can also use the 'when' construct with 'next' and 'continue' where ever they can be used. The compiler simply reverses the construct, so 'next when (x);' turns into 'if (x) next;'.
Originally I went with 'break if (x);'. Some languages allow if() tails on any instruction, but they are usually not whitespace-agnostic. I looked at this case to decide against it:
if (x)
doSomething ();
else
doSomethingElse () // OOPS! forgot my semicolon!
if (x)
doSomethingTotallyDifferent ();
Forgetting semicolons happens all the time, and this error wouldn't even be acknowledged by the compiler, making this bug very hard to find. Adding the 'when' keyword avoids this ambiguity, and fits in nicely with the do{} loop syntax. I'll be further investigating whether it's a good idea to allow this for all instructions (or most anyway).
There are some specific error conditions for the infinite 'do' loop; for one, the construct:
do;
causes a compile-time error, not because we disfavor pure infinite loops, but rather because it looks retarded. Also, only certain instructions are allowed to be put as the action of an infinite do loop. Curly brace groups, standalone expressions which have known/unknown side effects, conditionals, or loops are allowed. So this construct 'do echo "annoying!";' is thankfully not allowed.
If you want a pure infinite loop, just use 'loop;'. This will always emit a warning, telling you it should never be used in production code (unless you explicitly ignore it, or elevate the warning to be treated like an error).
Another type of loop (which is not implemented yet by my compiler) is do/exits.
var int x = 0;
var int y = 3;
do {
// x x x
} exits {
case x > 10:
// x x x
case y < 0:
// x x x
}
This is syntactically very different from similar constructs in other languages, as it reuses the switch() syntax and logic and tosses it in with the do loop. The result is a pretty unobscured syntax that is easy to remember once you've learned the nuances of both.
Using 'break' in this loop will cause the exits to be evaluated, before control returns outside the loop. Using 'next' will also cause the exits to be evaluated, except that a lack of any exits will result in a new loop iteration. Within the 'exits' block, the 'continue' and 'break' work exactly like they do in switch/branch.
Owing to the fact that we use 'next' for loops and 'continue' for switches, you can use 'next' within an exit block to have the loop return to iteration. This is a unique property among the loop types that Fera offers, something which must be done with if() in C#.
Naturally the test casing marathon continues. Currently there are a total of 90 tests within the test suite, and 71 of them pass. 10 are expected fails, and the other 9 are regressions. I tested many of the earliest work on this project by hand, so now that I've added testcases for them, I discovered many bugs in the Fera grammar and of course the compiler itself.
One of the most perplexing problems was something I thought was happening in the compiler. The problem was happening in the do/while testcases which used a compound condition like so:
var int x = 0;
do {
// x x x
++x;
} while (x > 0 && x < 5);
This particular formulation ensures that the compiler isn't creating the FWhileLoop instruction which represents the loop with PostCondition = false. Doing so would result in the loop behaving like a while() loop, in which case it would never do the loop action.
The problem was that it was running infinitely, and there is a Console.Write(x) within it, which resulted in an infinite sea of digits across the console window.
I quickly figured out it was the compound nature of the condition, so I turned my attention to test 'if3', which tested the if() statement with a similar condition. It happened to be 'x == 3 && y == 4'. The testcase failed because the action of the if() never runs though it should.
Inspecting the CIL showed the comparison code to be something like this:
0 ldloc.0 ; load x to the stack
1 ldc.i4.3 ; load constant zero to the stack
2 dup ; save the top value
3 brfalse 8 ; skip the second condition if false
4 pop ; pop the unused save value
5 ldloc.1 ; load y
6 ldc.i4.4 ; load 4
7 ceq ; compare equality
8 nop ; label
Naturally, there should be a ceq inserted at #2. The way it is now, the first condition would always end up being true. It looked like the FComparison expression operand was not outputting 'ceq'. However upon inspecting that code it was fine and I was able to verify that it in fact was running the branch that emitted the instruction.
Only after much head scratching did I realize that the 'ceq' was there, but was far later in the body then it should be. At a hunch I checked the token listing for the file being compiled and sure enough, it was treating the expression like this:
x == (3 && y == 4)
Which would cause a more complete compiler to yelp but not here. So the tree of expression operands looked like:
FComparison
| FVariableAccess
| FBinaryBoolean
| | FConstant
| | FComparison
| | | FVariableAccess
| | | FConstant
I had to add a new level in the expression grammar called 'CValue' which is comprised of a 'Value' term and an optional set of ComparisonTails. Binary logic operations are handled in the level above it, causing comparisons to be treated as children of the binary logic operators. The tree thus became:
FBinaryBoolean
| FComparison
| | FVariableAccess
| | FConstant
| FComparison
| | FVariableAccess
| | FConstant
Pretty.
Friday, March 20, 2009
My adventure with Unicode identifiers in Grammatica
For people who don't care about multilingual support in their grammars, a token type like this might be sufficient:
I wanted to expand this to support more than just the basic latin alphabet, hoping it would be as easy as reformulating this expression into character classes, now that Grammatica 1.5 apparently supports unicode regular expressions. First I tried something like:
However it appears that Grammatica entirely ignores this type of structure, instead treating it like a character set composed of :s and the letters a, l, p, h, a, etc. So I found out about the \p{Class} formulation for property classes...
The \p formulations like \p{L&} for these weren't working until I consulted Java's own set of property classes, which list Alpha and Alnum, so it turned into:
This made it past the grammar build, targetting .NET for the tokenizer code. But when the compiler runs, from all appearances I gather that it is using .NET's regular expression library, which does not accept {Alpha} and {Alnum} but prefers the Unicode block names instead like {L&}.
At a prime moment of head scratching I came up with a solution (though it's not as pretty as the formulations above:
This makes it through grammar compilation and parsing, matching the correct input. It matches any alphabetic letter (upper, lower, title case) as the first character, and any alphanumeric character for the rest.
The inability to use the Java style classes looks like a bug/oversight in the C# port of Grammatica, unless I miss a more elegant way to pull this off?
In any case it works, so that's what I'm using. Grammatica has a very long release cycle and they *just* released version 1.5. It's unlikely there will be a new version for quite awhile. So for anyone who needs Unicode-level identifier tokens, your welcome!
IDENTIFIER = <<[A-Za-z][A-Za-z0-9_]*>>
I wanted to expand this to support more than just the basic latin alphabet, hoping it would be as easy as reformulating this expression into character classes, now that Grammatica 1.5 apparently supports unicode regular expressions. First I tried something like:
IDENTIFIER = <<[[:alpha:]][[:alnum:]]*>>
However it appears that Grammatica entirely ignores this type of structure, instead treating it like a character set composed of :s and the letters a, l, p, h, a, etc. So I found out about the \p{Class} formulation for property classes...
IDENTIFIER = <<[\p{L&}][\p{L&}]*>>
The \p formulations like \p{L&} for these weren't working until I consulted Java's own set of property classes, which list Alpha and Alnum, so it turned into:
IDENTIFIER = <<[\p{Alpha}][\p{Alnum}]*>>
This made it past the grammar build, targetting .NET for the tokenizer code. But when the compiler runs, from all appearances I gather that it is using .NET's regular expression library, which does not accept {Alpha} and {Alnum} but prefers the Unicode block names instead like {L&}.
At a prime moment of head scratching I came up with a solution (though it's not as pretty as the formulations above:
IDENTIFIER = <<[\p{Ll}\p{Lu}\p{Lt}][\p{Ll}\p{Lu}\p{Lt}\p{Nd}]*>>
This makes it through grammar compilation and parsing, matching the correct input. It matches any alphabetic letter (upper, lower, title case) as the first character, and any alphanumeric character for the rest.
The inability to use the Java style classes looks like a bug/oversight in the C# port of Grammatica, unless I miss a more elegant way to pull this off?
In any case it works, so that's what I'm using. Grammatica has a very long release cycle and they *just* released version 1.5. It's unlikely there will be a new version for quite awhile. So for anyone who needs Unicode-level identifier tokens, your welcome!
Wednesday, March 18, 2009
More testcases! .... & translations
I revamped Fera's testcase system to differentiate between expected failures/passing. The way it's set up, it treats failed tests which were expected to pass as "regress", and the opposite is marked as "fixed". Example:
I also implemented translation support for all errors and messages in the Fera compiler (Fc). Here's a sample run of a testcase in my (probably incorrect) Google Translate-based Spanish translation:
Mmm fun. Of course I also implemented a pseudo translation which makes Fera's messages super brief and concise, useful for people who know what they're doing and want the compiler to yap as little as possible.
(pass) decl-field1 (Declarations: Field (test 1))
(pass) decl-field2 (Declarations: Field (test 2, verified result))
(regress) decl-property1 (Declarations: Property (test 1))
Caught exception 'Object reference not set to an instance of an object.'
(regress) decl-property2 (Declarations: Property (test 2, verified result))
Caught exception 'Object reference not set to an instance of an object.'
(pass) helloworld (Hello, world!)
(pass) echo1 (Echo (test 1))
(regress) echo2 (Echo (test 2: conversion to string))
Unexpected program console output (padded to align to [U]nexp...):
{no output}
(pass) partial-types1 (Partial types)
(pass) variables1 (Variable support (simple definition))
(pass) variables2 (Variable support (initialization))
(pass) variables3 (Variable support (assignment))
(pass) variables4 (Variable support (variable as instance))
(fail) field-get1 (Field access (test 1))
Caught exception 'OpCode ldsfld have null operand'
(fail) field-set1 (Field assignment (test 1))
Compile was not successful (1 errors)
(fail) field-set2 (Field assignment (test 2, verified result))
Compile was not successful (1 errors)
(fail) property-get1 (Property access (test 1))
Compile was not successful (2 errors)
(fail) property-set1 (Property assignment (test 1))
Compile was not successful (1 errors)
(regress) mutate1 (Mutation (++x))
Caught exception 'Operation is not valid due to the current state of the object.'
(pass) methodcall1 (Method call (no parameters, void return))
(pass) methodcall2 (Method call (1 parameter, void return))
(pass) methodcall3 (Method call (1 parameter, throw-away return))
(pass) methodcall4 (Method call (1 parameter, used return))
(pass) methodcall5 (Method call (incorrect parameters, missing 1))
(pass) methodcall6 (Method call (incorrect parameters, 1 extra))
(pass) bool-constants1 (Boolean constants (true))
(pass) bool-constants2 (Boolean constants (check))
(pass) bool-not (Boolean unary operator (!))
(pass) bool-and (Boolean binary operator (&&))
(pass) bool-or (Boolean binary operator (||, test 1))
(pass) bool-or2 (Boolean binary operator (||, test 2))
(pass) bool-or3 (Boolean binary operator (||, test 3))
(pass) invalid-standalone-expr1 (Invalid standalone expressions (x + 3))
(regress) invalid-standalone-expr2 (Invalid standalone expressions (MethodWithoutSideEffects()))
Unexpected program console output (padded to align to [U]nexp...):
success
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-imperative1 (Imported Namespaces (unqualified type for variable definition))
(pass) switch1 (Switch test 1 (case variable scope))
(pass) switch2 (Switch test 2 (dynamic cases))
(pass) invalid-type-variable (Unknown type (variable))
(pass) missing-variable-initializer (Missing variable initializer (var x;))
(pass) valuetype-instance1 (Passing by-value types as instance parameter (int x; x.ToString ()))
(pass) valuetype-instance2 (Passing by-value types as instance parameter (addressof parameter))
(pass) valuetype-constant-instance1 (Passing by-value constants as instance parameter (38.ToString ()))
(pass) arrays1 (Arrays (array def/construction))
(pass) arrays2 (Arrays (element assignment))
(pass) arrays3 (Arrays (element access))
(pass) arrays4 (Arrays (use of Length))
(fail) variable-params1 (Variable parameters (basic test 1))
Compile was not successful (1 errors)
(fail) generics1 (Generics (test 1))
Compile was not successful (1 errors)
I also implemented translation support for all errors and messages in the Fera compiler (Fc). Here's a sample run of a testcase in my (probably incorrect) Google Translate-based Spanish translation:
C:\fera>fc invalid-standalone-expr2.f /lang:es
invalid-standalone-expr2.f(13,4): Advertencia: 'FeraLanguageTest.Program.MethodWithoutSideEffects' El método no tiene efectos secundarios y devuelve un valor. Este uso del método e
s, probablemente, no.
Compilación éxito (invalid-standalone-expr2.exe): 1 advertencias
Mmm fun. Of course I also implemented a pseudo translation which makes Fera's messages super brief and concise, useful for people who know what they're doing and want the compiler to yap as little as possible.
Tuesday, March 17, 2009
Optimizations & Testcases
I got a little ahead of myself when I decided to start implementing optimizations in Fera... it has code flow graph generation now but it given my lack of access to some of the more efficient algorithms for doing anything beyond that, it makes more sense to get all the language features done and in place (and testcased).
So I did some of that the last couple of days, fixing a critical scoping bug for resolving imported types on declaration entries and implementing arrays (which went so smoothly that I had to pat myself on the back with this blog entry).
I also implemented inspection of method side effects, culminating in this warning which appears whenever you use a side-effect-free method as a standalone expression:
invalid-standalone-expr2.f(13,4): Warning: The method 'FeraLanguageTest.Program.MethodWithoutSideEffects' does not have side effects and returns a value. This usage of the method is probably not intended.
I'm developing the code in a very agile/test-driven way. Here is the Fera testcase suite results for today:
(pass) helloworld (Hello, world!)
(pass) echo1 (Echo (test 1))
(pass) partial-types1 (Partial types)
(pass) variables1 (Variable support (simple definition))
(pass) variables2 (Variable support (initialization))
(pass) variables3 (Variable support (assignment))
(pass) variables4 (Variable support (variable as instance))
(fail) mutate1 (Mutation (++x))
Caught exception 'Operation is not valid due to the current state of the object.'
(pass) bool-constants1 (Boolean constants (true))
(pass) bool-constants2 (Boolean constants (check))
(pass) bool-not (Boolean unary operator (!))
(pass) bool-and (Boolean binary operator (&&))
(pass) bool-or (Boolean binary operator (||, test 1))
(pass) bool-or2 (Boolean binary operator (||, test 2))
(pass) bool-or3 (Boolean binary operator (||, test 3))
(pass) methodcall1 (Method call (no parameters, void return))
(pass) methodcall2 (Method call (1 parameter, void return))
(pass) methodcall3 (Method call (1 parameter, throw-away return))
(pass) methodcall4 (Method call (1 parameter, used return))
(pass) methodcall5 (Method call (incorrect parameters, missing 1))
(pass) methodcall6 (Method call (incorrect parameters, 1 extra))
(pass) invalid-standalone-expr1 (Invalid standalone expressions (x + 3))
(pass) invalid-standalone-expr2 (Invalid standalone expressions (MethodWithoutSideEffects()))
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-imperative1 (Imported Namespaces (unqualified type for variable definition))
(pass) switch1 (Switch test 1 (case variable scope))
(pass) switch2 (Switch test 2 (dynamic cases))
(pass) invalid-type-variable (Unknown type (variable))
(pass) missing-variable-initializer (Missing variable initializer (var x;))
(pass) valuetype-instance1 (Passing by-value types as instance parameter (int x; x.ToString ()))
(pass) valuetype-instance2 (Passing by-value types as instance parameter (addressof parameter))
(pass) valuetype-constant-instance1 (Passing by-value constants as instance parameter (38.ToString ()))
(pass) arrays1 (Arrays (array def/construction))
(pass) arrays2 (Arrays (element assignment))
(pass) arrays3 (Arrays (element access))
(fail) arrays4 (Arrays (use of Length))
Caught exception 'Unknown error'
(fail) variable-params1 (Variable parameters (basic test 1))
Compile was not successful (1 errors)
(fail) generics1 (Generics (test 1))
Compile was not successful (1 errors)
Press any key to continue . . .
As you see, there's still some bugs in arrays and variable parameters / generics are totally broken. As a nod to test driven development: the mutate testcase fails because of the changes to the Assignable expression model, I wouldn't have known without this great unit test framework!
So I did some of that the last couple of days, fixing a critical scoping bug for resolving imported types on declaration entries and implementing arrays (which went so smoothly that I had to pat myself on the back with this blog entry).
I also implemented inspection of method side effects, culminating in this warning which appears whenever you use a side-effect-free method as a standalone expression:
invalid-standalone-expr2.f(13,4): Warning: The method 'FeraLanguageTest.Program.MethodWithoutSideEffects' does not have side effects and returns a value. This usage of the method is probably not intended.
I'm developing the code in a very agile/test-driven way. Here is the Fera testcase suite results for today:
(pass) helloworld (Hello, world!)
(pass) echo1 (Echo (test 1))
(pass) partial-types1 (Partial types)
(pass) variables1 (Variable support (simple definition))
(pass) variables2 (Variable support (initialization))
(pass) variables3 (Variable support (assignment))
(pass) variables4 (Variable support (variable as instance))
(fail) mutate1 (Mutation (++x))
Caught exception 'Operation is not valid due to the current state of the object.'
(pass) bool-constants1 (Boolean constants (true))
(pass) bool-constants2 (Boolean constants (check))
(pass) bool-not (Boolean unary operator (!))
(pass) bool-and (Boolean binary operator (&&))
(pass) bool-or (Boolean binary operator (||, test 1))
(pass) bool-or2 (Boolean binary operator (||, test 2))
(pass) bool-or3 (Boolean binary operator (||, test 3))
(pass) methodcall1 (Method call (no parameters, void return))
(pass) methodcall2 (Method call (1 parameter, void return))
(pass) methodcall3 (Method call (1 parameter, throw-away return))
(pass) methodcall4 (Method call (1 parameter, used return))
(pass) methodcall5 (Method call (incorrect parameters, missing 1))
(pass) methodcall6 (Method call (incorrect parameters, 1 extra))
(pass) invalid-standalone-expr1 (Invalid standalone expressions (x + 3))
(pass) invalid-standalone-expr2 (Invalid standalone expressions (MethodWithoutSideEffects()))
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-structure1 (Imported Namespaces (unqualified type for method return))
(pass) imports-imperative1 (Imported Namespaces (unqualified type for variable definition))
(pass) switch1 (Switch test 1 (case variable scope))
(pass) switch2 (Switch test 2 (dynamic cases))
(pass) invalid-type-variable (Unknown type (variable))
(pass) missing-variable-initializer (Missing variable initializer (var x;))
(pass) valuetype-instance1 (Passing by-value types as instance parameter (int x; x.ToString ()))
(pass) valuetype-instance2 (Passing by-value types as instance parameter (addressof parameter))
(pass) valuetype-constant-instance1 (Passing by-value constants as instance parameter (38.ToString ()))
(pass) arrays1 (Arrays (array def/construction))
(pass) arrays2 (Arrays (element assignment))
(pass) arrays3 (Arrays (element access))
(fail) arrays4 (Arrays (use of Length))
Caught exception 'Unknown error'
(fail) variable-params1 (Variable parameters (basic test 1))
Compile was not successful (1 errors)
(fail) generics1 (Generics (test 1))
Compile was not successful (1 errors)
Press any key to continue . . .
As you see, there's still some bugs in arrays and variable parameters / generics are totally broken. As a nod to test driven development: the mutate testcase fails because of the changes to the Assignable expression model, I wouldn't have known without this great unit test framework!
Monday, March 9, 2009
Fera: a new .NET language
So over spring break I worked tirelessly, even through my severe rhinovirus infection at the end on a compiler for a new programming language that I'm developing which I call Fera.
I'm doing it purely for educational purposes right now, but if it turns out good maybe I'll release it. It's very similar to C#, but it just outright drops most of the historical baggage that it brought along from C.
The best example of this is the 'switch' construct in the language, which is something that pisses me off about C#. In C# switch statements you are required to place a 'break' instruction at the end of each case, with the exception of cases with no instructions, which fallthrough into the next case.
Example:
Yes, even that last break has to be there, supposedly to make sure a developer never adds a case without adding the 'break' between the old last case and the new case. If you think about the logic of that it's pretty retarded, and really is only there to make it look like Microsoft has improved it. As you see with the multiple definitions of 'y', the whole inside of a switch statement is within the scope it is placed in, meaning in order to define similarly-named variables within multiple case statements, you must place {}s around the cases like so:
And boy, doesn't that look retarded. All the current IDEs get confused too when you do this, changing the indent on lots of stuff while you hammer out the curly braces.
So with that said, here's Fera's interpretation of the switch statement.
As you see, each case statement is given it's own variable scope, and a break at the end of each case is implicit. To fallthrough to the next statement, you use the 'continue' construct like so:
The 'break' construct works like it does in C# and other languages, using it causes the instruction pointer to exit the whole switch statement, allowing the next instruction to execute.
Another interesting thing about Fera's switch statement is that it's totally dynamic. The compiler is (well, isn't yet but will be) capable of determining the static nature of the case statements for a given switch statement, so using static cases will allow the compiler to turn it into a constant time branch (CTB). But if it can't do that it will just compile it as a simple cascading set of if/else branches.
Naturally there are times when you want to ensure that the compiler can use static analysis to improve compilation of your switch. For this purpose, Fera provides the 'branch' construct:
This doesn't guarantee that the construct will compile to a constant time branch any more than C#'s does, but at least it gives the compiler a chance while making sure the programmer doesn't get any fancy ideas and use dynamic expressions for it's cases.
So there's tons more stuff I'm working to implement, but this is a particularly interesting bit which is already mostly implemented. I think I'll post a few more blogs with info about some of the other features, like contract-based design, aspect-oriented programming, advanced language-level features and more.
I'm doing it purely for educational purposes right now, but if it turns out good maybe I'll release it. It's very similar to C#, but it just outright drops most of the historical baggage that it brought along from C.
The best example of this is the 'switch' construct in the language, which is something that pisses me off about C#. In C# switch statements you are required to place a 'break' instruction at the end of each case, with the exception of cases with no instructions, which fallthrough into the next case.
Example:
switch (x) {
case 0:
case 1:
int y = 4;
Console.WriteLine ("x is either 0 or 1");
break; // this MUST be here
case 2:
int y = 6; // compile-time error, 'y' already exists in the current scope
Console.WriteLine ("x is 2");
break; // this TOO must be here
}
Yes, even that last break has to be there, supposedly to make sure a developer never adds a case without adding the 'break' between the old last case and the new case. If you think about the logic of that it's pretty retarded, and really is only there to make it look like Microsoft has improved it. As you see with the multiple definitions of 'y', the whole inside of a switch statement is within the scope it is placed in, meaning in order to define similarly-named variables within multiple case statements, you must place {}s around the cases like so:
switch (x) {
case 0:
case 1: {
int y = 4;
Console.WriteLine ("x is either 0 or 1");
break; // this MUST be here
} case 2: {
int y = 6; // compile-time error, 'y' already exists in the current scope
Console.WriteLine ("x is 2");
break; // this TOO must be here
}
}
And boy, doesn't that look retarded. All the current IDEs get confused too when you do this, changing the indent on lots of stuff while you hammer out the curly braces.
So with that said, here's Fera's interpretation of the switch statement.
switch (x) {
case 0:
case 1:
int y = 4;
Console.WriteLine ("x is either 0 or 1");
case 2:
int y = 6;
Console.WriteLine ("x is 2");
}
As you see, each case statement is given it's own variable scope, and a break at the end of each case is implicit. To fallthrough to the next statement, you use the 'continue' construct like so:
switch (x) {
case 0:
case 1:
int y = 4;
Console.WriteLine ("x is either 0 or 1");
continue;
case 2:
int y = 6;
Console.WriteLine ("x is 0, 1, or 2");
}
The 'break' construct works like it does in C# and other languages, using it causes the instruction pointer to exit the whole switch statement, allowing the next instruction to execute.
Another interesting thing about Fera's switch statement is that it's totally dynamic. The compiler is (well, isn't yet but will be) capable of determining the static nature of the case statements for a given switch statement, so using static cases will allow the compiler to turn it into a constant time branch (CTB). But if it can't do that it will just compile it as a simple cascading set of if/else branches.
int x = 3;
int y = 2;
switch (x) {
case y + 1:
case y + 2:
int y = 4;
Console.WriteLine ("x is 1 or 2 more than y");
case 2:
Console.WriteLine ("x is 2");
break; // this TOO must be here
}
Naturally there are times when you want to ensure that the compiler can use static analysis to improve compilation of your switch. For this purpose, Fera provides the 'branch' construct:
branch (x) {
case 0:
case 1:
Console.WriteLine ("x is either 0 or 1");
case y+1: // this causes a compile-time error
Console.WriteLine ("x is 1 more than y");
}
This doesn't guarantee that the construct will compile to a constant time branch any more than C#'s does, but at least it gives the compiler a chance while making sure the programmer doesn't get any fancy ideas and use dynamic expressions for it's cases.
So there's tons more stuff I'm working to implement, but this is a particularly interesting bit which is already mostly implemented. I think I'll post a few more blogs with info about some of the other features, like contract-based design, aspect-oriented programming, advanced language-level features and more.
I've got a crazy little theory of my own
So the crazies are at it again, but I can't say I didn't expect it.
http://www.newsweek.com/id/169192?digg=1
But I have a crazy theory of my own. What is Obama isn't the Antichrist-- what if the battle WAS the election, and Jesus Christ has already won. Yes that's right, what if Obama was the resurrection of your lord? Is it so hard to believe because he's black? Do you think that God sees the white man as his son when he made black first? Africa is the cradle of human life.
So, assuming Obama is actually Christ, how do we define the armies? Perhaps the Republicans are the armies of the "Antichrist", being the intention of ill will toward the world. After eight years of degrading human rights and terrorizing the world under the guise of it's protection, I think it fits. Maybe the end of your world of suffering is already coming to pass. Maybe Obama will go on to unite us all in preparation for this next thousand years of peace and prosperity.
I'm not religious, but that's a good thing. I'm not clouded by idealogy, only principles. And tell me that hoarding our prosperity in the US is RIGHT and I'll show you a greedy son of a bitch. People in hundreds of countries starve to death everyday, their children die from easily curable diseases, and the best the conservative Christian group will do is send a dollar a day to them.
Jesus had a saying for this: "Give a man a fish and he'll eat for a day, teach a man to fish and he'll eat for a lifetime". Sending money isn't the solution. We have to honestly and seriously help our neighbors as we would like to be helped if it were us in that situation.
http://www.newsweek.com/id/169192?digg=1
But I have a crazy theory of my own. What is Obama isn't the Antichrist-- what if the battle WAS the election, and Jesus Christ has already won. Yes that's right, what if Obama was the resurrection of your lord? Is it so hard to believe because he's black? Do you think that God sees the white man as his son when he made black first? Africa is the cradle of human life.
So, assuming Obama is actually Christ, how do we define the armies? Perhaps the Republicans are the armies of the "Antichrist", being the intention of ill will toward the world. After eight years of degrading human rights and terrorizing the world under the guise of it's protection, I think it fits. Maybe the end of your world of suffering is already coming to pass. Maybe Obama will go on to unite us all in preparation for this next thousand years of peace and prosperity.
I'm not religious, but that's a good thing. I'm not clouded by idealogy, only principles. And tell me that hoarding our prosperity in the US is RIGHT and I'll show you a greedy son of a bitch. People in hundreds of countries starve to death everyday, their children die from easily curable diseases, and the best the conservative Christian group will do is send a dollar a day to them.
Jesus had a saying for this: "Give a man a fish and he'll eat for a day, teach a man to fish and he'll eat for a lifetime". Sending money isn't the solution. We have to honestly and seriously help our neighbors as we would like to be helped if it were us in that situation.
Saturday, February 7, 2009
A name found for my hate of pop music
OK so this has been going on for a long time but Slashdot today posted an article on it. It's called auto-correlation, and it allows singers to have perfect pitch and sing perfectly in tune. But the interesting part of the article is that apparently the inventor never intended for singers to start removing the natural transitions between notes, which is REALLY what pisses me off. But they did, evidently they thought they were cool sounding like robots, and then it kind of just stuck as a requirement for shitty singers in the industry. But I'm happy I suppose because without that lack of note transitions, I might not be able to tell who can't sing worth their million dollar paycheck.
Boycott any music that uses auto-tune/auto-correlation: support people who PUT EFFORT into sounding good, and take pride in the understanding of music theory.
Tuesday, January 20, 2009
BSG returns in full force
Complete with violently unexpected twists and mind-binding conundrums, the new season of Battlestar Galactica is off to an impressive start. The new episode, Sometimes a Great Notion continues where the show left off during the writer's strike last year. Warning, this article contains spoilers, so head on over to Hulu and watch it.
The strangest part of the new episode is the evidence that Starbuck has visited earth before and died there. Kara first finds her own ship's emergency transponder, then a piece of scrap metal carrying her ship's wing designation, culminating in her discovery of the flight module, containing one stinky decomposing Kara, complete with dog tags and her ring.
The strangest part of the new episode is the evidence that Starbuck has visited earth before and died there. Kara first finds her own ship's emergency transponder, then a piece of scrap metal carrying her ship's wing designation, culminating in her discovery of the flight module, containing one stinky decomposing Kara, complete with dog tags and her ring.
Now there's only so many possible resolutions for such a contradiction, and most can be grouped into one of the following explanations:
1. Time travel
2. Cloning
3. Starbuck is a Cylon
4. Starbuck is not human or Cylon
I'll be impressed if the real answer is not among these (knowing BSG, it likely isn't). But if it is, my money's on number 2. We know she's prophesized as the angel of death, something she is quick to bring up while freaking out but there has already been at least one explanation for why such a prophesy was foretold.
And keeping faithful to BSG's completely unexpected and totally jarring gunplay, Dee kills herself after a seemingly joyous date with her ex-husband. From a literary perspective this is golden: the viewer is put into a very positive mindset, observing the rekindling of their once troubled love (further amplified by the contrast to the new discovery of a charred and desolate Earth). Lee and Dee (whoa, a rhyme) part ways and Dee heads in to her quarters. Looking very content and love-drunk, she has a brief conversation with Gaeda before he leaves. She carefully places her ring on a hook with some of her other personal effects, then pulls her gun and shoots herself in the head. I didn't think BSG could pull off the shock gun trick again but the circumstances were such that it played excellently.
Although hardly remarkable when first seen, it becomes apparent that the earlier scene in which Dee finds the jacks in the dirt on Earth might have some relevance to her decision to blow her brains out. Throughout the episode some of the cylons have flashbacks of former lives on Earth when it's armageddon occurred which opens many questions about how they remember it and how they got from point A (Earth in a Cylon society, apparently 2000 years before the events of BSG) to point B (the Colonies, thinking they were human and having no memory of those years). Dee's encounter with the jacks may have inspired a similar flashback which either instilled just enough melancholy or just enough knowledge for her to say fuck this shit. We won't know until we see the next one. I can't wait.
Monday, January 19, 2009
Planes in ODE
The ODE documentation is quite lacking. Since it's a wiki I'll probably help to improve it as I use it but for anyone who wants to better understand ODE's Plane geometry, here you go:
The plane geometry is, well, a plane. But it's not really, it's actually a half-space, which means that stuff on the "solid" side of the plane is ejected out violently toward the "empty" side. To specify a plane you use the basic plane formula:
Ax + By + Cz = D
If you've had a math class that covered it, great, I bet you know how this works. For those that haven't, (A,B,C) is the normal vector (or unit vector) of the plane, and D is the distance from the origin along that normal. Now, the open side of the plane is on the positive (larger) side of the normal, ie the side of the plane that the normal would point to if it was, in fact, an actual arrow.
To illustrate this point, here are some axis-aligned planes and an explanation of which side is open and which is closed:
Plane (1, 0, 0, 0) is aligned to the X axis, with positive X values being in the open side. The plane (-1, 0, 0, 0) is also aligned to the X axis, but conversely the negative X values are in the open side of the half space.
Likewise, (0, 0, 1, 0) is aligned Z, with the open side on the positive side. To have the other half of the plane open, it is (0, 0, -1, 0).
The opposite portion of the half space of any given plane can be defined as the opposite of it's formula, for instance both of the following planes are on the same line but specify the opposite portion of the plane as the open space: (123, 456, -789, 10) and (-123, -456, 789, -10) (although ODE won't like these as the vector (A,B,C) should be normalized to a length of 1-- just illustrating the point).
Sure, most of this is pretty straightforward but the documentation is completely lacking in the fundamental information, hardly making a mention of the slightly deceptive nature of it's name (it's called Plane but it's actually a half-space). Maybe this will help the next maths-deficient ODE user to not waste time playing with planes to understand their construction and behavior. Unless you still want to. It can be fun.
Tuesday, January 13, 2009
Philosophia
So the new semester is underway and although I couldn't get the math class I needed (damn my procrastination!) I did get a chance to work on some of the liberal studies requirements for my major. I'm taking an introductory philosophy class toward that end, and already I've learned more about philosophy than I thought I knew before. Which is a funny way of putting it but it describes it well.
We've started with Plato's Apology-- now previously I've not studied any more about Socrates than was necessary to complete high school but from this one dialogue I've found out that I've been missing a lot of keen insights into understanding ethics and virtues. If you are not familiar (don't feel bad!), I've summarized the first half or so of it. I've added a couple comments which I've colored blue, so those who are already familiar with the work can skip past the summaries.
We've started with Plato's Apology-- now previously I've not studied any more about Socrates than was necessary to complete high school but from this one dialogue I've found out that I've been missing a lot of keen insights into understanding ethics and virtues. If you are not familiar (don't feel bad!), I've summarized the first half or so of it. I've added a couple comments which I've colored blue, so those who are already familiar with the work can skip past the summaries.
In Apology Socrates is defending himself against two charges brought by his enemies, old and new. The first group hates Socrates because they were at the blunt end of his philosophical wisdom detector (that is, his mind). Socrates explained that Chaeraphon had approached the oracle of Delphi and asked her whether there was any man wiser than Socrates. The oracle replied that there was no man wiser. Chaeraphon returned the news to Socrates.
Socrates was very puzzled by this, knowing that he was not wise he was curious about why Delphi had declared this. So Socrates decided to find the meaning of the god's words by seeing for himself the wisdom of a respected Athenian, a wiser man than himself. He first selected a politician for examination who was reputed to be a wise and virtuous man. Socrates' discussion with this man quickly lead him to the conclusion that his reputation was false. Socrates felt it his duty to show the man that his wisdom was founded upon the politician's self-image, and he quickly made an enemy of him.
Still searching for a wiser man, Socrates then talked to one politican after the other but could find no man who's "wisdom" was true. He then talked to poets of all sorts. He asked them questions about the meaning and significance of their verses. Although the poets acclaimed their own work beautifully, none of them could tell him the messages behind their most popular works. He concluded that the poets acted more on inspiration than deep thoughtfulness. He continued, talking to artisans, orators and many of other professions but still could not find a single man whose wisdom was true.
The second class of his accusers, led by Meletus, said that Socrates was a deceiver of youth and that he did not follow the religion of the State (Greece, so the Greek gods which I'm sure you are aware of).
Socrates questioned Meletus directly asking him firstly who was a man worthy of improving the youth of Athens. Meletus replied that the laws were their improver. Socrates then asked who would know the law to which he replied that the jury presently in the court knew the laws. Of course Meletus replied affirmatively and Socrates had him confirm that the jury was in fact capable of improving the youth of Athens. Socrates then had him confirm that the senators were capable of improving the youth. Finally he said surely the assemblymen must corrupt the youth then? And Meletus said no, the assemblymen also improve their youth. Socrates then stated that, according to Meletus, everyone improves the youth of Athens-- except Socrates of course.
Socrates handling of the first charge is impeccable, certainly worthy of modern day practice of law, despite his admitted lack of experience in the field. In this part he showed that Meletus was not concerned with the guilt nor innocence of Socrates', but merely that he is punished for his personal vengeance (as Meletus was at the sharp end of a wisdom assessment by one of Socrates' followers). The fact (confirmed by Meletus himself) was that in his eyes, Socrates was incapable of improving youth merely because of his identity.
Towards the second charge, Socrates asked whether Meletus was implying that he worshipped different gods or was an atheist. Meletus confirmed it was the latter. He then asked Meletus whether a person can believe in divine actions without believing in gods. Meletus replied negatively, saying that no, a man who believes in divine actions must believe in gods. Socrates then pointed out the differences between Meletus' testimony and the indictment which he swore by as his charges against Socrates, in which he says under oath that Socrates taught and believed in divine activites.
Once again, Socrates has nailed down another charge in a way that would probably result in a charge of perjury against Meletus and a quick exoneration of the second set of charges against Socrates in the modern legal system of the US. He shows his excellent reasoning skills which also seem to resonate the falsehood of the charge of his deception too, as he does no deceiving of any kind, presenting only the contradictions of his accusers.
I won't cover the whole story as it is rather lengthy and Socrates points are many. In fact, I doubt I could express his arguments eloquently in my crudely insufficient hardly-philosophical way but it's a story that by the end had made me regret not investigating the orations recorded by Plato and subsequently Plato's student Aristotle. I can tell you that Socrates is found guilty, but the most amazing part of the story is the punishment which Socrates himself proposes to the court and Socrates final speech after the proceedings were finished. (in the legal system of ancient Greece both the offense and defense parties would propose punishment which the original jury would vote on).
So if you are currently an undergrad and need some liberal studies classes outside of your major, take a philosophy class. Many times requirements for even introductory philosophy classes can be intense, and of course there is lots of deep and abstract readings, but that's a pro in my book! It's not much worse than your average history or composition class anyway.
Socrates was very puzzled by this, knowing that he was not wise he was curious about why Delphi had declared this. So Socrates decided to find the meaning of the god's words by seeing for himself the wisdom of a respected Athenian, a wiser man than himself. He first selected a politician for examination who was reputed to be a wise and virtuous man. Socrates' discussion with this man quickly lead him to the conclusion that his reputation was false. Socrates felt it his duty to show the man that his wisdom was founded upon the politician's self-image, and he quickly made an enemy of him.
Still searching for a wiser man, Socrates then talked to one politican after the other but could find no man who's "wisdom" was true. He then talked to poets of all sorts. He asked them questions about the meaning and significance of their verses. Although the poets acclaimed their own work beautifully, none of them could tell him the messages behind their most popular works. He concluded that the poets acted more on inspiration than deep thoughtfulness. He continued, talking to artisans, orators and many of other professions but still could not find a single man whose wisdom was true.
The second class of his accusers, led by Meletus, said that Socrates was a deceiver of youth and that he did not follow the religion of the State (Greece, so the Greek gods which I'm sure you are aware of).
Socrates questioned Meletus directly asking him firstly who was a man worthy of improving the youth of Athens. Meletus replied that the laws were their improver. Socrates then asked who would know the law to which he replied that the jury presently in the court knew the laws. Of course Meletus replied affirmatively and Socrates had him confirm that the jury was in fact capable of improving the youth of Athens. Socrates then had him confirm that the senators were capable of improving the youth. Finally he said surely the assemblymen must corrupt the youth then? And Meletus said no, the assemblymen also improve their youth. Socrates then stated that, according to Meletus, everyone improves the youth of Athens-- except Socrates of course.
Socrates handling of the first charge is impeccable, certainly worthy of modern day practice of law, despite his admitted lack of experience in the field. In this part he showed that Meletus was not concerned with the guilt nor innocence of Socrates', but merely that he is punished for his personal vengeance (as Meletus was at the sharp end of a wisdom assessment by one of Socrates' followers). The fact (confirmed by Meletus himself) was that in his eyes, Socrates was incapable of improving youth merely because of his identity.
Towards the second charge, Socrates asked whether Meletus was implying that he worshipped different gods or was an atheist. Meletus confirmed it was the latter. He then asked Meletus whether a person can believe in divine actions without believing in gods. Meletus replied negatively, saying that no, a man who believes in divine actions must believe in gods. Socrates then pointed out the differences between Meletus' testimony and the indictment which he swore by as his charges against Socrates, in which he says under oath that Socrates taught and believed in divine activites.
Once again, Socrates has nailed down another charge in a way that would probably result in a charge of perjury against Meletus and a quick exoneration of the second set of charges against Socrates in the modern legal system of the US. He shows his excellent reasoning skills which also seem to resonate the falsehood of the charge of his deception too, as he does no deceiving of any kind, presenting only the contradictions of his accusers.
I won't cover the whole story as it is rather lengthy and Socrates points are many. In fact, I doubt I could express his arguments eloquently in my crudely insufficient hardly-philosophical way but it's a story that by the end had made me regret not investigating the orations recorded by Plato and subsequently Plato's student Aristotle. I can tell you that Socrates is found guilty, but the most amazing part of the story is the punishment which Socrates himself proposes to the court and Socrates final speech after the proceedings were finished. (in the legal system of ancient Greece both the offense and defense parties would propose punishment which the original jury would vote on).
So if you are currently an undergrad and need some liberal studies classes outside of your major, take a philosophy class. Many times requirements for even introductory philosophy classes can be intense, and of course there is lots of deep and abstract readings, but that's a pro in my book! It's not much worse than your average history or composition class anyway.
Saturday, January 3, 2009
How Prince of Persia captured my heart, and then skewered it in ground spikes
There's a lot of hype about Prince of Persia's new undying gameplay. If you haven't heard-- in the new Prince of Persia you apparently always have a magical friend who will pull you out of fatal situations to let you keep playing without downtime. I was interested from the point of game design, but as I read my memory began to recall the many recommendations over the years to try the Prince of Persia games. Up until now I never had.
So I finally grabbed a copy of Sands of Time (for those not in the know, that's the PS2-era Prince games). What transpired was a veritably executed bait and switch maneuver by Ubisoft to first steal my heart, and then repeatedly drop it off cliffs into ground spikes.
Let me start by saying that Prince of Persia: Sands of Time is a tour de force of beautiful gameplay, capturing story, and intriguing presentation. The game starts out with the Persian king's siege on the palace of it's enemy the Maharajah, facilitated by the betrayal of the Maharajah's corrupt Vizier Jaffa. The Prince plays a minor role in this, but manages to find his own unique keepsake: the Dagger of Time. This all goes well and the Persian's have their way with the belongings (and apparently maidens) of the Maharajah's palace. They also find a huge hourglass (the Hourglass of Time of course) which they cart off to their friend's palace.
Persuaded by the treacherous Vizier (who for some unknown reason seems to be treated as some sort of trusted advisor to the Persian king??), the Prince stabs the dagger into the Hourglass of Time which manages to release the sands within, ravaging the people and palace in it's wake. The people are turned into what amounts to Zombies, and your goal throughout the game is to get to the hourglass so you can somehow reverse this mess.
The gameplay is phenomenal, consisting of a brilliant blend of fast paced action, intelligent puzzles, excellent plot line, and extraordinary attention to detail. In many parts of the game I was surprised to see how well they had anticipated the character's actions when scripting the voice work, and they even managed to make Farah, your female sidekick, not suck at fighting. There are many times when Farah is in the fight and needs help and no, you don't always have to help her (at least to me, these parts never seemed too much like escort missions). Over the course of the game the Prince and Farah hit it off (surprise, surprise) and the romantic nuances are neither overwhelming nor poorly done.
I finished the game in two days of solid frenzied playing to experience an end which made me happy to have spent the time. I immediately started looking for it's sequel, Warrior Within.
Here's where shit hits the fan. I don't want to say that Warrior Within isn't a decent game in some respects... actually fuck it yeah that's what I'm saying the game sucked. I spent more time on this one than Sands of Time but the reason I spent more time isn't because the game was longer, or I was inspired to keep playing because of it's excellent replay value. No. The reason is because it is so uncompromisingly brutal to it's players.
For those who haven't seen or played it, Warrior Within is the dark sequel. It's the sequel you can be pretty sure was handed over by the Devil when Ubisoft Montreal sold their soul to keep the Prince of Persia franchise alive. Warrior Within couldn't have been the first name they picked: I'm betting on Prince Of War, but alas there was already a popular ultra-violent racy demonic action/adventure game series for the PS2 that sounded like that. But in the end they picked a good name: it's a name which embodies the plot of the game: fighting. What you say? Fighting isn't a plot, but a gameplay element? Tell that to these sell out fucks, the only thing that qualifies as an actual plot point in the game is at the end when the plan doesn't work and you decide to find the Sandwraith mask. And by that point in the game you just don't care, you'd rather skewer yourself in the eye than get involved in anything this game throws you.
Mostly gone are the puzzles from Sands of Time, replaced by neverending sand enemies and mostly crappy rock music. Oh, I won't forget mindlessly repetitive acrobatics, because unlike it's predecessor, all the monkey work in this game revolves primarily about six possible paths, meaning by the end of the game you will fucking hate the world you are in. They didn't have to drain all color from the game. They didn't have to turn the Prince into a God of War wannabe with some unexplained pissed offness about the whole Sands of Time thing (psst: at the end of Sands of Time, everything returns to normal and none of it happened). The only justification for the game (and the journey it entails) is that the Prince is being chased by a big ass beast for fucking with the Sands of Time and not dying. So wait, this Empress of Time bitch makes these sands of time which are supposed to sit in an hourglass doing nothing, and if anyone unlocks them than they have to die? I'm sorry but what was the fucking point of making them in the first place!?
On top of that, the game is infuriatingly difficult, even on Easy. I played through Sands of Time in probably fifteen hours of gameplay with virtually no problems. That game also does not have a difficulty setting. Welcome to Prince of War, where I think the game has more fun killing me and throwing the insidious Game Over screen at my face. Come to think of it, I bet I spent more time sitting behind the game over screen than I did actually playing this game. So many deaths in the game out of reflex my mind said "this would be way more fun if it was easier". So then it says OK well change the difficulty. Crap. Not only am I already on Easy but I would have to start a fresh game to change that.
The game is also extremely glitchy. I had to consult walkthroughs countless times just to make sure I had picked the correct path (the game is only SUPPOSED to give you one path but if you find some of the possible branches and take the wrong one, you will sit there for decades trying to figure out where you went wrong and why there is nowhere to go. There's also lots of scripting glitches. At one point I was supposed to face a mini boss (the Golem), the battle music started but no enemies appeared. So I continued through the room and reached a window where I could look out on the "battlefield" to see the Golem had appeared down there and was patiently waiting for me to go back and kill it. Later in the game you must jump quickly between the masts of a broken ship before they fall down and even if executed perfectly, the Prince will likely glitch out and fall off it, forcing you to waste most of your time rewind powers to make it through it. The game even feature my most hated of all gameplay "features", the times when you have literally the lowest amount of health you can possibly have and you have no choice but to go back to a previous save or face insurmountable odds fighting huge amounts of extremely difficult enemies without getting hit once. Believe it or not, the latter was the quicker option in many scenarios.
The Bink video codec used by the game for cutscenes is absolutely terrible. I'm sorry but my computer is rendering millions of polygons and particle effects, it's applying NUMEROUS vertex and pixel shaders, it's applying realistic lighting settings and real time shadows, and it's using compositing to do motion blurs, color filters, all while the CPU is handling audio, enemy AI, input and general gameplay. This all works pretty fluidly on my system. So the question is, why in Canada's freezer can't the stupid Bink codec play these shitty quality cutscenes properly? This is definitely not just my problem, I found loads of forum posts across the web about frustrated users trying to fix their settings, even upgrading their hardware just to make the stupid cutscenes work right in this game!
There are redeeming points, but really they are all just bait to get you hooked. Once you're deep into the game, you start loathing it; planning it's assassination- some way to stop it from devouring your soul before you finish it. Oh wait, I didn't finish it because I missed some life upgrades and the end boss battle is too difficult for me to care, considering the only way I'll ever get that second ending is if I play through the entire game again and use a walkthrough to make sure I don't miss the hidden life upgrades, which unlike in the Sands of Time, look entirely like the confusing maze your ALREADY trying to get through. I mean big surprise if you miss it considering half of the paths won't let you get back easily. And what would the point of playing through again if it wasn't somehow different. Usually in this sort of scenario I would up the difficulty level one notch. Oh right, I hardly made it through this game on easy. And I don't ever want to see another square foot of that fucking island, nor do I want to ever hear the stupid fight music.
No, I haven't and am not going to play Two Thrones (that's the second sequel to Sands of Time) because I can't risk to be used again for some Persian demonic agenda. I don't have a PS3 or 360 to play the new Prince of Persia, but if I ever do, I think I will just not play it. I played Assassin's Creed before this whole mess and loved every moment. In fact that style of acrobatic gameplay made me enjoy Sands of Time.
This isn't the first franchise with a popular first game and a mind blowingly terrible sexed out, ultraviolent, big budget rock-music button mash romp for a sequel, but the boys at Ubisoft Montreal really took the concept to a new level. It's the kind of game that gives you a choice: stop playing or risk partial or full-on insanity, rage, scitzophrenia, upset stomach, diahhrea, bloody nose, incontinence and partial disembowelment.
It's overwhelmingly disappointing that such an excellent trilogy could be ruined for me by such an astronomically shitty game. The game actually induced me to think about ways to get back at the developers, for wasting not only my time but my love on a sold out piece of shit franchise. There's an air of "the sequel lost it's visionary" and as I look at Jordan Mechner's Wikipedia (the creator of the original PoP game) it
does indeed mention that Mechner was actively involved in Sands of Time, but in name only for Warrior Within as he was busy with the movie. That explains a lot. The true genius leaves the house and all that's left is the wannabe fuck designers who only care about getting a best seller game on their resume, at the expense of the fans. Well it won't be at the expense of me, because I, sir, am not a fan.
So I finally grabbed a copy of Sands of Time (for those not in the know, that's the PS2-era Prince games). What transpired was a veritably executed bait and switch maneuver by Ubisoft to first steal my heart, and then repeatedly drop it off cliffs into ground spikes.
Let me start by saying that Prince of Persia: Sands of Time is a tour de force of beautiful gameplay, capturing story, and intriguing presentation. The game starts out with the Persian king's siege on the palace of it's enemy the Maharajah, facilitated by the betrayal of the Maharajah's corrupt Vizier Jaffa. The Prince plays a minor role in this, but manages to find his own unique keepsake: the Dagger of Time. This all goes well and the Persian's have their way with the belongings (and apparently maidens) of the Maharajah's palace. They also find a huge hourglass (the Hourglass of Time of course) which they cart off to their friend's palace.
Persuaded by the treacherous Vizier (who for some unknown reason seems to be treated as some sort of trusted advisor to the Persian king??), the Prince stabs the dagger into the Hourglass of Time which manages to release the sands within, ravaging the people and palace in it's wake. The people are turned into what amounts to Zombies, and your goal throughout the game is to get to the hourglass so you can somehow reverse this mess.
The gameplay is phenomenal, consisting of a brilliant blend of fast paced action, intelligent puzzles, excellent plot line, and extraordinary attention to detail. In many parts of the game I was surprised to see how well they had anticipated the character's actions when scripting the voice work, and they even managed to make Farah, your female sidekick, not suck at fighting. There are many times when Farah is in the fight and needs help and no, you don't always have to help her (at least to me, these parts never seemed too much like escort missions). Over the course of the game the Prince and Farah hit it off (surprise, surprise) and the romantic nuances are neither overwhelming nor poorly done.
I finished the game in two days of solid frenzied playing to experience an end which made me happy to have spent the time. I immediately started looking for it's sequel, Warrior Within.
Here's where shit hits the fan. I don't want to say that Warrior Within isn't a decent game in some respects... actually fuck it yeah that's what I'm saying the game sucked. I spent more time on this one than Sands of Time but the reason I spent more time isn't because the game was longer, or I was inspired to keep playing because of it's excellent replay value. No. The reason is because it is so uncompromisingly brutal to it's players.
For those who haven't seen or played it, Warrior Within is the dark sequel. It's the sequel you can be pretty sure was handed over by the Devil when Ubisoft Montreal sold their soul to keep the Prince of Persia franchise alive. Warrior Within couldn't have been the first name they picked: I'm betting on Prince Of War, but alas there was already a popular ultra-violent racy demonic action/adventure game series for the PS2 that sounded like that. But in the end they picked a good name: it's a name which embodies the plot of the game: fighting. What you say? Fighting isn't a plot, but a gameplay element? Tell that to these sell out fucks, the only thing that qualifies as an actual plot point in the game is at the end when the plan doesn't work and you decide to find the Sandwraith mask. And by that point in the game you just don't care, you'd rather skewer yourself in the eye than get involved in anything this game throws you.
Mostly gone are the puzzles from Sands of Time, replaced by neverending sand enemies and mostly crappy rock music. Oh, I won't forget mindlessly repetitive acrobatics, because unlike it's predecessor, all the monkey work in this game revolves primarily about six possible paths, meaning by the end of the game you will fucking hate the world you are in. They didn't have to drain all color from the game. They didn't have to turn the Prince into a God of War wannabe with some unexplained pissed offness about the whole Sands of Time thing (psst: at the end of Sands of Time, everything returns to normal and none of it happened). The only justification for the game (and the journey it entails) is that the Prince is being chased by a big ass beast for fucking with the Sands of Time and not dying. So wait, this Empress of Time bitch makes these sands of time which are supposed to sit in an hourglass doing nothing, and if anyone unlocks them than they have to die? I'm sorry but what was the fucking point of making them in the first place!?
On top of that, the game is infuriatingly difficult, even on Easy. I played through Sands of Time in probably fifteen hours of gameplay with virtually no problems. That game also does not have a difficulty setting. Welcome to Prince of War, where I think the game has more fun killing me and throwing the insidious Game Over screen at my face. Come to think of it, I bet I spent more time sitting behind the game over screen than I did actually playing this game. So many deaths in the game out of reflex my mind said "this would be way more fun if it was easier". So then it says OK well change the difficulty. Crap. Not only am I already on Easy but I would have to start a fresh game to change that.
The game is also extremely glitchy. I had to consult walkthroughs countless times just to make sure I had picked the correct path (the game is only SUPPOSED to give you one path but if you find some of the possible branches and take the wrong one, you will sit there for decades trying to figure out where you went wrong and why there is nowhere to go. There's also lots of scripting glitches. At one point I was supposed to face a mini boss (the Golem), the battle music started but no enemies appeared. So I continued through the room and reached a window where I could look out on the "battlefield" to see the Golem had appeared down there and was patiently waiting for me to go back and kill it. Later in the game you must jump quickly between the masts of a broken ship before they fall down and even if executed perfectly, the Prince will likely glitch out and fall off it, forcing you to waste most of your time rewind powers to make it through it. The game even feature my most hated of all gameplay "features", the times when you have literally the lowest amount of health you can possibly have and you have no choice but to go back to a previous save or face insurmountable odds fighting huge amounts of extremely difficult enemies without getting hit once. Believe it or not, the latter was the quicker option in many scenarios.
The Bink video codec used by the game for cutscenes is absolutely terrible. I'm sorry but my computer is rendering millions of polygons and particle effects, it's applying NUMEROUS vertex and pixel shaders, it's applying realistic lighting settings and real time shadows, and it's using compositing to do motion blurs, color filters, all while the CPU is handling audio, enemy AI, input and general gameplay. This all works pretty fluidly on my system. So the question is, why in Canada's freezer can't the stupid Bink codec play these shitty quality cutscenes properly? This is definitely not just my problem, I found loads of forum posts across the web about frustrated users trying to fix their settings, even upgrading their hardware just to make the stupid cutscenes work right in this game!
There are redeeming points, but really they are all just bait to get you hooked. Once you're deep into the game, you start loathing it; planning it's assassination- some way to stop it from devouring your soul before you finish it. Oh wait, I didn't finish it because I missed some life upgrades and the end boss battle is too difficult for me to care, considering the only way I'll ever get that second ending is if I play through the entire game again and use a walkthrough to make sure I don't miss the hidden life upgrades, which unlike in the Sands of Time, look entirely like the confusing maze your ALREADY trying to get through. I mean big surprise if you miss it considering half of the paths won't let you get back easily. And what would the point of playing through again if it wasn't somehow different. Usually in this sort of scenario I would up the difficulty level one notch. Oh right, I hardly made it through this game on easy. And I don't ever want to see another square foot of that fucking island, nor do I want to ever hear the stupid fight music.
No, I haven't and am not going to play Two Thrones (that's the second sequel to Sands of Time) because I can't risk to be used again for some Persian demonic agenda. I don't have a PS3 or 360 to play the new Prince of Persia, but if I ever do, I think I will just not play it. I played Assassin's Creed before this whole mess and loved every moment. In fact that style of acrobatic gameplay made me enjoy Sands of Time.
This isn't the first franchise with a popular first game and a mind blowingly terrible sexed out, ultraviolent, big budget rock-music button mash romp for a sequel, but the boys at Ubisoft Montreal really took the concept to a new level. It's the kind of game that gives you a choice: stop playing or risk partial or full-on insanity, rage, scitzophrenia, upset stomach, diahhrea, bloody nose, incontinence and partial disembowelment.
It's overwhelmingly disappointing that such an excellent trilogy could be ruined for me by such an astronomically shitty game. The game actually induced me to think about ways to get back at the developers, for wasting not only my time but my love on a sold out piece of shit franchise. There's an air of "the sequel lost it's visionary" and as I look at Jordan Mechner's Wikipedia (the creator of the original PoP game) it
does indeed mention that Mechner was actively involved in Sands of Time, but in name only for Warrior Within as he was busy with the movie. That explains a lot. The true genius leaves the house and all that's left is the wannabe fuck designers who only care about getting a best seller game on their resume, at the expense of the fans. Well it won't be at the expense of me, because I, sir, am not a fan.
Subscribe to:
Posts (Atom)