snapsvg

2012-07-27

Quick jQuery empty-object test

Arrays have .length but objects don't.

But since you're already using jQuery you can simply use param() to get a truthy value for the object:

  if ($.param(obj)) {
    // obj has stuff
  }

Al out.

2012-07-23

empty() Considered Harmful

PHP has a function—which may or may not be a function—called empty().

From its docs:

A variable is considered empty if it does not exist or if its value equals FALSE. empty() does not generate a warning if the variable does not exist.


First of all let's apply a little bit of logic. If the value equals false, that means that

  empty($foo)

is exactly the same as

  $foo == FALSE

which is, in turn, exactly the same as

  ! $foo

So these expressions are identical.

Except for one small thing:

empty() does not generate a warning if the variable does not exist.

Absolutely, never ever, in the name of all that is good and holy, even consider doing something like this.

I mean, for fuck's sake, this is a language that complains if an array index doesn't exist!

One of the most basic rules in programming is that you get the compiler and runtime systems to tell you when things are wrong as much as is humanly possible. The stricter the better! Except possibly in the case of PHP, it is almost certain that the person who wrote the language you're using is smarter than you are. It is certain that your compiler (or at least your runtime machine) knows whether or not what you have written is valid. If you suppress the computer's warning that you've done something wrong then you're a fucking idiot, pardon my English.

Testing a variable for empty instead of falseness does exactly one extra thing: it suppresses one of the most useful error messages actually available in PHP, which is that you've misspelled your variable name. Why in god's name would you do that?

The Sanctity Of The Symbol


See, the variable space is sacrosanct, OK? That's essentially rule number one. When you create a variable you are performing a ritual, a rite of ascension, that brings the abstract, incorporeal idea of an item of data from your grey matter and establishes it, manifests it in a real way in the script of your program. This variable serves a purpose: it is a vessel in which you are going to put information without which your routine will surely fail! It is a transferrable, mutable mug of the elixir of the programming gods, a chalice of the very stuff of which a program's execution is made.

Ideally, to create such a vessel would require some sort of incantation, a keyword of declaration. But if you don't have one, the next best thing is to have it be a horrible, terrible crime to try to sip juice from a cup that does not exist!

But! I hear you cry. But what of the processed symbol names? What of those, collected by a prefix, whose existence allows us to enumerate a user's input, and determine whether the input is enough, or missing, or will cause us to behave differently?

I say unto thee: That's what the associative array is for you bozo. An associative array, stored in the sacrosanct variable, is an anarchic, loose, free data dump, in which one can add arbitrary keys, string symbols inherently grouped under the bosom of the variable's own name, but milling around, free radicals in the womb of the variable. To complain about the non-existence of a key in an associative array is to complain about the non-existence of the girl from the ice-cream stall in the club you happened to wander into today. It is legitimate, nay expected, that in this array some information exists and some does not.

The non-existence of a variable is fact. It is not optional. Do not test for a variable's existence. Do not avoid the penalty for accessing one. If you cannot birth your variables with a word of magic, at least do not dismiss the warnings of the almighty when it tells you that your variable is not even there.

2012-07-19

Today's PHP-induced bug: arbitrary object properties

Today's stupid bug that shouldn't happen is brought to you by PHP's retarded object system. The various systems it appears to be bastardised from are incompatible but it is mostly similar to Java's: single inheritance, interfaces and access protection.

Access protection is where today's bug comes from. As you had better already know, PHP's classes can be declared with properties:

class Foo {
    public $bar;
    protected $_foo;
    private $_baz;
}

This declares that, with an object $obj of type Foo one can access $obj->bar but not $obj->_foo or $obj->_baz without being lexically within the class (for $_baz) or a subclass (for $_bar) of Foo.

But unlike Java's slightly more robust system, PHP allows you to arbitrarily create properties on objects:

$obj->bazinga = 1;

Since bazinga is not even declared on class Foo, the correct response for any self-respecting object system would be to tell you to sod off and stop playing the fool.

Alternatively, it would not provide a way for you to declare properties on the class in the first place, because doing so is wholly inappropriate when any property not declared is implicitly available, and public.

This sort of logic is akin to the logic of the courts that ruled that ISPs must block the pirate bay, but not block any other website that shares torrents, nor any website that allows you to access the pirate bay via proxy. That is to say, it's never going to work.

The problem is of course that the point of declaring protected and private member variables on classes is twofold, like most things:

  1. The structure of the data represented by objects of this class is a defined contract. Attempting to access non-existent properties will error because the user is trying to do something that cannot be done by the contractual interface, meaning that the user is most likely mistaken as to the identity of the variable they are dealing with.
  2. The data structure of the object is usually not for public consumption and defines a state in which the object may be. The object exposes an interface by which the data values can be manipulated but the user has no control over how this manipulation takes place internally.

If you want arbitrary strings to be available as a public property on a data structure you wanted a map. This is implemented as an associative array in PHP, a hash in Perl and Ruby, and a dictionary in Python.

Point 1 of the two reasons why you don't do what PHP doesn't understand why you don't do is the reason why I wish it didn't. I had defined an interface on my class promising that any value passed to a particular method would be later returned by the same method when not passed any argument besides null:

public function value($val = null) {
    if ($val !== null) {
        $this->_value = $val;
    }

    return $this->_value;
}

A very common interface. The fact that it is implemented by storing the value in the protected property $_value is no business of the user's. The class defined no public property '$value' but, when I did this:

$obj->value = 'foo';

No complaints were raised. And yet for all such objects, nullness persisted throughout my data.

It is not simply that my class, not having declared the property 'value', had no obligations regarding such a property: the interface defined on my class had the very specific obligation to deny the property 'value' from being accessed in any way whatsoever, because that property is not a part of the data structure represented in my class.

PHP allows you to access any identifier on an object as a property, and only the subset that you explicitly declare protected will be so. The rest are first given to a special method called __get to get, or __set to set, and if they do nothing it just goes ahead and creates something for you.

I have no implicit problem with these magic get/set methods per se—the problem arrives when the default function of these methods is to allow the thing through! If the default reaction were to tell you to take a hike this whole thing would be fine. Give a class the opportunity to deal with arbitrary properties, sure; that then becomes part of the contractual interface of the object. But no contract should be so liberal as to let people crap all over them unchecked.

PHP: you are doing classes wrong.