Request for Comments: Autoboxing
- Version: 1.0
- Date: 2010-05-04
- Author: Moriyoshi Koizumi moriyoshi@php.net
- Status: Inactive
- First Published at: http://wiki.php.net/rfc/autoboxing
Introduction
Autoboxing is a language feature that enables just-in-time conversion of a value object to another kind that is suitable to the context where it happens. In general, the source object is of a primitive data type like int or string, and the destination is an instance of a value class.
Why do we find it useful in PHP?
In PHP, unlike other scripting languages, there are fundamental differences between primitive types and classes. While they may contribute to a substantial boost of overall runtime performance, the differences prevent primitive values from having methods to operate with. For example, PHP has many functions named array_xxx() that operate on an array to produce a result in an immutable manner (i.e. don't modify the original data to store the result). They often look pretty much unintuitive when the operations are chained, because they don't allow one to write those operations in the order they occur, but to write them in a nested function calls where the innermost function gets called first. With autoboxing, you should be able to write such a chain like the following:
<?php $sum = $arr->keys()->sum(); // with autoboxing $sum = array_sum(array_keys($arr)); // without autoboxing ?>
Proposal
There would be a special function named __autobox()
that would be called whenever primitive types are used in a context where an object should occur, and expected to return an wrapper object that represents the value passed to it if the conversion is feasible, or null if not.
<?php function __autobox($value) { return ... /* some object */ } ?>
To enable autoboxing on integer values, one could write:
<?php class IntObject { private $value; function __construct($value) { $this->value = $value; } function upTo($upper_bound) { return range($this->value, $upper_bound); } } function __autobox($value) { if (is_int($value)) { return new IntObject($value); } return null; } // Test code $val = 1; var_dump($val->upTo(10) == array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); ?>
To take advantage of this autoboxing feature, I also propose a modification to the language syntax that enables arbitrary values to come to the left-hand side of arrow operators (->
). With such a modification, one could write the above test code as follows.
<?php // Test code var_dump(1->upTo(10) == array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); ?>
You may find it interesting that it would also allow you to write an arrow operator right after a new operator and parenthesized parameters.
<?php new Foo()->bar()->baz(); ?>
Discussions
Conflicts between libraries that utilizes this feature
I fear that a lot of people will (have) to come up with their own string libraries, int libraries etc. which will have (subtle) differences. Guess you code for two projects, one using the autbox library X and one library Y. Would you always remember which methods you're allowed to call on an int, or the order of parameters, especially when there are many methods which have a similar name?
It looks like a very interesting idea. However, I believe that we should learn from the __autoload experience: It does not cope well with multiple projects. I'd rather have register_autoboxer($callback) or even register_autoboxer(“type”, $callback); for instance, so that many projects could have their own autoboxer.
In general I would agree that allowing multiple instances of __auto* is a good thing, but with __autoload you are loading class names that have far more diversity than basic types. If my code relies on int being boxed with MyInt, but I use a library that wants to box it as ProjectInt we could have some very odd results that would appear to be very magical. Confining it to a namespace sounds like a potentially better solution to me than a global registry.
Possible fix
- Per-namespace autoboxing rules (like extension methods in C#) -- The idea is to allow namespaces to have each
__autobox()
magic method and limiting the scope where it takes effect to the namespace in which it is declared or used throughuse
statement.
Relation to the existing PECL libraries
Is there any reason why primitives couldn't be autoboxed to SplInt, SplBool, etc.1)? These classes could maybe even be extended with method aliases to the relevant functions in PHP's library.
I liken this to pecl/runkit. “For all those things you.... probably shouldn't have been doing anyway”. It will create a world where scripts are not portable. And if you need that for your internal project, that is fine. But, having this as part of the PHP core would be a disaster. This is even more heinous than __autoload(), IMO. SPL fixed this for autoload. I would support an SPL extenstion to treat primitive types as SPL objects. They are standardized. Not random.
Efficiency
I am afraid, this magic method will make php slower even if scripts don't use this future (at least the patch disables code specialization for ZEND_INIT_METHOD_CALL) and make some future type propagation optimizations non-applicable.
Magic functions considered harmful
Introducing new magic function may bring a lot of troubles and open a new door for exploit writer (we already have problems with __toString() method2)).
Context information to the callback
Should'nt any autobox callback should not only recieve the value to be autoboxed, but also the context information? I.e. the method name to be called on the variable? otherwise you cannot decide between different behaviours.
Exception on infeasible conversion
It could throw an exception.
Patch
A preliminary patch (may be a bit outdated) is available at http://gist.github.com/162517 .
Discussion on the List
- 2005-02-09 : Similar discussion back in 2005
- 2010-05-03 : Initial discussion about this RFC
Changelog
2010-05-04: initial version