Michael G Schwern wrote:

> On Tue, Jan 28, 2003 at 12:11:18PM +1300, [EMAIL PROTECTED] wrote:
> 
> > Has anyone considered removing with the syntactic distinction
> > between numeric and string indexing -- that is, between array and
> > hash lookup?
> 
> PHP works this way.

Well, for some definition of "work", anyway.

> http://www.php.net/manual/en/language.types.array.php
> 
> So that makes a nice case study to investigate.

The manual is strangely quiet on how this duality fits together, but
through using PHP I've managed to work some of it out.

Basically in PHP there are just hashes, but hashes retain the order in
which elements are stored.  When iterating with C<foreach> or C<print_r> you
get elements back in the order you put them in:

  $colour = array('grass' => 'green', 'sky' => 'blue',
        'orange' => 'orange');
  print_r($colour);
  
  # output:
  Array
  (
      [grass] => green
      [sky] => blue
      [orange] => orange
  )

If you add an element that doesn't have a key, then PHP finds the
maximum key that looks like a non-negative integer, adds one to it, and
uses that as the key for the new element, or uses zero if no elements
have such keys.

This means that if you never assign any explicit keys you can make it
seem like the hash is a 'normal' array:

  $colour = array('purple', 'black', 'silver');
  print_r($colour);

  Array
  (
    [0] => purple
    [1] => black
    [2] => silver
  )

But it isn't.  Remember that elements retain the order in which they
were stored.  So if you set them not in numerical order then they remain
in that order:

  $colour = array();
  $colour[1] = 'taupe';
  $colour[3] = 'red';
  $colour[0] = 'zephyr';
  $colour[2] = 'pink';
  print_r($colour);

  Array
  (
      [1] => taupe
      [3] => red
      [0] => zephyr
      [2] => pink
  )

And if you remove an element from the middle of an array, the existing
elements keep their previous indices, so the indices are no longer
consecutive:

  $colour = array('purple', 'black', 'silver', 'gold');
  unset($colour[2]);
  print_r($colour);

  Array
  (
      [0] => purple
      [1] => black
      [3] => gold
  )

And if you put that element back, well it doesn't go there but appears
at the end:

  $colour = array('purple', 'black', 'silver', 'gold');
  unset($colour[2]);
  $colour[2] = 'bronze';
  print_r($colour);

  Array
  (
      [0] => purple
      [1] => black
      [3] => gold
      [2] => bronze
  )

The ordering means that it's possible to shift elements off the
beginning of a hash, which is fine:

  $colour = array('grass' => 'green', 'sky' => 'blue',
        'orange' => 'orange');
  array_shift($colour);
  print_r($colour);

  Array
  (
      [sky] => blue
      [orange] => orange
  )

There's also something in there which checks for non-negative integer
keys, and if so renumbers them after shifting.  This helps keep up the
pretence that the hash can be used as an array:

  $colour = array('purple', 'black', 'silver', 'gold');
  array_shift($colour);
  print_r($colour);

  Array
  (
      [0] => black
      [1] => silver
      [2] => gold
  )

But this can have surprising consequences if you are trying to associate
numbers with particular elements:

  $days = array(1 => 'day', 7 => 'week', 14 => 'fortnight',
      365 => 'year');
  array_shift($days);
  print_r($days);

  Array
  (
      [0] => week
      [1] => fortnight
      [2] => year
  )

Zero days in a week?  And the same thing happens even if the keys are
quoted, so that they are strings that happen to look like integers but
not actual integers:

  $days = array('1' => 'day', '7' => 'week', '14' => 'fortnight',
      '365' => 'year');

Trying that on a hash where some of the keys happen to look like
integers and some don't results in the former being renumbered and the
latter being left alone.

Is that enough?

The amazing thing is that most of the time, despite the above, what PHP
calls arrays do actually work well enough.  But really PHP has hashes
with elements that retain their storage order plus some awkward hacks
that may make them seem more like arrays in certain circumstances.  It's
messy.  It's bordering on evil.

And I've never found it to have any advantage over the Perl way of
allowing the programmer to specify which data structure is required
rather than making the interpreter guess.

I cannot think of a worse example for Perl to follow.

Smylers

Reply via email to