snapsvg

2013-10-18

Fixing PHP

PHP is not a bad language.

Come back. Let me rephrase that.

PHP is a terrible implementation of what under the surface is a perfectly adequate, dynamic scripting language. Unfortunately it is implemented as a poorly-thought-out, logically bereft templating language, peppered with pitfalls and irritating inconsistencies.

But it can be fixed. It can be fixed with some simple, non-backwardly-compatible, sensible, welcome-to-the-real-world, feasible alterations. Let us begin.

1. Get rid of <?php ?>

The fact that PHP used to be a templating language is archaeologically apparent in this vestigial remnant from a bygone era. These tags are still all over the place because PHP is trying to be two things at once: both a templating language and a scripting language.

Once you grow up (or metastasise) and become a real language, you have to put away childish things.

These break-in-break-out tags were fine when PHP was designed to be parsed by a Perl script and run as a simple if-this, for-each-that dynamic HTML page generator. They remain fine, if you want to use PHP as the templating language it is. But if PHP wants to be taken seriously, the first thing it needs to do is stop hanging on to that I-can-do-templates-me attitude, and hand over to one of the many modern alternatives that have come along since the Internet was still finding its feet.

In fact there's no real reason PHP should not remain a templating language. After all, Mason (and indeed Template Toolkit) allow you to inject actual Perl into your web templates for those times when you simply can't be arsed to abstract your logic to where it's supposed to go. However, if PHP is going to behave like this, it needs to understand there is a difference between a PHP template and a PHP script.

Therefore I propose

1a. Create .php and .phpt file types

Or suchlike. .php files would naturally be PHP scripts and do away with that ridiculous <?php header that persists throughout PHP projects like a blight. .phpt or suchlike would be recognised as text files containing PHP segments, and they can use the old break-in-break-out paradigm to inject program logic into the template.

Of course it is not recommended in Mason or TT2 that you use actual Perl in your actual templates, because then the temptation is just to merge your views with your controller logic, and then you get into a Right Mess. Better would be simply to have a PHP port of TT2 or Mason, or use Twig or Smarty, and allow those to have their own this-bit-is-PHP-and-I'm-sorry directives.

1b. Make it a decent templating language too

It's a bit of an issue that PHP is stupid, as well. Modern templating languages offer myriad text processing options as part of the language itself. An example is the way Template::Toolkit allows you to filter output text through, e.g., the HTML filter, sanitising the data just before it's output.

PHP's best answer to this so far is user-written PHP classes that render PHP templates (two entirely different things written in the same language) by sanitising the data assigned to them at some time or other just before the template file itself is actually rendered.

That's just one example. PHP is not really a templating language any more either, because templating languages have evolved past the very basic output-string behaviour that PHP was originally tasked with. PHPT would need to catch up as well, and separate itself from PHP proper.

2. Stop pretending everything is an HTTP request

That PHP never left its template roots shows when you try to write command-line interfaces into your business software. You realise that you've been assuming throughout the code that the $_SERVER variable actually contains a URI of some description; that there's a protocol; that you're outputting HTML.

As soon as the first file that started with <?php and didn't contain a ?> was created, PHP was broken. As soon as you create a file that contains utility functions, or classes, you have a file that you can run without a webserver . As soon as you have that , you have a scripting language. That was the point at which people should have stood back, taken a look, and dived in to PHP 4 or whatever with the attitude that this time we're going to do it right.

No one did.

PHP still outputs HTML whenever it feels like it - see var_dump . It still has global, HTTP-centred variables. It doesn't do exit codes properly. The fact that exit and die are the same damn thing just shows that someone somewhere has completely misunderstood the point of these things. Heck I don't even know whether error messages actually go on stderr.

At about the time PHP was swapping its soft teething toy for its first big-boy spoon, the rest of the world was discovering that if you interface your HTTP server with your scripting language via stdout, you can maintain a separation of interests wherein your entire business logic is a collection of useful modules or classes or whatever, which when used in a web environment can be wrapped in an HTML layer and called a website - the layer being swappable for a CLI one that outputs the same information in a salient format. Or a JSON one, for public APIs, or even private, socket-based APIs that don't touch either HTTP or even TCP!

Nope. In PHP's land of unicorns and rainbows the whole world is an HTTP request. The world springs into existence when the request begins and disappears when the response is sent, and if anything happens to be left around since the last universe's brief lifespan came and went then that's just something we have to deal with as part of our new one. Trying to leverage command-line support, or non-HTTP support, into this assembly of spit and chewing gum is baby's first steak knife to PHP.

3. Use your own exception mechanism

Nothing is as irritating while working with PHP as when it throws its toys out of the pram. Now, I'm quite happy to accept that a parsing error is completely unrecoverable, but that is it, and absolutely it. Anything and everything that happens at runtime should be tryable, and anything that ever goes wrong should be catchable.

This expected feature of the language should not be taken as a comment on the sense in doing so. Trying to call $app->run() and catching it when it fails is going to be a bit less useful than letting it fail and tell you what was wrong.

But being able to catch it - now that's a tool we need. Since the original error mechanism was put in place a new, superior nonlocal return is available, and one which puts control in the hands of the user (without horrible set_error_handler hacks). Might as well use it.

4. Tidy up the root namespace

We get it. You like functions. Well, take stock and look around you. Not only have you implemented exceptions and then completely failed to use them, you've also implemented classes, interfaces, namespaces, closures and traits and failed to use those as well!

Right. For a start, having all those functions is confusing because there's no consistency in them. I'm not going to rewrite the entirety of A Fractal Of Bad Design , but I'm going to borrow from it here. Some of the functions have underscores, some don't ( strpos / str_rot13 ). Some take arguments one way, some the other ( array_filter($input, $callback) / array_map($callback, $input) ). Every time we use a built-in function we have to look up how it's spelled and what order the arguments are in and there are so. Damn. Many.

Secondly, certainly PHP has to lookup every called symbol in both the user's own symbol tables as well as the language's. That sort of thing is surely expensive, especially if this language is aimed at beginner programmers who are only ever going to use 10% of the functions 90% of the time.

Thirdly, every single built-in function or class is just another name that the user can neither use for their own functions nor override to replace. Sure, PHP has modules that you can jump through hoops to install at the C level, but who needs that?

All of this might be forgivable if this overabundance of global functions covered literally every possible operation a user could conceivably want; but it doesn't! Worse still, a majority of them can trivially be abstracted into one generic function that takes a callable. All the array_* functions, for example: the sort functions are all just user sort with different sort procedures passed in. The filter functions are all the same with different identity functions passed in - and, for a specific example, recently I needed a version of array_search that took a custom identity function! How dare I want the key of a value that has a sub-value that matches my input! PHP says I may not do that and therefore I may not do that.

Ridiculous. The fact the PHP team haven't abstracted this stuff sensibly does not speak in favour of their ability to write the code behind PHP in the first place, does it? It doesn't take a genius to tidy all this up, and yet no one has - nor has anyone written the tidied version alongside. That attitude of constant implacability hurts the language and the community and the reputation of the people behind it, and damages confidence.

Hypothetical inefficiency aside it's just poor maintenance. The language has a mechanism by which to automatically find class files when a non-existent class is requested. So, put all the less-common functions in autoloaded classes and put those classes somewhere discoverable. Everyone else is modular these days. Is it stubbornness or incompetence that's leaving PHP behind?

Also, quit adding useless prefixes or suffixes to your functions. I know you're going to push onto an array because you push onto arrays. So call it push , not array_push .

Also also, don't fob us off with mb_ crap. Fix your Unicode. There's no excuse whatsoever for a language prevalent in the 21st century to be coded by people who can't cope with Unicode, or its various representations. I know, it's hard. Writing a language is hard. If you can't, don't.

5. Expressions, for the love of god

PHP's compiler is apparently written by chimps. Do we still really believe that there is a difference between a statement and an expression? Do we really still have to have "language constructs" (PHP's term) that are parsed and treated differently from any other expression?

No. Maybe back in the stone age we did things that way but here in the age of enlightenment we have come to realise that the only real difference between a statement and an expression is that a statement actually has a persistent effect.

In PHP, for example, the x or y construct has become possible. Except when y is not an expression - which is 90% of the bloody language. return is not an expression. continue is not an expression. die is not an expression, but it is special-cased to work with or , and has been since before we even had the x or y construct in the first place. Because Perl did it. exit is not an expression and does not have the same special-casing in the language that die does, even though it is the exact same thing .

Another example. Normally, () is used to group things, i.e. to override precedence. I'm quite OK with the way it's required for function calls, conditions etc. In PHP, however, these seem to form a magical, ref-breaking construct that is parsed under its own rules. That is to say, in PHP, $a is not guaranteed to be the same as ($a) . That's because PHP is a language whose every feature is a special case in the parser. If $a is a ref, ($a) is not any more.

So what's the point of all these examples? Well hopefully they all bring up the obvious question: why? Why are these things different? For a given X, why does the way you use X have to be allowed by the compiler?

A language built out of expressions is obvious - expressions are what make the operands to operators. And an operator is itself another, larger expression. Suddenly the parsing should seem trivial; you look at a line of code, decide which operators and expressions it contains and run them in a well-defined order. You can see it in the language that when you use an expression it behaves exactly like you'd expect any other expression to behave. At least, it compiles like that - runtime behaviour may be bizarre.

It's trivial to draw up a simple table of PHP's main features in terms of expressions; in all of this the reader is invited to consider in what situations these do not work in PHP's current implementation, and what it means about the compiler for that to be the case. In the table, X and Y mean any expression, i.e. literally anything that compiles.

Construct Meaning Examples Notes
${X} The value referred to by X ${$foo} # $$foo

${f()}

$a = &$b; ${$a}
When X returns a string, look up that variable. Otherwise, treat it as a reference. When X is another variable, the {} can be omitted.
X [Y] Return the element Y from the array X $array['foo']

f()['foo']

x()[y()]

['a', 'b', 'c'][0]
This implements the "feature" that is "special" in PHP 5.5 of array literal dereferencing (example 3)
X() Run the closure X f()()

$x()

['a' => function() {}, ...][$x]($y)
Actual functions like f() are separate, since f is not a valid expression.
X or Y If X is false, run Y $type = $config['type'] or continue;
X and X If X is true, run Y $val = $config['x'] and return $val;

The reader should take away from this at least the awareness that all of the examples in this table would already work if PHP used a proper expression-based grammar; but instead we have been sold these things piecemeal over the past few versions as new features important enough to go on the front page of the release notes.

6. Complete the complement of magic methods

__toString is a pretty good method. It uses an established consistent convention that double-underscore means special-to-PHP. It uses dynamic dispatch so that if it exists it's used, and if it doesn't there's no "default" behaviour - it just complains.

There are also __isset , __set , __get etc. These do what you'd expect: test for setness, default setter, default getter...

Where's __toInt ? __toFloat ? __toArray ? Why is __toString represented and not the others? Furthermore, if you can use a string as an integer and only complain after this conversion, why don't you use __toString first and then try to turn the result into an integer?

Consistency is paramount in a structured, logical world such as programming. Expectations being formed and then violated is the worst of things. It's the Principle of Least Astonishment . Use it.

7. Stop pretending you have types. Or: Have proper types.

What in god's name is this? (int) $val

"Casting," I hear you cry. "It is casting the type of $val to int !"

"Rollocks," I reply in a PG way. For casting is the act of converting a type through known mechanisms to another type. But we don't have __toInt to convert all possible $val s to int , and we don't have mechanisms to convert all possible types in place of int in the first place.

Nope, it is another special case in the PHP compiler, where someone saw another language doing something and implemented the same syntax but completely failed to understand what it was doing, and implement the theory rather than the practice .

What about this? function foo(array $arg)

"Type hinting!" comes the call from the thousands-strong crowd. But if I ask them to explain this mechanism they roll out the usual approximately-right answers they read in the documentation but cannot explain the concept.

PHP is a dynamic language; that's one of its strengths. Dynamic means that PHP exhibits certain runtime features that static languages require at compile time. For the purposes of this section the dynamic features we are interested in are:

  • Runtime method lookup. If an object can perform a method, the method will be performed. If not, a runtime exception is thrown. Inheritance introduces methods from other classes into the object's symbol table, assisting DRY, but otherwise there is no reason every method could not simply be dynamically dispatched to a function somewhere using magic.
  • Automatic type conversion. If an operation requires a string and an integer is provided, or an integer and a string is provided, or a string and an object is provided, PHP will transparently perform the conversion at runtime and only complain if it didn't work.

Now apply your theories about type hinting to this. What can it do but cripple PHP's dynamicity? Duck typing is the principle by which, if you have dynamic method lookup, an object only has to be able to perform a task in order to be considered suitable for the task. That is, until runtime, until you actually try to run the method on the object, there is no way to know that the object cannot do it. If there were you would have sacrificed dynamic method lookup for static compilation already. Type hinting for classes is completely non-semantic if you have the option of duck typing, because there is literally nothing special about your particular class that makes it important that an object is of this type.

How about non-object type hinting? Well you can't actually do that, because int and string aren't types to hint about - probably because any scalar can be used as a string! And any string can be used as an integer! So why enforce the check? Or, from the other perspective, why aren't they types? I can cast to them; why can't I require them?

And why can I require classes but not cast to them?

If we look at the whole type system of PHP as a looser concept than PHP makes it, it makes a lot more sense.

Classes are not some promissory aspect of a piece of data that ensure the datum can perform tasks, but an organisational structure allowing you to introduce functionality from other classes into new ones by inheritance or merging traits. From this perspective, duck typing makes sense - you don't need a specific class to ensure an object can perform tasks; any class can theoretically do it, especially if it consumes a trait that provides it. Type hinting for classes, from this perspective, is logically inconsistent with traits - which are considerably more useful - because you can't test for what a class can do , which is the only thing that's important.

Similarly, basic types are not remotely based on reality either: even if you could ask for a string or an integer, assuming we get the rest of the family of magic methods, any object could have __toString or __toInt . And even if we don't get __toInt , a string can be an int . So if you ask for an int, you could give a string, and you won't know the data the string contains are bad until you try to use it as an int. And you should be able to give an object to a parameter that wants an int simply by casting it to a string and then an int - something PHP should be doing for us already.

Hopefully the reader has spotted the inconsistency between type hinting and a dynamic language: the language cares about what the datum can be , but the type hinting cares about what the datum is . There is absolutely no logical association between what the datum is and what it can do , because Dyamic Point 1 allows for any object - independently of class , thanks to traits and __call - to be able to perform any task; and Dynamic Point 2 allows any type - thanks to __toString and the proposed __toInt and __toArray - to be any other type.

If you're going to have type hinting, therefore, you have to have statically compiled types: you have to enforce the relationship between type and behaviour; otherwise, your type hints are just extra bytes in a file that are going to appear in a commit log at some point in the future deleted by some frustrated developer trying to implement a trait and use it in a method that doesn't expect it.

That's all

I'm sure I could find many more examples of things PHP can fix at a basic level and stop being so irritating about simple things. You'll note I didn't complain about the tiresome conflation of array and dictionary, despite it being the biggest misunderstanding in programming history.

But surely this is a start? We can keep most of the PHP grammar; the syntax doesn't change (much); and so many of the pitfalls and gotchas that a programmer falls into will be resolved in one fell swoop!

As with many things PHP has reached sufficient mass that nothing important will ever change, because the politics of the mailing lists drag everything down, with half-right people expressing their ill-informed opinions on stuff that really, actually matters.

And there's the rub; the alternative is to start again. Start a new, similar language, on the right foot. A language that doesn't have those tags; a language that interfaces with the standard streams properly; a language detached from the web server, that doesn't assume a web environment; a standalone, dynamic, modular language, easy to learn, easy to stick together, easy to run on any decent OS and the not-decent one.

But why? We already have Perl and Ruby and Python. The amount of changes required to PHP means that literally the only reason to improve it at all is that it's associated with the name PHP. Installing it, upgrading it; these things would take an identical amount of effort as simply using an alternative. It wouldn't be sufficiently backwardly compatible that existing PHP code would run, because all the crap you have to do in existing PHP code wouldn't be possible or necessary.

It can still be done, though. But it won't.

2013-07-11

Introducing Pod::Cats

You may notice the title of the blog has changed to Pod::Cats

Pod::Cats is a module I wrote for the original incarnation of the blog at podcats.in (no longer a thing).

The module extends POD conceptually, allowing for arbitrary C<elements> and =commands , and adding new +begin and -end commands.

Check out the docs , and the github repository if you want to help out.

2013-05-31

Pain-Based Learning intitiative

Google will wrongly determine PBL to mean Problem-Based Learning.

I wish to promulgate the observation that pain is a much more effective teaching mechanism than mere adversity.

Pain-based learning has proven to be a great deterrent for git push -f and logging of stupid bugs, and is widely encouraged for any organisation finding itself with rogue behaviour.

2013-05-02

My Manager Is A Git (But I'll Teach Him!) - Part 1

I read (funny term for a writing course) journalism at university because I was tired of the bad rap journalists were getting. I didn't know whether or not there was any genuine corruption in the system—although reading some of the tripe passed off as news to the proletariat made it hard to believe otherwise—but I was determined to do my bit to redress the balance. So I studied journalism, received above-average grades, generally impressed my tutors with my grasp of the language, and proceeded to find not a notepaper's worth of work since.

Now I work for Hills & Moon. This is a publishing house with an unorthodox business model. The company puts out small, generic, mildly erotic novels: the sort with just enough sauce and simple enough plots to keep middle-aged, bored housewives believing they're being risqué and coming back for more. Each book is credited to an author who doesn't exist—the actual books are written by a team of failed authors and journalists and other such creative types.

A new book starts today. There is just a small team of six for this one. Teams are usually between two and twenty, depending on the imminence of the deadline, the profile of the "author", and various other business-related factors we mere writers are too under-educated to understand. Anyway, today five others and I are starting a new story under the assumed pen name Ian Jackson, a new but promising author in the Hills & Moon line-up.

New projects are the highlight of the job. Besides the obvious creative outlet afforded by a blank slate, the process under which we work is interesting as well. There is an internal writing team who churn out plots, frameworks against which we write books. Each "author" has his own formula, or possibly two for a high-profile author. They're all the same basic idea: woman meets man, woman has erotic but unfulfilling relationship with man, man dumps woman, woman goes on bender, woman returns to long-term male friend full of enlightenment about his romantic advances, woman realises hitherto undiscovered feelings for long-term male friend, woman and long-term male friend enter long-term fulfilling relationship. That sort of thing. Adjust a few things here and there, tweak the knobs on the intensity of feelings and levels of eroticism, change the bender to a respectable séjour, and there's the next book, ready for the slavering maws of the listless classes. The main character is always female and always learns some character-building lesson, but not without having some generic fantasy sex with some plastic fantasy man first.

So a new book starts with the next plot already laid out. It's very vague, but the important characters are already sketched out and the story, such as it is, is written. Our job is to fill in the details. This involves a fair amount of collaboration among the team to maintain consistency, but by and large we write fairly large parts of the book independently, especially at the start. This is when we each are given a section of the book to write—two or three chapters each for a team this size—so we get on with it at a fair rate.

When I arrive at the office, then, I'm sent to the room I'll be working in for the next few weeks. Each office has five rows of four desks—which is why there's the twenty-person limit—and at the front sits the manager for this book. His role in this story is to collaborate all the work we produce and make sure it makes sense as it arrives. The upper echelons of management, however, don't favour overstaffing our company, so overseeing a writing project is only part of each manager's workload, what with administrating employees, various communications with the executives, reorganising filing cabinets—who knows what they do. Anyway, this means the managers give only the most cursory of attention to each revision to the manuscript before editing it into the master copy. Occasionally the manager passes the manuscript to the proofreaders and editors, who either give it the OK or send it back with annotations, but mostly we get on with it uninterrupted until it's ready.

We each sit at our desks with two copies of the manuscript. The desks have a number of features worth noting at this point. The first thing is the two spaces where the manuscripts are kept. In one is kept a copy of the master document, the one on the manager's desk. This only changes when his does. The next is an evolving one, covered in notes and annotations and chopped up to our hearts' content. This one we can discard at any time and replace it with a fresh copy of the master document. Don't worry: all the paper is recycled into grocers' bags!

Finally on the desk are a few recesses, one of which contains a pad of headed notepaper. This paper also sports a few formal boxes, and each sheet has a serial number printed on it. These are our revision papers, on which we put our official, final amendments to the story.

The process of work goes like this. We receive two copies of the master document, as described already.

I probably shouldn't really be writing this down. It probably counts as trade secrets. But I am a journalist at heart, and this is my journal, so as long as I don't publish it I suppose I should be OK.

Anyway, two copies. One to scribble on. At the start of the project we all know what we have to do and can work fairly autonomously so we start adapting the manuscript, which at this point only contains the bare-bones framework of the story. We can do as much as we like to the second copy of the manuscript because the only things that actually get accepted are the things written on the serialised notepaper.

So now you should have an image in your mind of six people bent over their desks, peeling off pieces of notepaper and stacking them into one of the other recesses on the desk.

Each filled piece of notepaper is called a revision, since it describes a change to the manuscript. The forms on the sheets include a space to write down the serial number of the previous piece. This is because revisions sometimes apply to other revisions, but since we've already written the other one down it's easier to amend it than to rewrite it. That means that the order is important.

Sometimes we do rewrite a revision, but all that involves is taking a new sheet, writing the new content on it, and replacing the old one with it. This simply means that the sequence of numbers is interrupted, so it's always valuable to know which other revision your new revision is based on.

The interesting part here is that the manuscript also has a serial number. It is the serial number of the last revision that was applied to it. Today at the desk, with our fresh manuscript, its number is zero. I have the first desk, so my notepad has a sheet at the top with the serial number 001-0000-0001. We can get through thousands of revisions before a book is ready.

As we write the story our stacks of revisions grow. My job today is the third chapter, in which the lonely housewife is tiring of her husband being constantly away on business and her friend introduces her to the man who will be her wild, sexually-charged affair. I have to build a generic, toned male character, a sort of bronze Baywatch type, and not allow him to have so much personality that he actually becomes a romantic interest. Nothing new here. Occasionally I will try a new idea, so I will put the revision papers in a new stack. The bottom one will be based on the top of the first stack, so if I like how it goes I can just shove it on top. If I don't, I can just throw the stack away to become bags of apples.

Eventually the six of us have written a sixth of the book each. We know it's not perfect, but we're encouraged to get some meat on the skeleton, since later we can revise it further after a bit of collaboration and discussion. Ideas often come better in groups. So there's no point writing what you think is a masterpiece if it's only going to be updated by someone else who imbued your characters with an unnecessary amount of intelligence in their own section. So we write generically, then step back and look at what we have.

I've finished my chapter now, so I'm going to take my revisions to the manager. I stack up the papers and staple them together. We have this amazing stapler for the job—you should see it. It can literally staple a stack of papers three fingers thick without complaint. As long as we keep the staples out of the content of the revisions it is ideal. Now I have a wad of paper, only about one finger thick, containing a list of revisions to make to the manuscript. The manager will go through them and perform the most boring part of his job, which is to apply each revision to the manuscript.

This takes time, so I make a cup of tea.

There is no drinking or eating at the desks. A kitchen area is provided.

By the time the kettle's boiled the manager is halfway through. By the time the tea has cooled enough for me to start it, he's nearly done. By the time I've actually drunk it, he's not only finished but has printed off a new copy of the master document and replaced the one at his desk with it.

Since I gave him some revisions he has also printed a new copy for me, because I will continue work based on this new copy. And, of course, he has printed a second copy for me to maim wantonly.

The manuscript proudly bears the serial number 001-0000-0054. I wrote fifty-four revisions to complete chapter three.

The process works well, really. It is difficult to apprehend, but I do appreciate that we can work on a section of the book independently of others. I'm writing chapter three. I don't really care what the writers of chapters two and four are going to write, because we have a framework that should guide the plot. The first version is always going to be segmented anyway, so it means we can plaster over the cracks later on and align the story with itself after the first reading.

We've been doing this so long that we can basically preempt what each other is going to do anyway, since a formula is a formula and the story can only really go one way.

Next I'm doing chapter seven. I don't know why I'm not doing chapter nine. That is another one of those things the powers that be decide we are not worthy to know. Clearly they know better than us how to run a ghost writer circus or else we'd be running it instead.

We're not.

I work on chapter seven similarly to chapter three. The husband is on a protracted session away from home and the affair is taking her to Majorca or Minorca or somewhere. Details. Anyway, there's a raunchy sex scene on the train—Budapest, that was it. Orient Express—and too much wine is drunk and there's this heart-to-heart except it isn't because neither of them has one. Well, maybe that's unfair to the characters, but at this point it's all about lust, and that's not a heart thing.

Meanwhile I can hear my colleagues trekking back and forth to the manager's desk and the tea kitchen (coffee is also available) with their stacks of revisions, performing the awkward bit of the process, which I'll get to next. It is inevitable that I will have to do this bit as well, because this part is what happens when someone else has submitted revisions before you.

Remember how we're all working in parallel? Well since I wrote chapter three and had 001-0000-0054 emblazoned upon the official master document (a pristine copy of which still resides on my desk), everyone else has written their chapters as well. Six chapters are now incorporated into our story, and six more are being written. This means that the manuscript on the manager's desk no longer has my serial number on it. I happen to have been paying enough attention to see that desk 4 submitted his chapter last, and that was chapter two.

(I make no pretense of understanding the distribution of work in this office.)

This means that the serial number of the manuscript starts 004. It also means that the last revision was for chapter two, even though chapter two is earlier in the book than mine.

This works because another part of the form on each revision states where in the book the revision takes place. On each of my chapter three revisions I simply took the page number with CHAPTER THREE written on it in revision zero (remember that?) and wrote it on revision 001-0000-0001. This tells the manager that revision 001-0000-0001 goes on that page. Each subsequent revision refers to the page, paragraph, sentence and/or word numbers required to identify the location of that revision in the document. So revision 001-0000-0002's location was the position of CHAPTER THREE, plus the number of paragraphs in 001-0000-0001.

This is very flexible, since it means you can literally amend anything from a single letter to an entire chapter just by filling in the relevant parts of the form and submitting your revision.

Now comes the hard part.

All the work I just did on chapter seven is based on the fact that CHAPTER SEVEN is written on page 178.

In revision zero it was written on page 65, but I added a bunch of pages when I wrote chapter three, so my copy of the manuscript labelled 001-0000-0054 has it on page 178.

Trouble is, if I submit my revisions to the manager now, he's going to reject them, because the first one (001-0000-0055) says it is based on 001-0000-0054. The manager has changed things considerably since then, so he's not prepared to even consider it. He's busy, remember? He can't deal with that sort of thing. That's our job.

The master document's last revision is that one from chapter two that starts 004. I only knew it started 004 because desk 4 submitted it. I don't know what the rest of the manuscript looks like; especially not where CHAPTER SEVEN has got to.

I need to update my manuscript.

I ask the manager for a new copy. He obliges, and sure enough, the manuscript's serial number is 004-0000-0086. Desk four took eighty-six revisions to write chapter two. No wonder he submitted last.

Since I know nothing after chapter six has been touched, I can simply do two things.

First, I will find where CHAPTER SEVEN is and amend the form on revision 001-0000-0055, the first part of chapter seven, to reflect the new page number.

The second thing I will do is change the form on that same revision to say that it is actually based on 004-0000-0086. This is a simple process, because remember that revision 001-0000-0056 is based on 001-0000-0055, and the manager doesn't know about that one yet.

Now I can give everything a once-over to make sure no one's snuck anything in the original document inside chapter seven (otherwise the revisions I made would not make sense!), and re-submit my work.

I make another cup of tea because the manager is incorporating my work. All I had to do was say that my first revision sheet in chapter seven was based on the master document, and not my ancient copy of it, and it was all fine.

The manager is strict, but we avoid lots of problems this way. Otherwise he'd have to spend time trying to figure out how to make what we're telling him to do work with what actually exists. That's the job of the creative team—the writers—not the managerial team. Imagine letting managers try to decide which of two versions of a story makes the book better! It would be a disaster. Simpler not to look, and to just make us rewrite the second version that comes along.

The manager finishes creating the copy with chapter seven in it, but there's little time to complete the next part today. The major part of both chapter three and chapter seven are already complete, and I have time to read over the whole manuscript and identify inconsistencies in the plot, awkward scenes, contrived scenarios, not-contrived-enough scenarios and generally give our current progress a once-over to see how we're getting on. I fill in a few revision sheets, but I keep them on my desk. They're just private musings at the moment, and I might never send them out.

With a few notes on my desk, and more ideas rattling around my head, I fetch my jacket and wander home to let my subconscious sort my thoughts out for me.

2013-04-29

Monsieur, with these simple one-job jQuery plugins you are really spoiling us.

Today's new jQuery plugin is the check-all plugin: https://github.com/propcom/jquery-checkall

It has a couple of bugs at the time of writing, but I'll probably have those fixed this week.

Usage is quite simple (obviously); you target the 'All' checkbox and tell the plugin how to recognise all the others:

    $('#check-all').checkAll({
        rel: '.normal-checkbox'
    });

As with all of my plugins, if the selector selects multiple things, it loops over them so each one gets its own context.

2013-04-17

Announcing two new jQuery plugins

I like to keep things simple. I get a bit tired of trawling through pages of misinformation trying to figure out how to use a behemoth library when all I want is a simple feature.

Yesterday I uploaded very alpha (but working for me) editions of two new jQuery plugins that I wrote to solve the problem of having to read too much.

sort-by


http://github.com/propcom/jquery-sortBy

jQuery doesn't provide a .sort() method, but if it did it would be wrong.

sort-by uses the Schwartzian Transform concept to sort the children of the element you run it on. It takes a function, and the function is provided each child. The function returns a value by which the child may be sorted, and then the children are sorted in-place based on that.

You can view an example at http://propcom.github.io/jquery-sortBy

Checkbox Linked Lists


https://github.com/propcom/jQuery-checkbox-linked-list

This plugin relies on sort-by and jQuery UI. jQuery UI sucks so I'd like to not use it but for now it does.

The plugin takes all children of an element and splits them into two lists; the first list contains all children that contained a checkbox that was checked, and the second contains all children that contained a checkbox that wasn't checked. Then the checkboxes are hidden and the items can be swapped between the two lists. The plugin changes the checkboxes as it runs so that posting the form works exactly as it did before you implemented it.

Examples to come! Enjoy!

2013-03-28

Cannot reassign $this?

PHP won't let you reassign $this because it is a readonly reference to the contextual object.


class Test {
    var $foo = "bar";

    function abc() {
        $this = "Hello!";
    }
}

$test = new Test();
$test->abc();

PHP Fatal error:  Cannot re-assign $this in - on line 14

Fatal error: Cannot re-assign $this in - on line 14

Since PHP has the flaw of allowing you to use variables as variables, however, you can put 'this' in a variable. PHP doesn't seem to notice that that's assigning to $this:


class Test {
    var $foo = "bar";

    function abc() {
        $thisStr = "this";
        $$thisStr = "Hello!";
    }
}

$test = new Test();
$test->abc();

Tricked you!


However, if you then use $this as an object, it's still $this! But if you don't, it's not:


class Test {
    var $foo = "bar";

    function abc() {
        var_dump($this);
        var_dump($this->foo);

        $thisStr = "this";

        $$thisStr->foo = "cats";

        $$thisStr = "Hello!";

        var_dump($this);
        var_dump($this->foo);
    }
}

$test = new Test();
$test->abc();

class Test#1 (1) {
  public $foo =>
  string(3) "bar"
}
string(3) "bar"
string(6) "Hello!"
string(4) "cats"

Surely someone's realised by now that the people behind PHP might not really know what they're doing.


Edit: turns out this already came from reddit

2013-03-08

Gnu Passive-Aggressive Public Licence (GPAPL)

This licence is for people reluctant to give away code but who understand the rationale behind it.

This program is free software. I wouldn't expect you to pay for it anyway.
You can and probably will redistribute it and/or modify it under the terms 
of the GNU General Public License as painstakingly published by the Free 
Software Foundation, either version 3 of the License, or (at your option, 
if you think that's best) any later version. I know you're going to anyway
so I might as well legitimise it. 

This program is distributed in the hope that it will be useful, not that you 
care, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, especially yours.  
If you can find the energy, see the GNU General Public License for more 
details, but it's OK if you don't. Most people don't. Whatever.

You should have received a copy of the GNU General Public License
along with this program.  If not, all I can really do is point you to this URL 
<http://www.gnu.org/licenses/> and assume you're going to follow it. I can't
force you so whatever. Just have it. 

The GPAPL is released under the WTFPL, as if you care.