No to a Uniform Variable Syntax

As you might have heard, PHP developers voted on an RFC called "Uniform Variable Syntax". This RFC "proposes the introduction of an internally consistent and complete variable syntax". In general, this RFC argues for making PHP's parser more complete for all sorts of variable dereferences. For example:

$foo()['bar']()
[$obj1, $obj2][0]->prop
$foo->bar()()
$foo::$bar::$baz

Thirty people voted for, and one against: Me.

Does that mean that I am against a unified variable syntax? No, I am not. I am actually quite a fan of having a consistent language, but we need to be careful when this hits existing users.

The already accepted RFC also has some negative aspects, in the form of backwards compatibility (BC) breaks. For example (quoted from the RFC):

// syntax               // old meaning            // new meaning
$$foo['bar']['baz']     ${$foo['bar']['baz']}     ($$foo)['bar']['baz']
$foo->$bar['baz']       $foo->{$bar['baz']}       ($foo->$bar)['baz']
$foo->$bar['baz']()     $foo->{$bar['baz']}()     ($foo->$bar)['baz']()
Foo::$bar['baz']()      Foo::{$bar['baz']}()      (Foo::$bar)['baz']()

This basically says that the RFC author knows there are BC breaks, but choses to ignore how this might annoy users.

Unlike keyword additions, or functions and/or settings being removed, this change in semantics is probably one of the worst BC breaks you can imagine. You can't really write a scanner for it, as the code could already have been converted. A tiny change like this however, can create very hard to debug issues within existing code. And this is exactly why people whine that PHP breaks BC and does not care about its users. In many cases, breaking BC happens by accident, and I'm no stranger to breaking BC due to some oversight. Accidents like this are certainly annoying, but slightly unavoidable as we do not have test cases for everything.

However, when you know for certain that you are going to break BC, there is no excuse. With such a marginal new "feature" as is outlined in this RFC, antagonising our users is not a good thing.

Shortlink

This article has a short URL available: http://drck.me/nobc-b11

Comments

Thank you.

I voted in favor of this RFC knowing full well that it represented a BC break. I was okay with this for one major reason:

The RFC was explicitly offered for inclusion in the next major (PHP6, PHP7, whatever people want to call it).

This is precisely what major versions are for: improvements that might break backwards compatibility in exchange for a better language. Is BC critically important for the success of any language? Absolutely. Is this break justifiable for a major version? In my opinion, absolutely.

If this RFC were offered for any minor version I would have been strenuously against it. Thankfully, that was not the case. Any user upgrading to a new major version with the expectation that all existing code will "just work" is destined for problems regardless. Such users must not be held out as justification for holding back language progress.

Just my two cents on the subject :)

Daniel,

Even for a new major version being able to break BC doesn't mean it's good. Changing BC adds costs to everybody in the environment. Developers having to review the code, IDE developers, tool developers, ...

This case might actually be bad - you have to be very careful in a review to find this and figure out whether the old or new way is expected.

As Bjarne Stroustrup says: "Compatibility is a feature." To existing users who can stay up to date easily as well as to new users who can be assured that their investment is safe. Randomly changing the language doesn't do that. Randomly changing the language tells "be prepared to continuously reviewing your code for breakage" instead of helping them solving their actual issues. Staying up to date should not be an issue for any user.

well, daniel, the thing is, the more BC breaks are in the more legacy you will have aftewards - we now have PHP5 for 10 years, and still there are a few PHP4 users left, because their stuff is not running on PHP5.

Thats a bad thing.

And i'm sorry, but this is not "lets break some minor thing to get a huge benefit", and after just reading this RFC i have to disagree on the "low practical impact" of the BC break.

I agree with you, of course. Historical compatibility is one of PHP's best attributes and must not be discarded lightly. Any BC break must be weighed against the potential havoc it may create in existing codebases. Whether or not a change justifies potential breakage is in the purview of the voting process. The hard part is striking a balance between progress and compatibility. The voting process (in theory) brings the wisdom (hopefully) of the group to bear on this determination.

I don't think anyone wants to see PHP in a Python 3 situation, and for that, Derick's opinion here is 100% valid. Caution and patience are the best antidotes to introducing new WTFs going forward.

Sorry Derick, but i might desagree with your vote.

I'm no expert in the core concepts of PHP, i'm speaking as an user, and as an user that in the past one or two years saw tecnologies like hack, a fork of PHP, being ovacionated just for the fact that they did what PHP was affraid to do, Break BC.

As Daniel Lowrey said and i quote "This is precisely what major versions are for". PHP should evolve and just the fact that some old users with legacy code don't have the courage to grow up and learn how the language evolve in the last 10 years does not change the necessity of evolution that moves the more active community.

In fact i think this is less then the expected but is already a start, i think many more BC breaks should and must be made in order to place the PHP in the new era, or we will loose the train (again).

And you don't need to look too far to see that hungry for change, since this changes doesn't not come from the language itself they grow up widely on the community, the examples are vast, composer, hack, hhvm, FIG and many others are all examples of changes being made on the margins of the language.

Please as an user I ask, bring these changes and this thirsty for changes to the core of the language and stop being so corservatives, lets grow up all together.

Thanks

@Paulo do not confuse new technologies being talked-about on the interwebs with their adoption rate. Do you know many people running today their Wordpress on hhvm?

I was a proponent of the "go-php5" initiative, and I remember how it took a concerted effort of all the major players at the time to get adoption of version 5 kickstarted (which was not, mind you, the abandoning of version 4).

Php is much bigger today, and BC breaks in syntax can not happen unless there is agreement and aoption from:

  • frameworks

  • major apps (cms, etc)

  • operating systems bundling the new version

@gggeek yes, i do know many people running or at least testing wordpress applications, zend framework apps, symfony apps, laravel apps and many more on hhvm, in fact we did a hangout talking just about it, is in portuguese but you can see here: https://www.youtube.com/watch?v=3tGiK4hXDag

And the community arround the most widely used frameworks and applications are exactly the one pushing foward to see new features and changes on PHP, and operating systens will just use the most recent version avaliable on the launch date.

I know that any change is hard to adopt, but they are needed and postpone this changes is not a solution, is just pass the problem ahead, so i rather see this changes now and at once than see it being made in installments.

Hi Derick!

Thank you for writing this post. I think you are right that BC is very important and we should pay attention and try to avoid breaking it as much as possible. But there are things that I disagree with this post. I think main thing I disagree with is that this is a marginal feature. I think the time has come in PHP's life when it's mature enough to try and fix some of the mistakes of its more youthful and careless years. If you look at the meanings table you quote, and hide everything but the leftmost column and forget all BC and just ask yourself - what what I would expect, naively, this to mean - and then open the other two columns again, I think you will discover that in most cases the naive expectation matches the "new" column. Yes, for various reasons, both good and not so good, it was not so in PHP. But we can make it so, and a major version is a good opportunity to do it. Major version is expected to break some things. That does not mean it should, but it is an acceptable price if necessary.

I think it is a big service to our users, most current and future, to try and make their expectations match the reality. Yes, we will have to pay for it, with BC breakage and some temporary pain while moving to PHP.Next. We can ease this pain with tools, etc. but we know we will not be able to avoid it. But once the debt is paid, we'd have much cleaner and consistent language, and I think it is a big win. PHP.Next, which is being started now, is a major opportunity to get such fixes - an opportunity the like of which we probably won't have for another decade or so in PHP. Thus, in my opinion, using this opportunity to fix some of PHP's less appealing parts is not marginal. Compatibility is a feature, yes, but so is cleanness and easiness of use. I think if we have to sacrifice a little of the former to gain a sizeable deal of the latter, it is a worthy investment.

PHP has always been a large collection of inconsistent behavior, even after 14 years of the stuff I still find myself looking up the order of arguments in the manual.

Please please PLEASE vote for every single suggestion that makes it more consistent. Yes that will break BC, but PHP programmers waste a truckload of time trying to deal with the current inconsistencies. It is a lot easier to debug code that has been broken by a newer, more consistent behavior, than by the current inconsistencies.

There is no question that breaking BC, major version or not, can lose you users, and it is always a balancing act. At the same time, not breaking BC can also lose you users.

After more than 10 years of writing PHP and building my entire profressional career on it, I left the community because inconsistencies like this made it impossible to write the kind of functional code that I wanted to write. Frankly, it didn't make sense to me that the language would behave in such an unexpected way, and admittedly I didn't know until recently that the cause was way more fundamental to the internals than I expected.

In any case, this RFC addressed what was easily my biggest complaint about PHP, and I think it is awesome.

Derick, in no way am I upset that you voted against this proposal, but I do hope you consider the benefits of a BC break as well as the hardships. As I said before, it's always a balancing act, but sometimes breaking compatibility is good for the greater community.

Hi Derick,

I really get you point here and being an Obj C developer we have been through a few ugly shifts.

One shift was going from manual reference counting to Automatic Reference Counting. Objective c was pretty good at converting code sometimes but other times not so hot and you have to go fix it.

  1. I do think it would be possible to write a scanner to fix it but the scanner would need to comment the fix so it does not fix it twice. I dont know what the comment would look like but it would mark the function somehow.

  2. With Obj-c we always had a fallback and told the compiler NOT to compile a list of files as ARC and could use the old syntax for this list of files.

For PHP to remain backward compatible I would suggest that a file, names space or directory could be marked as non Uniform Variable Syntax so it would be possible to continue to use these massive libraries that exist today yet have the app code using the new syntax.

John.

Hi Derick, PHP dev here.

I completely agree with you that introducing BC break changes can fall people into problems with existing code.

But think of it another way.

PHP5 was released 10 years ago, but there still are people who write code or libraries that are written in PHP4. Or let's take PHP5.3 which was released 5 years ago, but only recently hosting providers started upgrading PHP version to newer versions.

The point is - upgrading version is always painful and not one-week/month/year thing. People to whom the major version upgrade will cause troubles will either stick to current version or spend some time to fix all BC troubles it caused.

And it's not only about PHP. There're plenty of libraries (no matter what language they're written in) that introduce new changes that are not BC. We always have either to maintain our code to conform them or leave the codebase at some snapshot that is satisfying customer needs.

Just my 2 cents.

Hey Derick

I don't have my own 2 cents to throw in; I just want to say thanks for publicly explaining your opinion. Seeing so many for and one against on the vote made me very curious to know the reasoning.

Thanks

I really understand your point of view. The fact that BC are taken lightly makes me a little bit sad.

In my last few companies, we were always years and years behind the cutting edge. Once your codebase grows to hundreds of thousands of lines of code you are stuck. Any breaking change is a disaster to deal with.

We have just finished migrating rest of our platforms to PHP 5.3 this year and it was a gigantic effort. Doing it all over again with breaking changes? I am not sure if I even want to think of it.

Personally, I could not care less whether I can $foo()['bar']() or not. It has never been an issue for past 10 years and believe me I was pretty busy writing code. If anything, I am a bit worried that people may start abusing it making code an absolute mess.

Thanks for a nice post.

Dead Code

Frequently I've been asked why Xdebug sees "dead code" in places where people don't expect it. Most often this is related to PHPUnit's Code Coverage in the following situations:

1:  <?php
2:  function foo()
3:  {
4:      if ( false )
5:      {
6:          throw new Exception();
7:      } /* line with dead code */
8:
9:      return 42;
10: } /* line with dead code */
11: ?>

The explanation for this is rather simple. Xdebug checks code coverage by adding hooks into certain opcodes. Opcodes are the building blocks of oparrays. PHP converts each element in your script—main body, method, function—to oparrays when it parses them. The PHP engine then executes those oparrays by running some code for each opcode. Opcodes are generated, but they are not optimised. Which means that it does not remove opcodes that can not be executed.

With vld we can see which opcodes are generated. For the above script, there are two elements. The main body of the script, and the foo function. I used vld to show their opcodes, and after some trimming the main script body looks like:

line     #* I O op               ext  return  operands
--------------------------------------------------------
   2     0  >   EXT_STMT
         1      NOP
  12     2      EXT_STMT
         3    > RETURN                        1

We'll ignore this one mostly, as there is nothing much in it, but do notice the RETURN opcode, which represents a return statement in a PHP script. We did not add a return statement, but PHP's parser always puts a RETURN opcode at the end of each oparray.

The foo function's oparray looks like:

line     #* I O op               ext  return  operands
--------------------------------------------------------
   2     0  >   EXT_NOP
   5     1      EXT_STMT
         2    > JMPZ                          false, ->11
   6     3  >   EXT_STMT
         4      FETCH_CLASS        4  :0      'Exception'
         5      EXT_FCALL_BEGIN
         6      NEW                   $1      :0
         7      DO_FCALL_BY_NAME   0
         8      EXT_FCALL_END
         9    > THROW              0          $1
   7    10*     JMP                           ->11
   9    11  >   EXT_STMT
        12    > RETURN                        42
  10    13*     EXT_STMT
        14*   > RETURN                        null

Xdebug's code coverage marks line 7 and 10 as "dead code". When we look at the vld output above, we see that line 10 has an EXT_STMT and a RETURN statement. But they can never be reached as there is no path through the code that does not hit the RETURN on line 9 first. vld marks dead code with a *. The > in the I and O columns indicate points in the oparray that that are the end point of a jump instruction (ie., the start of a branch) and a location from where a jump is initiated respectively (ie., the exit point out of a branch).

vld actually tells you which branches and paths are found:

branch: #  0; line: 2- 5; sop:  0; eop:  2; out1:   3; out2:  11
branch: #  3; line: 6- 6; sop:  3; eop:  9
branch: # 11; line: 9-10; sop: 11; eop: 14
path #1: 0, 3,
path #2: 0, 11,

Each branch is "named" by its starting opcode entry. For each of the branches, Xdebug, and vld, check whether there is a premature unconditional exit. Conditional exits and jumps are already checked when the oparray is split into branches.

From the three branch definitions you can already see that opcode 10 is not part of any branch as it sits between an exit point and an entry point. Hence it's marked as dead code on line 7. This line contains the closing brace (}) of the if statement.

In the branch covering opcodes 3 to 9 the THROW in opcode 9 is the exit point. For if statements, PHP's code generator always generates an extra JMP at the end. This opcode would simply jump to the next opcode (the jump target is shown as ->11). However, if the branch is exitted prematurely (due to the THROW) in this case, it's not hit. Because it's the only opcode on line 7, the whole line gets marked as "dead code".

In the branch covering opcodes 11 to 14, the RETURN statement in opcode 12 on line 9 is the exit point of the branch, and hence opcodes 13-14 are marked as dead code.

Hopefully this explains that sometimes lines which seem to have code, are marked as dead code. And this is in the cases where PHP gets the line numbers for opcodes right... which isn't always the case either.

For Xdebug, I am improving code coverage to also include path and branch coverage, which should come in Xdebug 2.3.

Shortlink

This article has a short URL available: http://drck.me/deadcode-azx

Comments

No comments yet

Walking the London LOOP - part 15

We took a bit of a rest after last time's mud fest. But this Sunday was very looking very promising weather wise, so we set out to do section 15.

The start of section 15 is easy for us to reach, at only 11 stops on the Overground to Hatch End. We left the station on the way to the start, but after a few hundred meters we realised we forgot to take a photo of the LOOP section at the station. Unfortunately, it's on the other side of the barriers so Morag went back in to snap a photo. With that out of the way, we started towards the start of the section yet again, while spotting some KLM houses in an antique shop for sale.

loop15-d36_6362.jpg

Just after starting the section, we had to battle through some jungle. After a bit we gave up, and took a much easier stroll at the edge of a nearby field. Although technically not quite the LOOP, it sure beat getting stung by nettles and scratched by brambles. A make-shift LOOP sign told us where to go.

We crossed through a field, and under the West Coast Main Line towards Little Oxhey Road. After following this road for a bit we crossed a major road into a field with scary looking Keep Out signs on the right. Not sure why we would be at that side of the massively broken barb wire fence anyway, as there were only nettles and brambles. We walked past the Grims Dyke Golf Club and came upon a marker explaining about Grim's Ditch (or Grim's Dyke), an ancient earthwork.

loop15-d36_6385.jpg

We turned into the woods—infested with mosquitoes as my legs now show—along the ditch. I made a small navigational error and instead of going past Gilbert's Lake, we ended up at his mansion! The house was not built for W.S. Gilbert, but he lived there the last two decades of his life. The elephpants thought it beautiful too. We walked back along the lake and through some woods with only a little bit of mud. When coming out of the woods we hit to top of Grim's Dyke with excellent views over central London. Not much after that, we stopped for a quick pint at The Case is Altered, probably the pub with the weirdest name I've been at.

loop15-d36_6445.jpg

After the pint we went back into the woods for a bit and after a while we crossed into Bentley Priory Nature Reserve, where all the paths were nicely concreted—a big change from all the mud of the last sections. At the other end I found a unmapped postbox. Then we crossed into Stanmore Common and walked around the rugby club to come upon another bit of jungle. More stingy nettles attacked my legs while we walked past the Royal National Orthopedic Hospital.

Out of the jungle we crossed a field filled with buttercups and clover in bloom. We spend some time taking photos. After the nice field, we crossed under the M1 and had to walk a little bit alongside Elstree Road. Probably the least pleasant part of the walk. However, there was another pub, The Fishery. Some snacks, and two local bitters later we continued to finish the section. There was a leisurely walk along the Aldenham Reservoir at the Aldenham Country Park. The last bit of the walk went over fields and over the Elstree Golf Club to end at Elstree & Borehamwood station.

loop15-d36_6482.jpg

The weather was mostly sunny with a few clouds at the start, and a few more at the finish. It was 24°C and not nearly as humid as we feared. We took nearly four hours for this section's 15.5km.

The photos that I took on this section, as well as the photos of the other sections of the LOOP, are available as a Flickr set.

Shortlink

This article has a short URL available: http://drck.me/loop15-azm

Comments

No comments yet

Walking the London LOOP - part 13 and 14

Another Sunday, another walk. You know the drill.

Because we cheekily stopped a little before the end of section 12 last time, we had to go back and do this last mile. So we set off for Harefield where I discovered that I had forgotten my proper camera. So sadly, this walk's photos are done on my phone.

Because we ended at The Old Orchard last time, we found it more than fitting to start this walk at this same pub as well. After a half pint, we walked down the hill to the Grand Union Canal for the last bit of section 12. The weather wasn't as pleasant as the previous weekend, so there were not so many boats on the canal.

There was only about a mile to go in the section and we soon found ourselves at the start of section 13.

Section 13

This section started with a slightly steep path into the first of the woods. After a short section we came out onto fields where there were friendly horses, allotments and some stinky cows. The paths were easy going, with some gravel and some fields. This unfortunately all changed once we got to our first forest.

loop13-20140511_134826a.jpg

From this point on there was a lot of mud, sometimes half a foot deep. There were a lot of grumps and it was very slow going. I guess we should have known better after so much rain the past week.

loop13-20140511_141147a.jpg

There were plenty of nice parts of the walk as well, with fields and meadows. We stopped at Ye Olde Greene Manne for a pint and some snacks, which made us feel quite a lot better. The last stretch went mostly over easy going public footpaths. We crossed underneath the Metropolitan Line near Moor Park towards the end of section 13.

Section 14

loop14-20140511_141938.jpg

Section 14 started by going over Sandy Lodge golf club where we had to avoid flying golf balls (not really). We had some fun with the elephpants in a field full of buttercups. The LOOP continued through a few streets and back into the woods, Oxhey Woods. But it could also have been named for Oxhey Mud Bath. It was not as tough going as in section 13, but it was certainly no fun.

loop14-20140511_175839a.jpg

After a while we crossed another field, and continued walking along some streets before getting into yet another muddy section. But luckily, most of section 14 was alongside fields so that it was rather easy to wipe our boots clean. We were happy to get to the end though of the mud. Finally, we dodged through a bit of jungle to come upon a farm and back onto paved roads. We walked straight to Hatch End station, forgoing our usual "we had made it" pint.

The weather was overcast, with 14°C and a few short showers. We took nearly five hours for the two sections that together were 22.5km long. The mud surely slowed us down.

The photos that I took on this section, as well as the photos of the other sections of the LOOP, are available as a Flickr set.

Shortlink

This article has a short URL available: http://drck.me/loop1314-ayk

Comments

No comments yet

Walking the London LOOP - part 11 and 12

Bank holiday Monday walking, I like it.

Section 11

We ended at West Drayton last time, where we already sneakily had done part of section 11. This to make the last walk a bit longer and this one a bit shorter.

loop11-d36_5517.jpg

Getting to West Drayton was quite straightforward as there are direct trains from Paddington. From the station, we started along the Grand Union canal and walked past a mega-Tesco. Leaving the Grand Union Canal we continued along the Slough Arm and past a canal-boat marina. The paths are all very easy going and soon we came upon the aqueduct that brings the Slough Arm over the river Frays.

loop11-d36_5519.jpg

Just before we got to the river Colne (remember from last time!) we came upon a granite marker indicating that tax (on coal) had to be paid while bringing it into London. We crossed the canal and headed North towards the Little Britain Lake. Named after its sort-of likeness with the shape of Great Britain. There was quite a bit of fishing going on as well, but we left the anglers to their own and crossed the river Colne into Hampshire.

loop11-d36_5521.jpg

We stumbled upon a tree that had fallen into the river, and continued following the river for a considerable amount of time, past industrial estates, to finally get back to the Grand Union Canal near Uxbridge. In Uxbridge section 11 ended, and we went for a well deserved pint at The Good Yarn, a typical Weatherspoon's pub.

Section 12

After our refreshments we headed back to the Grand Union Canal for section 12. Walking along the canal, we first we passed the Uxbridge Lock, crept under the A40 and after a mile and a half we came upon the Denham Deep Lock. Crossing a bridge, we left the side of the canal for a bit walking past disused, and flooded quarries—one with a sailing school.

loop12-d36_5550.jpg

We had the leave the canal for another detour to get around the Harefield Marina, but joined it shortly after that at the Widewater Lock. From there we walked a few more miles on the towpath besides the canal and made it to our last lock of the day: Black Jack's Lock. From there it would be another half mile until the end of the section, but we sneaked off and climbed up the hill to The Old Orchard pub. Sections 11 and 12 were mostly along canals. I also figured out that doing the stretch from West Drayton to Harefield on foot is about as fast as by boat, especially when they have to wait for locks to be in the right position.

loop12-d36_5571.jpg

But let me get back to the pub. Unlike some of the dire pubs that we walked past in Uxbridge, The Old Orchard is actually a really nice place. Good beers and ciders, and very nice food. And the view was amazing too! Glad we stopped here, and we promised each other to finish section 12 when we do 13 and 14 on our next walk. We had to run to make our bus into Northwood, and the Metropolitan line home. The pub was worth the run though :-)

loop12-d36_5553.jpg

The weather was again very good, with 14-16°C and few light clouds. I even took my new walking shorts out! We took just under four hours for the two sections that together were 18.5km long.

The photos that I took on this section, as well as the photos of the other sections of the LOOP, are available as a Flickr set.

Shortlink

This article has a short URL available: http://drck.me/loop1112-aya

Comments

No comments yet

Life Line