at 2007-04-29
in Examples
by friebe
(0 comments)
With RFC #0106 implemented, the collection API now offers generics support.
What are generics? To best explain what generics are let's start with a non-generic example of a container class:
<?php class Container extends Object { public $elements= array(); public function add(Generic $o) { $this->elements[]= $o; } } ?> The Container's add() method accepts any value, regardless of its class. Imagine we were using this container to store - say - integers, and suddenly someone was adding a string to this container:
<?php $container= new Container(); $container->add(new Integer(5)); $container->add(new Integer(1)); $container->add(new String('Hello')); foreach ($container->elements() as $number) { Console::writeLine($number->intValue()); } ?> When the iteration reaches the offset containing the string object, the program will die with a fatal error, because the string class does not provide an intValue() method.
Continue reading to see how generics can help you in these situations!Solution Basically, what we want is that to prevent errors from happening by failing fast - that is, at the point someone tries to insert something into our container that we do not want to allow.
This could be done by creating a subclass called IntegerContainer and then checking on Integers in the add() method. But you can see where this will lead: An endless soup of XXXContainer classes, one for every situation we need a container of XXX objects.
We could also give the container class a constructor accepting a type name in its constructor, e.g.: $container= new Container('Integer');. This has the obvious downside that it might be hard to refactor old - non-generic classes to accept generics.
This is where generics come to help you. With generics, we can create a "container of whatever" by using a special syntax, $container= create('Container<lang.types.Integer>');. Read this as "Create a Container of Integers".
We now change the Container class as follows:
<?php class Container extends Object { public $elements= array(); public $__generic= array(); public function add(Generic $o) { if ($this->__generic && !$o instanceof $this->__generic[0]) { throw new IllegalArgumentException( 'Argument '.xp::stringOf($o).' must be of '.$this->__generic[0] ); } $this->elements[]= $o; } } ?> ...and then revisit the sourcecode example from above, we will see the following behaviour: $container= create('new Container<lang.types.Integer>'); $container->add(new Integer(5)); // Works $container->add(new Integer(1)); // - " - $container->add(new String('Hello')); // Throws an IllegalArgumentException! Classes in the XP framework supporting generics All the classes from the util.collections package support generics:
- HashTable
A map of keys and values. $hash= create('new HashTable<String, Object>');
- HashSet
A set (unique list) of objects. $set= create('new HashSet<XPClass>');
- Vector
A resizable list of objects. $list= create('new Vector<peer.URL>');
- Queue
A First-In-First-Out (FIFO) queue of objects. $queue= create('new Queue<de.thekid.messaging.Message>');
- Stack
A Last-In-First-Out (LIFO) stack of objects. $stack= create('new Stack<lang.reflect.Argument>');
- LRUBuffer
LRU (last recently used) buffer $lru= create('new LRUBuffer<Contract>');
Comparing generics in the XP framework to Java / C# The first and most noticeable difference is the syntax they are declared and used in. While in Java and C#, the language itself supports generics, the XP framework needs to simulate them on top of PHP5. Because the XP framework is written purely in PHP and because userland PHP cannot modify the language grammar nor the way the engine works, the syntax is a bit kludgy. Java/C# syntax is as follows: class Container<T> { // ... public void add(T t) { // ... } }
Container<Integer> c= new Container<Integer>(); The second most obvious difference is that in the XP framework, all type checks occur at runtime, whereas Java and C# catch type errors when compiling: $c->add(new String('Hello')); // XP: Throws an IllegalArgumentException! c.add(new String("Hello")); // Java/C#: Compile-Time error! Further reading RFC #0106 contains more information about how generics work in the XP framework. An introduction into Java generics is availabe here, and for C# they're explained over at MSDN.
|
Subscribe
You can subscribe to the XP framework's news by using RSS syndication.
CategoriesNews General PHP5 Announcements RFCs Further reading Examples Editorial EASC Experiments Unittests Databases
RelatedFind related articles by a search for «Introducing».
|