# [RFC][VOTE] Objects as Keys

- Thread: https://externals.io/message/79700
- Original archive: https://news-web.php.net/php.internals/79700
- Started by Stanislav Malyshev on 2014-12-16T08:34:15+00:00
- Messages: 45
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/79700.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #79700 — Stanislav Malyshev — 2014-12-16T08:34:15+00:00

URL: https://externals.io/message/79700#79700

Hi!

I'd like to initiate a vote on "objects as keys" RFC:
https://wiki.php.net/rfc/objkey

I know this is a holiday season but it was extensively discussed and I
think most people already formed their opinions. I've put the voting
period as 3 weeks to have some time for people to vote even with the
holidays, etc.

The vote includes choice for the name. Vote for either name is counted
as the vote for the overall proposal, and 2/3 majority is required as
it's a language change.

Some more expanded summary of the arguments is here:
http://php100.wordpress.com/2014/12/14/objects-as-keys/ in case you're
interested.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79707 — Markus Fischer — 2014-12-16T10:31:10+00:00

URL: https://externals.io/message/79700#79707 · In reply to: #79700

> I'd like to initiate a vote on "objects as keys" RFC:
> https://wiki.php.net/rfc/objkey

Am I right this only covers the transformation into the array. Once it's
in it's essential a array compatible key entity (string/integer) so when
you var_dump($array) you only get the values of a hash.

In other words: it would not be possible to actually get the object from
the key, just this string/integer which is supposed to reference it?

thanks,
- Markus

---

## #79708 — Andrea Faulds — 2014-12-16T10:52:19+00:00

URL: https://externals.io/message/79700#79708 · In reply to: #79707

Hi Markus,

> 
> 
> 
> > […]
> 
> Am I right this only covers the transformation into the array. Once it's
> in it's essential a array compatible key entity (string/integer) so when
> you var_dump($array) you only get the values of a hash.
> 
> In other words: it would not be possible to actually get the object from
> the key, just this string/integer which is supposed to reference it?

Exactly. If I were to do this:

    <?php
    class Foo {
        public $foo;
        function __construct($foo) {
            $this->foo = $foo;
        }
        function __toKey() {
            return $this->foo;
        }
    }
    $arr = [];
    $arr[] = new Foo(1);
    var_dump($arr);

I would get this:

    array(1) {
      [0]=>
      int(1)
    }

This is the main problem with the RFC: magic, implicit, one-way data loss (object to integer/string).

I was previously in favour of this, but it’d prevent actual indexing by objects in future, and I can’t think of any use cases which aren’t better solved by explicitly converting to a string/integer.

Thanks.
--
Andrea Faulds
http://ajf.me/

---

## #79711 — Andrea Faulds — 2014-12-16T11:05:40+00:00

URL: https://externals.io/message/79700#79711 · In reply to: #79708

> 
> 
> 
> Exactly. If I were to do this:
> 
>    <?php
>    class Foo {
>        public $foo;
>        function __construct($foo) {
>            $this->foo = $foo;
>        }
>        function __toKey() {
>            return $this->foo;
>        }
>    }
>    $arr = [];
>    $arr[] = new Foo(1);
>    var_dump($arr);
> 
> I would get this:
> 
>    array(1) {
>      [0]=>
>      int(1)
>    }

Er, a correction… the example should’ve been something like this:

    $arr = [];
    $arr[new Foo(1)] = NULL;

Producing this:

    array(1) {
      [1]=>
      `NULL` 
    }

Obviously, it has no effect on values, only keys, sorry!

--
Andrea Faulds
http://ajf.me/

---

## #79717 — Guilherme Blanco — 2014-12-16T11:34:23+00:00

URL: https://externals.io/message/79700#79717 · In reply to: #79711

Hi,

All I can say is that the lack of this feature is one of the main reasons why Doctrine doesn't fully work with composite keys.
With this enhancement it would now become possible to implement a proper IdentityMap.

[]s,



> > […]
> 
> Er, a correction… the example should’ve been something like this:
> 
>    $arr = [];
>    $arr[new Foo(1)] = NULL;
> 
> Producing this:
> 
>    array(1) {
>      [1]=>
>      `NULL` 
>    }
> 
> Obviously, it has no effect on values, only keys, sorry!
> 
> --
> Andrea Faulds
> http://ajf.me/

---

## #79718 — Matteo Beccati — 2014-12-16T11:35:38+00:00

URL: https://externals.io/message/79700#79718 · In reply to: #79708

> This is the main problem with the RFC: magic, implicit, one-way data
> loss (object to integer/string).
>
> I was previously in favour of this, but it’d prevent actual indexing
> by objects in future, and I can’t think of any use cases which aren’t
> better solved by explicitly converting to a string/integer.

That's precisely the same reason why I voted Nay. And I wouldn't have 
been able to put it down in words better than Andrea did.


Cheers
-- 
Matteo Beccati

Development & Consulting - http://www.beccati.com/

---

## #79719 — Matteo Beccati — 2014-12-16T11:39:19+00:00

URL: https://externals.io/message/79700#79719 · In reply to: #79717

Hi Guilherme,


> Hi,
>
> All I can say is that the lack of this feature is one of the main reasons why Doctrine doesn't fully work with composite keys.
> With this enhancement it would now become possible to implement a proper IdentityMap.

Are you sure you haven't misinterpreted the RFC?


Cheers
-- 
Matteo Beccati

Development & Consulting - http://www.beccati.com/

---

## #79720 — Patrick Schaaf — 2014-12-16T11:46:08+00:00

URL: https://externals.io/message/79700#79720 · In reply to: #79718

Am 16.12.2014 12:36 schrieb "Matteo Beccati" <php@beccati.com>:
>
> 
> > […]
>
> That's precisely the same reason why I voted Nay. And I wouldn't have
been able to put it down in words better than Andrea did.

That was my thought initially, too. But I think it is wrong. If PHP ever
gets around to provide objects-themselves-as-array-keys support, it can
easily do that

1) only if the object does not have such a __toKey() method, or
2) if the object has one, but it returns the object itself (which is
forbidden now by the RFC)

best regards
  Patrick

---

## #79721 — Rowan Collins — 2014-12-16T12:44:07+00:00

URL: https://externals.io/message/79700#79721 · In reply to: #79720

Patrick Schaaf wrote on 16/12/2014 11:46:
> Am 16.12.2014 12:36 schrieb "Matteo Beccati" <php@beccati.com>:
> > […]
> been able to put it down in words better than Andrea did.
>
> That was my thought initially, too. But I think it is wrong. If PHP ever
> gets around to provide objects-themselves-as-array-keys support, it can
> easily do that
>
> 1) only if the object does not have such a __toKey() method, or
> 2) if the object has one, but it returns the object itself (which is
> forbidden now by the RFC)

Hm, that's an interesting thought. My thought had been that an 
object-as-key would need to specify its hash anyway, so that two objects 
of the same "value" would be automatically de-duped, just as two strings 
are. But I guess an internally unique handle for the specific object 
would also be a reasonable approach for some uses.

Perhaps like with Traversable, we could have a set of magic interfaces 
(although I'm struggling to think of names for them, which may be a bad 
sign):

a) an "abstract" base interface meaning "can be used as $bar in 
$foo[$bar]"; like Traversable, this would not actually be implementable 
directly, but be the parent of the following
b) an interface for objects which produce a one-way hash to use as the 
key (as in the current proposal)
c) an interface for objects which can themselves be stored as the key, 
with internally unique handle as identifier
d) an interface for objects which can themselves be stored as the key, 
but with a custom "value" used as the identifier

This sounds complex, but wouldn't necessarily be. (c) is just a special 
case of (d) with an implied default implementation of the value method. 
And if the structure of the HashTable retained the index/key structure 
we have now, but with the object pointer as an additional field, the 
pseudo-code when an object was encountered in array-key context would be:

if $obj has interface (a) then
.   if $obj has interface (c) then
.   .   key := get_internal_identifier($obj)
.   .   else key := $obj->getHash() // this covers (b) and (d)
.   end
.   store value against key
.   if $obj has interface (c) or (d) then store additional pointer to 
original object
else throw error
end

Importantly, the current proposal could be re-cast as an implementation 
of interface (b) while neither promising nor ruling out (c) and/or (d).

-- 
Rowan Collins
[IMSoP]

---

## #79722 — Florian Margaine — 2014-12-16T12:53:05+00:00

URL: https://externals.io/message/79700#79722 · In reply to: #79721

Hi,

Le 16 déc. 2014 13:45, "Rowan Collins" <rowan.collins@gmail.com> a écrit :
>
> Patrick Schaaf wrote on 16/12/2014 11:46:
>
> > […]
>
>
> Hm, that's an interesting thought. My thought had been that an
object-as-key would need to specify its hash anyway, so that two objects of
the same "value" would be automatically de-duped, just as two strings are.
But I guess an internally unique handle for the specific object would also
be a reasonable approach for some uses.

Just a random thought: the `__hash` method can just `return
spl_object_hash($this);` to have an object id.

> --
> Rowan Collins
> [IMSoP]
>
>
> --
> 
> 
>

Cheers,
Florian Margaine

---

## #79735 — Stanislav Malyshev — 2014-12-16T18:14:27+00:00

URL: https://externals.io/message/79700#79735 · In reply to: #79708

Hi!

> I was previously in favour of this, but it’d prevent actual indexing 

No, of course it won't - if we ever introduce indexing objects (which
probably will require rewrite of the HashTable, any takers?) it would be
very easy to index any object that does not implement __hash without any
BC problem, and convert all those implementing __hash to "return $this"
if desired.

> by objects in future, and I can’t think of any use cases which
> aren’t better solved by explicitly converting to a string/integer.

There's no implicit conversion, and explicit one is a) inacessible in
userspace for anything but string and b) annoying for the same reasons
for which __toString exists.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79739 — Rowan Collins — 2014-12-16T18:44:20+00:00

URL: https://externals.io/message/79700#79739 · In reply to: #79735

>Hi!
>
> > […]
>
>No, of course it won't - if we ever introduce indexing objects (which
>probably will require rewrite of the HashTable, any takers?) it would
>be
>very easy to index any object that does not implement __hash without
>any
>BC problem, and convert all those implementing __hash to "return $this"
>if desired.
>
> > […]
>
>There's no implicit conversion, and explicit one is a) inacessible in
>userspace for anything but string and b) annoying for the same reasons
>for which __toString exists.

Explicit conversion is trivial, just call whatever method you like. Sure, you can't write (int)$obj, but $obj->toInt() is just as expressive.

---

## #79740 — Stanislav Malyshev — 2014-12-16T18:50:06+00:00

URL: https://externals.io/message/79700#79740 · In reply to: #79739

Hi!

> Explicit conversion is trivial, just call whatever method you like.
> Sure, you can't write (int)$obj, but $obj->toInt() is just as
> expressive.

Exactly the same applies to __toString and whole ArrayAccess, yet we
still have them. Avoiding boilerplate code helps. Especially if
boilterplate code would look like:

if(is_object($foo)) {
  $foo_key = $foo->toInt();
} else {
 $foo_key = $foo;
}
$a[$foo] = 1;

Doing it each time is annoying.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79743 — Rowan Collins — 2014-12-16T20:52:09+00:00

URL: https://externals.io/message/79700#79743 · In reply to: #79740

>Hi!
>
> > […]
>
>Exactly the same applies to __toString and whole ArrayAccess, yet we
>still have them. Avoiding boilerplate code helps. Especially if
>boilterplate code would look like:
>
>if(is_object($foo)) {
>  $foo_key = $foo->toInt();
>} else {
> $foo_key = $foo;
>}
>$a[$foo] = 1;
>
>Doing it each time is annoying.

I was just confused by your statement that "explicit conversion is inacessible from userspace". But yeah, I guess with string keys you can just write $a[(string)$foo] and assume/hope it will do something meaningful whatever the type of $foo.

---

## #79760 — guilhermeblanco@gmail.com — 2014-12-17T00:48:52+00:00

URL: https://externals.io/message/79700#79760 · In reply to: #79743

> On Tue, Dec 16, 2014 at 9:39 AM, Matteo Beccati <php@beccati.com>
wrote:Hi Guilherme,
>
> > […]
reasons why Doctrine doesn't fully work with composite keys.
> > […]
IdentityMap.
 >
>Are you sure you haven't misinterpreted the RFC?

Hi Matteo,

I did not. You may think I mentioned IdentityMap as entity map, but I'm
talking about entityPersister mapping or resultPointers consumptions that
happens inside Doctrine throughout the execution. Entity IdentityMap is
enough to use purely `spl_object_hash()`. We should focus on the main goal
here, which is complex structures as keys.

As a very complex library developer I do see lots of use cases for this.

[]s,


On Tue, Dec 16, 2014 at 6:52 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:
>
> On 16 December 2014 18:50:06 GMT, Stanislav Malyshev <smalyshev@gmail.com>
> wrote:
> > […]
>
> I was just confused by your statement that "explicit conversion is
> inacessible from userspace". But yeah, I guess with string keys you can
> just write $a[(string)$foo] and assume/hope it will do something meaningful
> whatever the type of $foo.
>
>
>
> --
> 
> 
>
>

-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79761 — Christoph Becker — 2014-12-17T01:28:02+00:00

URL: https://externals.io/message/79700#79761 · In reply to: #79760

guilhermeblanco@gmail.com wrote:

> On Tue, Dec 16, 2014 at 9:39 AM, Matteo Beccati <php@beccati.com>
> wrote:
>
> > […]
> 
> I did not. You may think I mentioned IdentityMap as entity map, but I'm
> talking about entityPersister mapping or resultPointers consumptions that
> happens inside Doctrine throughout the execution. Entity IdentityMap is
> enough to use purely `spl_object_hash()`. We should focus on the main goal
> here, which is complex structures as keys.
> 
> As a very complex library developer I do see lots of use cases for this.

AIUI, this RFC is meant to introduce some sugar only.  Wouldn't it be
possible to have object hashes without __hash(), by introducing a
respective interface (maybe "Hashable" or "Identifiable") and requiring
the appropriate classes to implement this interface?

-- 
Christoph M. Becker

---

## #79762 — Stanislav Malyshev — 2014-12-17T01:32:09+00:00

URL: https://externals.io/message/79700#79762 · In reply to: #79761

Hi!

> AIUI, this RFC is meant to introduce some sugar only.  Wouldn't it be

I'm not sure what you mean by "some sugar only". It introduces the
capability of using objects in array key context, which was not
available until now.

> possible to have object hashes without __hash(), by introducing a
> respective interface (maybe "Hashable" or "Identifiable") and requiring
> the appropriate classes to implement this interface?

It's possible and essentially the same, replacing magic method (which is
how things were done in PHP since forever until now) with interface -
which probably would be slower to check, would still require dedicated
method name, probably starting with __, and will essentially do the same.

-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79763 — Andrea Faulds — 2014-12-17T01:52:20+00:00

URL: https://externals.io/message/79700#79763 · In reply to: #79762

Hi Stas,

> 
> 
> Hi!
> 
> > […]
> 
> I'm not sure what you mean by "some sugar only". It introduces the
> capability of using objects in array key context, which was not
> available until now.

That’s not true: the RFC doesn’t allow objects to be keys, it just adds implicit conversion. This is just sugar for an explicit conversion to int or string.

--
Andrea Faulds
http://ajf.me/

---

## #79764 — Christoph Becker — 2014-12-17T01:53:42+00:00

URL: https://externals.io/message/79700#79764 · In reply to: #79762

Stanislav Malyshev wrote:

> > […]
> 
> I'm not sure what you mean by "some sugar only". It introduces the
> capability of using objects in array key context, which was not
> available until now.

Yes, but it is already possible to call an object's method in array key
context, so in combination with an appropriate interface the same can be
accomplished.

> > […]
> 
> It's possible and essentially the same, replacing magic method (which is
> how things were done in PHP since forever until now) with interface -
> which probably would be slower to check, would still require dedicated
> method name, probably starting with __, and will essentially do the same.

I didn't mean to argue against the RFC, but merely wanted to point out
that one could have object hashes without the proposed magic method
(albeit in a more contrived way).

Frankly, I don't understand Guilherme's claim:

| With this enhancement it would now become possible to implement a
| proper IdentityMap.

It seems to me that is already possible since PHP 5.0.0.  I may be
missing an important detail, though.

BTW: as a userland developer I would not have called the dedicated
method __X, because __* is reserved for PHP's internal usage, AIUI.

-- 
Christoph M. Becker

---

## #79765 — Stanislav Malyshev — 2014-12-17T02:04:21+00:00

URL: https://externals.io/message/79700#79765 · In reply to: #79763

Hi!

> > […]
> 
> That’s not true: the RFC doesn’t allow objects to be keys,

And reading what I actually wrote would reveal that I did not write
"allow objects to be keys", I wrote "using objects in array key
context", and this is of course true. Please do read what you calling
"not true" before doing it. I explained it numerous times, I even wrote
a special blog post explaining it, I referenced it here, but it as if
nobody is actually reading anything before repeating the same arguments.

> it just adds implicit conversion. This is just sugar for an explicit
> conversion to int or string.

And this is completely false. While the result of the function must be
int or string, saying any function that returns int or string is "just
sugar for an explicit conversion to int or string" is false. This
function has its separate purpose which does not equal converting to any
specific type, but is suited for its unique context. You _can_ have it
return the same result as (int) or (string) but you don't have to.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79766 — Stanislav Malyshev — 2014-12-17T02:14:10+00:00

URL: https://externals.io/message/79700#79766 · In reply to: #79764

Hi!

> Yes, but it is already possible to call an object's method in array key
> context, so in combination with an appropriate interface the same can be
> accomplished.

No, it's not possible. It is possible to call object method in an
expression, and then use the result of the expression as an array key.
But to do that you'd have to check that you're dealing with the object
and the call the special method.
Looks like you don't understand why PHP has magic methods - since your
argument applies to every one of them. Why have __toString if you can
just call object method? Why have __call if you could just check if
method exists and call a special method if it doesn't? Why have __isset
if you could just call special method on an object and pass it the
property name? Of course, it's "just sugar". All programming languages
are "just sugar" by that definition.

> I didn't mean to argue against the RFC, but merely wanted to point out
> that one could have object hashes without the proposed magic method
> (albeit in a more contrived way).

You could have *everything* in a more contrived way. PHP 2 was Turing
complete, I am sure. Were we just wasting time these last 15 or so years
because everything was done in PHP since then was already possible,
albeit "in a more contrived way"? Or maybe there's some value in making
the ways significantly less contrived? IMO, that's the whole point of
what we're doing here.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #79772 — Rowan Collins — 2014-12-17T11:19:19+00:00

URL: https://externals.io/message/79700#79772 · In reply to: #79766

Stanislav Malyshev wrote on 17/12/2014 02:14:
> No, it's not possible. It is possible to call object method in an
> expression, and then use the result of the expression as an array key.
> But to do that you'd have to check that you're dealing with the object
> and the call the special method.

I think what Christoph was getting at is that you could implement an 
object map pretty simply by requiring the objects being added to 
implement a particular interface, as in:

...
function add ( Hashable $obj ) {
     $this->data[ $obj->getHash() ] = $obj;
}
...

The main thing that the current RFC would simplify is being able to 
accept a mixture of objects and scalars without performing an extra 
check; currently, you'd have to write something like this:

...
function add ( $scalar_or_obj ) {
     if ( is_scalar($scalar_or_obj) ) {
         $this->data[ $scalar_or_obj ] = $scalar_or_obj;
     } elseif ( $scalar_or_obj instanceOf Hashable ) {
         $this->data[ $obj->getHash() ] = $obj;
     } else {
         throw new InvalidArgumentException;
     }
}
...

Which is certainly uglier, any maybe was the case that Guilherme had in 
mind, but it's not like you have to build a whole new type of data 
structure, just add a few lines of implementation.

Compare that to trying to store the actual objects as keys, which would 
require a lot more than a few lines of code to emulate in pure PHP. 
Luckily, we have SplObjectStorage, which maybe makes that rather less 
urgent as well.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #79773 — Derick Rethans — 2014-12-17T12:04:30+00:00

URL: https://externals.io/message/79700#79773 · In reply to: #79700

> I'd like to initiate a vote on "objects as keys" RFC:
> https://wiki.php.net/rfc/objkey

I wonder why you opened voting on this, before resolving the "Open 
Issues":

Open Issues

    Should SplFixedArray support object indexes?
    Should SplObjectStorage support calling __hash for an object if it exists?

cheers,
Derick

---

## #79775 — guilhermeblanco@gmail.com — 2014-12-17T12:43:04+00:00

URL: https://externals.io/message/79700#79775 · In reply to: #79773

Hi,

Answering the question of Christopher Becker. It is not possible to
traverse and get your desired elements.
How would you achieve a foreach by key (returning object) without having to
store a separate list and track by hash or through an interface?

Cheers,


>
> 
>
> > […]
>
> I wonder why you opened voting on this, before resolving the "Open
> Issues":
>
> Open Issues
>
>     Should SplFixedArray support object indexes?
>     Should SplObjectStorage support calling __hash for an object if it
> exists?
>
> cheers,
> Derick
>
> --
> 
> 
>
>

-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79776 — Christoph Becker — 2014-12-17T13:07:46+00:00

URL: https://externals.io/message/79700#79776 · In reply to: #79775

guilhermeblanco@gmail.com wrote:

> Answering the question of Christopher Becker. It is not possible to
> traverse and get your desired elements.
> How would you achieve a foreach by key (returning object) without having to
> store a separate list and track by hash or through an interface?

AIUI, the RFC proposes that __hash() returns a string or an int, and
this value (not the object itself) will be stored and retrieved as key
of the array.

<https://wiki.php.net/rfc/objkey#proposal>:

| Create a new magic method, __hash() which is called when object is
| supplied as a hash key, and returns string or integer that is used as
| the hash key.

-- 
Christoph M. Becker

---

Next page: https://externals.io/message/79700.md?page=2
