Saturday, February 22, 2014

Falsy Values in Javascript

Javascript has a lot of truthy and falsy values. It can be really quite confusing, because this means your code will fail conditionals it shouldn't, and pass conditionals it shouldn't. It takes a little bit of discipline to ensure your code is always returning the right type. Here are some of my notes on the matter.

Truthy values in Javascript:

True
true

Empty object
{}

Empty list
[]

Non-empty string
"Hello, world"

Non-zero numbers
42

... (there are others, mostly variants on objects)


There are only six  falsy values in  Javascript, however:

False
false

Null object
null

Undefined
undefined

NaN
NaN

Zero
0

Empty string
""

There are some very odd things about these lists - the numbers and boolean keywords aside. Like, why are empty strings falsy, but empty arrays aren't? What's a string if not an array? Why aren't empty arrays and empty objects falsy? Why do we have undefined AND null?

In Javascript, there are a lot of ways to introduce bugs, and unfortunately, simple boolean algebra is one of them. Each of these values is truthy or falsy for a reason, but more importantly, they have vastly different use cases.

Empty objects and arrays are truthy because they are both objects. Objects instantiated with the array initializer will have a length attribute and "methods" for pushing, popping, reversing, and so on (because their prototype is the built in Array object). But, the Array object inherits from the base Object, so empty arrays are objects, and all objects in Javascript are truthy - they represent the existence of "something".

Empty strings, however, are an exception to this rule, as part of a conscious design choice. The exact reasoning is beyond my knowledge, but it makes sense to view empty strings as an exception to the rule that an object implies the existence of meaningful information. Not sure it's a decision I'd make, though.

A lot of problems happen because of undefined. Undefined is NOT null, and there is a reason for having both values. It is very important that programmers do not misuse these values, because it will quickly become impossible to determine where bugs are coming from and what the nature of them is.

When a name's value is null, that means it has no defined value. It is not an empty object, zero, the empty list, an empty string - it is undefined, unknown to Javascript. It should be returned when a function is asked for an object and no proper object has been found, or when an identifier needs to be declared but no object for it is available yet (like declaring "class members").

When a name is undefined, that means the name itself, the label, has never been defined in the current scope. It's not that the identifier doesn't have a value, it's that the identifier doesn't exist. There's a difference between a.x = null when x is defined, but not initialized, and a.x when, nowhere inside of a, is there anything with the name x.

In general, you should never, ever return undefined from a function. It's a language feature telling you that there is something fundamentally wrong going on, not a falsy value to let some other function deal with. Null, however, should be returned frequently; every time an object should be returned and nothing could be found, you should return null, not undefined.

Why would you return undefined accidentally? Excellent question. Undefined is the default return type for functions! If you have a void function, it's actually going to return undefined. This means if you don't make sure that every code path contains an explicit return, your function will sometimes return undefined, and sometimes not, which absolutely violates the rule about returning null if no valid answer could be found!

Unfortunately, some (many) of the built-in functions are not insulated against this. Array.pop() returns undefined if the array is empty, rather than null, for example. There's really no solution besides buckling up and learning how to be extremely careful.

NAN is confusing too, not because it's falsy, but because it doesn't equal itself. This makes perfect sense; NaN means "Not a Number", and it means that somewhere, you did a bad in your arithmetic, and wound up with something Javascript can't use. Since it's impossible to know that one non-number equals another, NaN === NaN returns false. To get around this, use the isNaN() function!

A final note: remember to use ===, not ==! This is an example of why:

var arr = [];
(arr == false) //true
(arr === false) //false
!!arr //true

This is because it evaluated arr and false to strings in the "==" comparison, and the empty string is false! BE CAREFUL.


Next post will be about why arithmetic in Javascript is terrifying.







Thursday, February 20, 2014

Lions and Tigers and Javascript (oh my!)

Javascript is awful.

There, I said it. But we're kind of stuck with JS, and it's a good language to know, and it is pretty powerful in a lot of ways. So it's a worthwhile language, but there are a lot of things to watch out for. Since we're doing a project in Javascript, I thought I'd do a post about some of my favorite, and least favorite, things about the language.

The main thing about Javascript to keep in mind is that it was designed for small "script-y" tasks. It was never intended for software development on any kind of major scope, so the core features of the language are built around the novelty of making a website be able to do something, and not to in any way aid the comprehension of the programmer, or the design of large, modular programs. It's a language built on making "clicky button do thing", not software.

Here are some of the things about the language that pop out at me as amazing, terrible, or bizarre (I'll admit, they're mostly gotchas and problems, but there are some wicked cool things you can do with some of these double-edged features):

Object-Oriented to an extreme
This is actually a nice feature. Everything in JS is one of four types: Booleans, Numbers, Strings, and Arrays/Objects. Functions are objects. Arrays and objects are identical, but have different (but interchangable) access patterns. Numbers, booleans, and strings are all actually objects as well, interestingly - they can all be instantiated with the "new" keyword. Once you come to grips with how this works, it can be an incredibly powerful feature, allowing the elimination of tons of work compared to implementing a feature in, say, Java. It's not very secure or powerful in a low level, but it does simplify a lot of things.

Dynamic Types
This is a double edged sword, but I consider it mostly a bad thing. Being able to change the type of an object on the fly without any kind of warning can cause major bugs, like changing "x" from a Number to a String, then performing concatenation instead of addition and wondering why you get "52" instead of "7" when you output x.

Global Scope
Everything in Javascript is global, unless you specify them as local with the "var" keyword. Even then, you can still go through the top-level window element, then follow the crumb trail till you find the appropriate object. Absolutely everything is visible to absolutely everything else, as long as you know where to look. This makes modularity require careful planning, and security laughably nonexistant in JS.

Silent runtime failures
What's worse than a compilation error? A runtime error. What's worse than a runtime error? one that can happen completely silently. Javascript will (depending on the browser and the problem) sometimes spit out errors and then just keep on trucking. Obviously, this can be a major headache. Remember to keep the console open to look for errors when testing, or else silent failures can completely ruin your day.

Javascript supports functional paradigms
That's right! Because functions are objects, you can pass functions around, make lambda expressions, and more. You can make a function foo(function) which takes a function as a parameter, then call it like this "foo(bar)" and have, inside of foo: "function();", which will call "bar". You can even do "foo(function(){ //some code//})" which is a lambda in all but name. BUT before you run off to go write something big using lambdas, you might want to know that...

...Javascript does not have tail call optimization
Why support functional programming and not have tail call optimization? Who knows. Maybe the functional programming support wasn't even intentional, or maybe the tail call optimization interfered with backwards compatibility or the basic language features - the crux of the biscuit is that it doesn't have it, so before you freeze your web browser, don't write anything recursively if you can at all avoid it.

The functional stuff is still useful
Callbacks are contested as bad style by some, but they jive with javascript just fine because of the first-class function business. You can create powerful event-driven systems with callbacks in Javascript with only a few lines of code.

Eval
Just about the most dangerous command in javascript, eval("x") executes x as if it were javascript code. Besides the obvious security loopholes that can arise if you don't scrub your input properly, it's slow, obscures meaning, and is almost never actually necessary.

All Numbers are 64-bit Doubles
This means both that you pay a serious performance price for having them, and that you have absolutely no choice about integer versus floating point numbers, except to use Math.floor()

Bitwise operators are slow
In a bizarre twist, bitwise operators are incredibly inefficient. Don't use bitpacking or bit flags unless you really need to. As a general rule of thumb, trying to be super-efficient in Javascript by using the same techniques you might in C++ or Java is a good way to make things worse.

Functions can return anything, or nothing.
Since everything is an object, you should be careful about what kind of objects you get from functions, and what kind you return. You can have a function that returns a number in some places, a string in others, a complex data structure in one spot, and nothing at all otherwise.

(Global) Functions and variables can be overwritten on-the-fly.
If you redefine a system function, hijinks ensue, and it's perfectly legal. Be careful that the name you're defining isn't already in use! This applies to any variable currently in-scope. Global (top-level) names are always visible. If you overwrite the top-level Math library to say, "foo", you will no longer be able to access any of the Math functions! Make sure to use the "var" keyword to define a scope variable.

'==' and '!=' do Black Magic
They actually convert the type of the object on the left to the type on the right silently before comparing, which can have unexpected results. Instead, use the '===' and '!==' comparisons to test value AND type.

 "new" does not work like in Java
This is good and bad. Prototypal inheritance is powerful, but counterintuitive to Java programmers. The notion is that you can make a "new foo" where "foo" is an object, and the new foo will have all of the properties of foo. You can fake a class system by making all objects intended for inheritance to start with a capital letter. You can also make a chain of classes by inheriting, modifying, inheriting, modifying, etc. This can be dangerous

Objects can have attributes (members) injected at any time
This is pretty cool, in my opinion, but it can be hazardous if used carelessly. You can make a new Foo called x, and then go ahead and say that x.y = "bar", and this new Foo object will now have a field, called y, containing the value "foo". Does this mean that objects of the same class can have radically different contents? ...yes, it does. Use with extreme caution.

This injection allows built-in libraries to be modified
If you decide the Math library needs linear algebra functions, you can just stick them in. Go ahead and say Math.matrixMult = function() { //some code //} and you're off to the races. This is really cool and also really dangerous if used improperly.

classes, functions, objects, methods, and arrays are the same thing
This has already been stated, but let me emphasise: you can make an array, give it some methods, start instantiating new ones with 'new', and call functions that are members ("methods") with the '.' operator. You can even use the '[]' and '.' operators semi-interchangeably. For instance, you can fill an array with a bunch of callback functions using an array syntax, then call "foo[0]()". Weird behavior can occur: strings default to using '[]' to reference a letter. Also, using the '.' syntax versus '[]' breaks down when using variables that have a Number value to reference: if foo = 1, f.foo might be different from f[foo], because f[foo] is interpreted as f[1], while f.foo refers to a field named the object foo. There are other bizarre behaviors. You can absolutely screw up if you're not careful, but this can still be amazingly powerful.

Javascript is not ECMAScript
But, when referring to javascript, most people mean ECMAScript. It is the language specification upon which Javascript is built, but javascript is built by Mozilla/Oracle, and supports features that other browsers don't. So while Javascript has list comprehensions and a boatload of other neat features, Chrome, Safari, and other browsers won't be able to interpret the code.

All functions are variadic
You can at any time pass any number of things to a function.

Careful with parameters
Because there are no type specifiers in Javascript, if you have a function that takes parameters of differing types - especially if there are a lot - they might get the order wrong, and your program will throw errors, possibly silently. Make sure you document all function headers with a type constraint so that users can see what is supposed to be passed, and try to not make a function like "function foo(num1, num2, str, num3, list, num3, str2){...}" because that will cause problems.

Semicolons are optional
foo = 1; is equivalent to foo = 1

Single and double quotes are identical
A char is just a string of size 1. It's strings all the way down.

NaN isn't NaN
Because NaN is a special value meaning not a number, no two "not numbers" can be guaranteed to be equal. Use isNaN(), not == NaN, to test for NaN-ness! This is a very good thing.

Null is an object
I wasn't kidding when I said everything is an object. However, you can't put methods and variables inside null, or change it's value. So at least there's that.

"this" refers to the object  calling a function, not the object containing an object.
In other words, if we have objects A and B, and A.x() passes A.y() to B.z(), like so: B.z(this.y), when we call y, we get an error. why? because inside of B.z, it evaluates it literally; "this.y()". Since B does not contain a function y(), it fails. The standard workaround is to create a local var called "that". Example: "var that = this; B.z(that.y);". This will work, and is considered a standard practice amongst JS programmers.

0, false, '', null, undefined, and NaN all evaluate to false inside of boolean operations
That's right, all of those are "falsy". This can be bad or good, depending on your opinion, but it can lead to unexpected behavior.


This is far from a comprehensive list of all of the problems - err, I mean, the features, of Javascript. The basic  tl;dr is this: it's easy to write horrible, awful, ugly javascript code that won't do what you want it to. Writing good Javascript code is entirely possible, however. I really recommend the book "Javascript: The Good Parts". Once you get past the surprising differences between it and other languages, Javascript can be an excellent language. It might just take a little while to get to that point.






Effective Java

Effective C++ was on the recommended reading for the class, and I recently bought it to give it a chance. I haven't read enough of it to comment (and honestly, I'm going to be learning the language as I go) but I have read Effective Java cover-to-cover and I highly recommend it. I suggest you get a copy, read it, and then keep it as a reference book.

Every serious Java programmer ought to have a copy. Even if you're not that serious, it wouldn't hurt to look.





Sunday, February 9, 2014

Game Programming Resources

Here are a few of the game programming (and general game dev) resources I've found to be useful.

Amit’s Game Programming Information
An absolute treasure trove of game programming tidbits, from how to do hex grids to pathfinding to line of sight to managing economics in MMOs.

Game Design Patterns
Design patterns that relate specifically to game dev. Useful if you have trouble structuring your game code, especially if you like building your core engines on a per-game basis.

Your Game Idea Is Too Big
If you need a little dose of reality.

Procedural Content Wiki
If you're like me, you find procedural content fascinating. This is a great resource.

Gamasutra
A major resource to any industry hopeful. Lots of great articles, resources for finding jobs, and more.

Pathfinding Demo
An online demo for some pathfinding techniques. Very useful for comprehending various search algorithms.

Extra Credits
A video series that focuses on game design.



Tuesday, February 4, 2014

Comments

I have now set comments to the most open, un-filtered settings I could. If this gets taken advantage of by spambots or random jerks, it's going to go away, but until then, feel free to comment - anonymously, if you so desire.

As a secondary minor update, I am finding that  seriously reading, comprehending, and reviewing each proposal is taking a lot longer than I anticipated. A few notes:

1) I'm taking the 0-5 scale seriously. By this, I mean 4 is GOOD.

2) I'm taking the time to try to read and comprehend every proposal I'm going over. This is slow.

3) Virtually anything under the sun can somehow be made better. If you want to be told that your proposal is good without any suggestions for improvement, I'm going to let you down. I would give myself a slough of suggestions based on the good and the bad I'm finding in other people's proposals. Follow them, or don't, they are well intentioned suggestions for making your proposal more compelling sounding, from my perspective.

4) Spelling and grammar count for an awful lot. If you can't communicate your idea effectively, odds are you scored poorly in other sections as well.

5) pdfs on dropbox won't let me use Ctrl+F to find text within Chrome. Very aggravating, but hardly the fault of people who use dropbox.

Right now, I'm working on the fourth review of five. I expect to be all done before midnight, but only just barely.