PHP lacks two very basic functions for working with arrays:
- array_first() returning the first element of an array (or null)
- array_last() returning the last element of the array (or null)
While PHP has functions that return the first and last keys,
array_key_first()
and array_key_last()
, it does not have more useful
functions for values.
a) What about reset()
and end()
?
Programmers "abuse" the reset()
and end()
functions for this purpose.
The problem is that these functions are used to move the internal
pointer in the array. Which is why they have a name that is
inappropriate when used in the sense of "return me the first element".
Much worse, they shouldn't to be used to get first/last value, because
they have a side effect (i.e. moving the pointer).
Further, in the absence of an element, they return the obsolete false
and not the currently expected null, which can be combined with the ??
operator. In this they differ from the similar functions
array_key_first()
and array_key_last()
.
b) What about $array[array_key_first($array)]?
For such basic functions as returning the first and last item in an
array, there should be a function in the basic package, not a
workaround. Moreover, this requires having the array in a local
variable, since $this->getFoo()[array_key_first($this->getFoo())]
would be very inefficient and possibly incorrect.
c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)
Yes, that was in 2018. At that time, functions like str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.
DG
PHP lacks two very basic functions for working with arrays:
- array_first() returning the first element of an array (or null)
- array_last() returning the last element of the array (or null)
While PHP has functions that return the first and last keys,
array_key_first()
andarray_key_last()
, it does not have more useful
functions for values.a) What about
reset()
andend()
?
Programmers "abuse" thereset()
andend()
functions for this purpose.
The problem is that these functions are used to move the internal
pointer in the array. Which is why they have a name that is
inappropriate when used in the sense of "return me the first element".Much worse, they shouldn't to be used to get first/last value, because
they have a side effect (i.e. moving the pointer).Further, in the absence of an element, they return the obsolete false
and not the currently expected null, which can be combined with the ??
operator. In this they differ from the similar functions
array_key_first()
andarray_key_last()
.b) What about $array[array_key_first($array)]?
For such basic functions as returning the first and last item in an
array, there should be a function in the basic package, not a
workaround. Moreover, this requires having the array in a local
variable, since $this->getFoo()[array_key_first($this->getFoo())]
would be very inefficient and possibly incorrect.c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.DG
I'm in favor of adding these.
To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in.
So basically you have the choice between calling end()
, which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty.
Regards,
Nikita
On Sat, Oct 14, 2023, at 20:00, David Grudl wrote:
PHP lacks two very basic functions for working with arrays:
- array_first() returning the first element of an array (or null)
- array_last() returning the last element of the array (or null)
While PHP has functions that return the first and last keys,
array_key_first()
andarray_key_last()
, it does not have more useful
functions for values.a) What about
reset()
andend()
?
Programmers "abuse" thereset()
andend()
functions for this purpose.
The problem is that these functions are used to move the internal
pointer in the array. Which is why they have a name that is
inappropriate when used in the sense of "return me the first element".Much worse, they shouldn't to be used to get first/last value, because
they have a side effect (i.e. moving the pointer).Further, in the absence of an element, they return the obsolete false
and not the currently expected null, which can be combined with the ??
operator. In this they differ from the similar functions
array_key_first()
andarray_key_last()
.b) What about $array[array_key_first($array)]?
For such basic functions as returning the first and last item in an
array, there should be a function in the basic package, not a
workaround. Moreover, this requires having the array in a local
variable, since $this->getFoo()[array_key_first($this->getFoo())]
would be very inefficient and possibly incorrect.c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.DG
I'm in favor of adding these.
To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in.
So basically you have the choice between calling
end()
, which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty.Regards,
Nikita
I’m in favor of these functions, for all the same aforementioned reasons.
Cheers,
Ben
Le 15/10/2023 à 01:11, Ben Ramsey a écrit :
On Sat, Oct 14, 2023, at 20:00, David Grudl wrote:
PHP lacks two very basic functions for working with arrays:
- array_first() returning the first element of an array (or null)
- array_last() returning the last element of the array (or null)
While PHP has functions that return the first and last keys,
array_key_first()
andarray_key_last()
, it does not have more useful
functions for values.a) What about
reset()
andend()
?
Programmers "abuse" thereset()
andend()
functions for this purpose.
The problem is that these functions are used to move the internal
pointer in the array. Which is why they have a name that is
inappropriate when used in the sense of "return me the first element".Much worse, they shouldn't to be used to get first/last value, because
they have a side effect (i.e. moving the pointer).Further, in the absence of an element, they return the obsolete false
and not the currently expected null, which can be combined with the ??
operator. In this they differ from the similar functions
array_key_first()
andarray_key_last()
.b) What about $array[array_key_first($array)]?
For such basic functions as returning the first and last item in an
array, there should be a function in the basic package, not a
workaround. Moreover, this requires having the array in a local
variable, since $this->getFoo()[array_key_first($this->getFoo())]
would be very inefficient and possibly incorrect.c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.DG
I'm in favor of adding these.To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in.
So basically you have the choice between calling
end()
, which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty.Regards,
Nikita
I’m in favor of these functions, for all the same aforementioned reasons.
Yes please !
array_first() and array_last() are definitely needed. I wrote foreach ($foo as $value) break;
too many times in my life. array_key_first()
and array_key_last()
I wouldn't use it much, but they'd probably find
their use cases as well.
The first two probably only make sense for a numerically indexed array,
so I guess that array_is_list() (whatever the name is, I don't want to
bikeshed about naming) would be a good addition as well, that, in my
opinion, would be pertinent to add at the same time.
Regards,
Pierre
The first two probably only make sense for a numerically indexed array,
so I guess that array_is_list() (whatever the name is, I don't want to
bikeshed about naming) would be a good addition as well, that, in my
opinion, would be pertinent to add at the same time.
That has already been done: https://www.php.net/array_is_list
--Larry Garfield
Le 15/10/2023 à 18:09, Larry Garfield a écrit :
That has already been done:https://www.php.net/array_is_list
--Larry Garfield
Oh, I forgot it was accepted and merged, thanks for pointing at it.
Cheers,
Pierre
Hi Pierre
The first two probably only make sense for a numerically indexed array
I do not think so. If these are something like "reset/end without side effects", then they should work fine even not numeric indexed array.
Regards.
Saki
Hi, David
Many times I've seen reset()
used to meet this requirement.
I support this, not only from a side effect standpoint, but also from a readability standpoint. I would also like to add the opinion that it is better because it is simpler than the function name in the original RFC that is being referenced.
Best regards.
Saki
I came up with the idea of using a signature like array_filter()
, and when a callback is passed, "return the first/last element that matches the condition" and "return null if there is no match."
The downside to this idea is the loss of simplicity. So I'll leave it up to you whether you want to go with this idea or not. I have no intention of forcing this.
Best regards.
Saki
I came up with the idea of using a signature like
array_filter()
, and
when a callback is passed, "return the first/last element that matches the
condition" and "return null if there is no match."The downside to this idea is the loss of simplicity. So I'll leave it up
to you whether you want to go with this idea or not. I have no intention of
forcing this.Best regards.
I'm in favor of these functions.
Right now I am doing:
$firstItem = current($array)
$secondItem = next($array)
Which is simple and works, but really it's just by design that the code
hasn't shifted the array pointer yet and I can cheat with current()
If the pointer was shifted then I'd have to do reset()
, which isn't good.
array_first() for the win
Many thanks,
Paul
Saki
To unsubscribe, visit: https://www.php.net/unsub.php
Hi
I came up with the idea of using a signature like
array_filter()
, and when a callback is passed, "return the first/last element that matches the condition" and "return null if there is no match."
This would be 'array_find()' and I would be in favor of it, with the
caveat that I would want it to work with arbitrary iterables.
See this previous thread regarding that topic:
https://externals.io/message/118896#118896
Best regards
Tim Düsterhus
PHP lacks two very basic functions for working with arrays:
- array_first() returning the first element of an array (or null)
- array_last() returning the last element of the array (or null)
While PHP has functions that return the first and last keys,
array_key_first()
andarray_key_last()
, it does not have more useful
functions for values.a) What about
reset()
andend()
?
Programmers "abuse" thereset()
andend()
functions for this purpose.
The problem is that these functions are used to move the internal
pointer in the array. Which is why they have a name that is
inappropriate when used in the sense of "return me the first element".Much worse, they shouldn't to be used to get first/last value, because
they have a side effect (i.e. moving the pointer).Further, in the absence of an element, they return the obsolete false
and not the currently expected null, which can be combined with the ??
operator. In this they differ from the similar functions
array_key_first()
andarray_key_last()
.b) What about $array[array_key_first($array)]?
For such basic functions as returning the first and last item in an
array, there should be a function in the basic package, not a
workaround. Moreover, this requires having the array in a local
variable, since $this->getFoo()[array_key_first($this->getFoo())]
would be very inefficient and possibly incorrect.c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.DG
I would love to have these functions in PHP as well.
With the bikeshed risk, perhaps it makes more sense to have the
functions named array_value_first
and array_value_last
, because we
already have array_key_first
and array_key_last
functions?
c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.
It's true that sentiment may have shifted in this time. However, a
common argument at that time still stands: null
is not a good
sentintenal for failure because the value inside the array very well
could have been null. This is not true for the keys. For me
personally, I think I would still vote no. I'm not entirely sure about
that, but that's how I would lean right now.
As it stands, you'd have to write code along the lines of:
$key = \array_key_first($array);
if ($key === null) {
// handle the failure
} else {
// success
$value = $array[$key];
}
Yes, it would be slightly nicer if we could do:
$value = \array_first($array);
if ($value === null) {
// handle the failure
} else {
// success
}
But I fear in practice people will just omit the error checking.
One way around that is to throw an exception. I'm not sure how I feel
about that, but I'll think about it.
On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals
internals@lists.php.net wrote:
c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.It's true that sentiment may have shifted in this time. However, a
common argument at that time still stands:null
is not a good
sentintenal for failure because the value inside the array very well
could have been null. This is not true for the keys. For me
personally, I think I would still vote no. I'm not entirely sure about
that, but that's how I would lean right now.As it stands, you'd have to write code along the lines of:
$key = \array_key_first($array); if ($key === null) { // handle the failure } else { // success $value = $array[$key]; }
Yes, it would be slightly nicer if we could do:
$value = \array_first($array); if ($value === null) { // handle the failure } else { // success }
But I fear in practice people will just omit the error checking.
One way around that is to throw an exception. I'm not sure how I feel
about that, but I'll think about it.--
To unsubscribe, visit: https://www.php.net/unsub.php
How is returning null any different than $array[0] on an empty array?
https://3v4l.org/K3gRs
Currently, it just outputs a warning, but the result is null
.
On Tue, Oct 17, 2023 at 11:15 AM Robert Landers landers.robert@gmail.com
wrote:
On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals
internals@lists.php.net wrote:How is returning null any different than $array[0] on an empty array?
https://3v4l.org/ https://3v4l.org/K3gRs>
c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.It's true that sentiment may have shifted in this time. However, a
common argument at that time still stands:null
is not a good
sentintenal for failure because the value inside the array very well
could have been null. This is not true for the keys. For me
personally, I think I would still vote no. I'm not entirely sure about
that, but that's how I would lean right now.As it stands, you'd have to write code along the lines of:
$key = \array_key_first($array); if ($key === null) { // handle the failure } else { // success $value = $array[$key]; }
Yes, it would be slightly nicer if we could do:
$value = \array_first($array); if ($value === null) { // handle the failure } else { // success }
But I fear in practice people will just omit the error checking.
One way around that is to throw an exception. I'm not sure how I feel
about that, but I'll think about it.--
To unsubscribe, visit: https://www.php.net/unsub.php
K3gRs https://3v4l.org/K3gRs
Currently, it just outputs a warning, but the result is
null
.--
To unsubscribe, visit: https://www.php.net/unsub.php
I'm okay with null
being given back as it's the current behavior of
accessing the key as well, which is often checked through $array[0] ?? null
. Something like an undefined
type could solve this problem, but
personally not a fan of this in Javascript. Maybe array_has_first
or
something could be made, but honestly I would still just check for null
myself most likely.
On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals
internals@lists.php.net wrote:How is returning null any different than $array[0] on an empty array?
https://3v4l.org/>c) Two such functions were proposed and rejected during the
array_key_first/last RFC
(https://wiki.php.net/rfc/array_key_first_last)Yes, that was in 2018. At that time, functions like
str_contains()
or
str_starts_with()
wouldn't have even come into existence, just because
there was an obscure way to do it without them. I believe we've moved
on since then. Today we know how useful it is to use simple,
easy-to-understand methods, both for programmers who write and read
the code.It's true that sentiment may have shifted in this time. However, a
common argument at that time still stands:null
is not a good
sentintenal for failure because the value inside the array very well
could have been null. This is not true for the keys. For me
personally, I think I would still vote no. I'm not entirely sure about
that, but that's how I would lean right now.As it stands, you'd have to write code along the lines of:
$key = \array_key_first($array); if ($key === null) { // handle the failure } else { // success $value = $array[$key]; }
Yes, it would be slightly nicer if we could do:
$value = \array_first($array); if ($value === null) { // handle the failure } else { // success }
But I fear in practice people will just omit the error checking.
One way around that is to throw an exception. I'm not sure how I feel
about that, but I'll think about it.--
To unsubscribe, visit: https://www.php.net/unsub.php
K3gRs
Currently, it just outputs a warning, but the result is
null
.--
To unsubscribe, visit: https://www.php.net/unsub.php
I'm okay with
null
being given back as it's the current behavior of accessing the key as well, which is often checked through$array[0] ?? null
. Something like anundefined
type could solve this problem, but personally not a fan of this in Javascript. Maybearray_has_first
or something could be made, but honestly I would still just check fornull
myself most likely.
Huh, that's a good observation Lynn. If I might suggest an API change
to array_value_first
(and a similar one for array_value_last), it
would be this: array_value_first(array $array, string|int|null &$key = null): mixed
where you also get back the key. If you want to know
if null is an error or an actual value:
$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $value
You can also freely ignore the key, if you don't need it or care about
error checking. That would save doing two function calls on the same
array, just to do some error checking.
$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $valueYou can also freely ignore the key, if you don't need it or care about
error checking. That would save doing two function calls on the same
array, just to do some error checking.
Please, no. What's wrong with count()
or empty()?
+1 for array_first() and array_last(). The only problem is probably a
big BC break. I myself have array_first() defined in my framework.
--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]
PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $valueYou can also freely ignore the key, if you don't need it or care about
error checking. That would save doing two function calls on the same
array, just to do some error checking.Please, no. What's wrong with
count()
or empty()?+1 for array_first() and array_last(). The only problem is probably a
big BC break. I myself have array_first() defined in my framework.--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hey Aleksander,
Please, no. What's wrong with
count()
or empty()?
Nothing. Why not either one? You don't have to use the $key variable
and you can use count()
or empty(), but for me personally, it makes a
lot of sense.
On Tue, Oct 17, 2023 at 11:37 AM Robert Landers
landers.robert@gmail.com wrote:
$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $valueYou can also freely ignore the key, if you don't need it or care about
error checking. That would save doing two function calls on the same
array, just to do some error checking.Please, no. What's wrong with
count()
or empty()?+1 for array_first() and array_last(). The only problem is probably a
big BC break. I myself have array_first() defined in my framework.--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hey Aleksander,
Please, no. What's wrong with
count()
or empty()?Nothing. Why not either one? You don't have to use the $key variable
and you can usecount()
or empty(), but for me personally, it makes a
lot of sense.
Ah, I just realized why it makes a lot of sense, and that is when
Fibers get involved. The value and key could change underneath you
from one function call to another.
$key = array_key_first($this-array);
// call something that suspends a fiber and results in $this->array
being mutated
$value = array_value_first($this->array);
// $value and $key may now point to two totally separate things.
I've been bitten by this with Fibers a few times now (or things very
similar to it).
Having a way to atomically get $key and $value would be a boon, not a hindrance.
Robert Landers
Software Engineer
Utrecht NL
Having array_value_first and array_value_last to match the existing
array_key_first and array_key_last functions make sense, and would seem to
me to be more intuitive than function names that would not match that
scheme.
On Tue, 17 Oct 2023 at 10:41, Robert Landers landers.robert@gmail.com
wrote:
On Tue, Oct 17, 2023 at 11:37 AM Robert Landers
landers.robert@gmail.com wrote:On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak alec@alec.pl
wrote:$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $valueYou can also freely ignore the key, if you don't need it or care
about
error checking. That would save doing two function calls on the same
array, just to do some error checking.Please, no. What's wrong with
count()
or empty()?+1 for array_first() and array_last(). The only problem is probably a
big BC break. I myself have array_first() defined in my framework.--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hey Aleksander,
Please, no. What's wrong with
count()
or empty()?Nothing. Why not either one? You don't have to use the $key variable
and you can usecount()
or empty(), but for me personally, it makes a
lot of sense.Ah, I just realized why it makes a lot of sense, and that is when
Fibers get involved. The value and key could change underneath you
from one function call to another.$key = array_key_first($this-array);
// call something that suspends a fiber and results in $this->array
being mutated$value = array_value_first($this->array);
// $value and $key may now point to two totally separate things.
I've been bitten by this with Fibers a few times now (or things very
similar to it).Having a way to atomically get $key and $value would be a boon, not a
hindrance.Robert Landers
Software Engineer
Utrecht NL--
To unsubscribe, visit: https://www.php.net/unsub.php
Having array_value_first and array_value_last to match the existing
array_key_first and array_key_last functions make sense, and would seem to
me to be more intuitive than function names that would not match that
scheme.
Please don't make things more complicated than they should be. Functions
names should be short and memorable and array_first() and array_last()
are perfect. No need for array_value_first() and array_value_last() just
for the sake of matching with array_key_first()
and array_key_last()
functions.
Furthermore, returning NULL
if the array contains no element is all we
need in daily life because most often it doesn't matter if the array is
empty or the first value is a NULL
value. If it does, checking the array
with empty() or using array_filter()
is enough. No exceptions, warnings
and notices please!
Always think of how you would use the functions in your own projects to
write short and elegant code, not about all the special cases that
should be handled separately.
Best,
Norbert
On Tue, 17 Oct 2023 at 10:41, Robert Landers landers.robert@gmail.com
wrote:On Tue, Oct 17, 2023 at 11:37 AM Robert Landers
landers.robert@gmail.com wrote:On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak alec@alec.pl
wrote:$value = array_value_first($array, $key);
if($key === null) // handle error
else // do something with $valueYou can also freely ignore the key, if you don't need it or care
about
error checking. That would save doing two function calls on the same
array, just to do some error checking.Please, no. What's wrong with
count()
or empty()?+1 for array_first() and array_last(). The only problem is probably a
big BC break. I myself have array_first() defined in my framework.--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hey Aleksander,
Please, no. What's wrong with
count()
or empty()?Nothing. Why not either one? You don't have to use the $key variable
and you can usecount()
or empty(), but for me personally, it makes a
lot of sense.Ah, I just realized why it makes a lot of sense, and that is when
Fibers get involved. The value and key could change underneath you
from one function call to another.$key = array_key_first($this-array);
// call something that suspends a fiber and results in $this->array
being mutated$value = array_value_first($this->array);
// $value and $key may now point to two totally separate things.
I've been bitten by this with Fibers a few times now (or things very
similar to it).Having a way to atomically get $key and $value would be a boon, not a
hindrance.Robert Landers
Software Engineer
Utrecht NL--
To unsubscribe, visit: https://www.php.net/unsub.php
--
Norbert Sendetzky
Aimeos GmbH
Rennbahnstr. 32
DE-22111 Hamburg
E-Mail: norbert@aimeos.com
Phone: +49 40 8668 4492
Web: aimeos.com
Trade register: District court Hamburg HRB 143090
Managing director: Norbert Sendetzky
VAT ID: DE302287839
It's true that sentiment may have shifted in this time. However, a
common argument at that time still stands:null
is not a good
sentintenal for failure because the value inside the array very well
could have been null.
What about a signature like:
array_first(array $array, mixed $value_if_missing = null);
That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function.
mjec
What about a signature like:
array_first(array $array, mixed $value_if_missing = null);
That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function.
This is a problem that should be addressed in your application.
array_first($arr) ?? $initial
I personally think we should make the effort to write it this way and not have to support initial values at the language level.
Regards.
Saki
What about a signature like:
array_first(array $array, mixed $value_if_missing = null);
That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function.
This is a problem that should be addressed in your application.
array_first($arr) ?? $initial
I personally think we should make the effort to write it this way and
not have to support initial values at the language level.
The problem Levi mentioned is that there's ambiguity in this construction: if the valid data domain for elements of $arr
includes null
, then you can't tell whether the null comes from the array being empty, or from its first value being null. In other words, there exists application code where using ??
in this way is unsuitable.
I can think of three approaches for dealing with this, resulting in application code like:
$value = array_first($arr, $default);
$value = count($arr) > 0 ? array_first($arr) : $default;
try {
$value = array_first($arr);
} catch (OutOfBoundsException $e) {
$value = $default;
}
I think the first of those - what I initially suggested - is the cleanest.
mjec
I see now, that makes sense.
There is also a technique to make the return value [$key => $value]
instead of just a value, but this loses simplicity.
Thanks.
Saki
There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.
Hmm, since the naming array_first and array_last doesn't clarify that
it's returning a key or a value. What if it returned both as ?[key,
value].
That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();
[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();
Since reset()
and end()
return false when the array is empty, in a sense, there is an idea that there is no need to take such strict care of the return value.
If you were to take proper care, you would probably specify a default value or throw an exception, as has already been suggested. However, specifying a default value is not very smart in my opinion.
The fact that what value is considered to be "unable to obtain" changes depending on the situation causes some complexity. And when dealing with an array whose values are completely unknown, it becomes necessary to "hope" that the values do not conflict with the default values.
Can the following signature meet your requirements? Or will it become too complicated?
// arrar_first(array $arr, bool &$has_value)
$value = array_first($arr, $has_value);
if ($has_value) {
// array has items
// $value is mixed
} else {
// array is empty
// $value === null
}
Regards.
Saki
I thought of it after sending the email, so I'll post it again. By combining my two ideas, I think I can come up with a smarter proposal.
array_first(array $array, int|string &$key = null)
If you want to accurately determine whether an array is empty or not, you can satisfy your request by checking if the key is null. Users who do not think accurate determination is necessary can omit the second argument.
And if you also want a key, it can fulfill that request as well.
Regards.
Saki
On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson brandonja991@gmail.com
wrote:
There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.Hmm, since the naming array_first and array_last doesn't clarify that
it's returning a key or a value. What if it returned both as ?[key,
value].That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();
This function signature can be accomplished by userland once we have
array_key_first()
and array_first()
. It's much better to keep
array_first()
as simple as possible and let everyone build their own
approach to go about it since we have so many approaches.
--
Marco Deleu
On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson brandonja991@gmail.com
wrote:There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.Hmm, since the naming array_first and array_last doesn't clarify that
it's returning a key or a value. What if it returned both as ?[key,
value].That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();
Hey Marco,
This function signature can be accomplished by userland once we have
array_key_first()
andarray_first()
.
This would always mean you have to keep them right next to each other,
it would be a best practice to do so and to split them up should be a
code smell in any static analysis. There is no way to tell if a Fiber
is involved in any function call in PHP, thus if you split them apart
and call a function, it is possible that your current Fiber is
suspended and another Fiber mutates the variable you are referencing
(this is especially true in Classes, not so much in pure functions).
Since they would always have to be right next to each other, it is
easier to just combine them into a single atomic function call, which
would negate the need for static analysis to be involved or surprises.
It's much better to keep
array_first()
as simple as possible and let everyone build their own
approach to go about it since we have so many approaches.
There is only one right approach that prevents Fibers from messing up
your day, and it would be considerable boilerplate code that you'd
have to type every time, as well as involve static analysis and watch
for "people who don't know" better in code reviews.
Robert Landers
Software Engineer
Utrecht NL
On Wed, Oct 18, 2023 at 4:31 AM Robert Landers landers.robert@gmail.com
wrote:
On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson brandonja991@gmail.com
wrote:There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.Hmm, since the naming array_first and array_last doesn't clarify that
it's returning a key or a value. What if it returned both as ?[key,
value].That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();Hey Marco,
This function signature can be accomplished by userland once we have
array_key_first()
andarray_first()
.This would always mean you have to keep them right next to each other,
it would be a best practice to do so and to split them up should be a
code smell in any static analysis.
"You" (general you) don't always have to keep them right next to each
other. Each function is self-sufficient and independent. Maybe on your
personal bubble you might need to always keep them next to each other,
which is why I suggested creating your own userland function that returns
key and value together.
There is no way to tell if a Fiber
is involved in any function call in PHP, thus if you split them apart
and call a function, it is possible that your current Fiber is
suspended and another Fiber mutates the variable you are referencing
(this is especially true in Classes, not so much in pure functions).
I might be completely wrong here, but on my personal bubble, I consider
Fibers to be a corner (a fraction) of PHP compared to non-Fibers PHP.
Although Fibers took the approach to not "paint" [what color is] your
function, it doesn't mean that Fibers can be used without taking
precaution, as with any new tool.
Since they would always have to be right next to each other, it is
easier to just combine them into a single atomic function call, which
would negate the need for static analysis to be involved or surprises.It's much better to keep
array_first()
as simple as possible and let everyone build their own
approach to go about it since we have so many approaches.There is only one right approach that prevents Fibers from messing up
your day, and it would be considerable boilerplate code that you'd
have to type every time, as well as involve static analysis and watch
for "people who don't know" better in code reviews.
You say only one approach, but a return signature of : [$key, $value]
or
the array_key(array $array, &$key = null)
makes it at least 2 approaches
that would be fibers-safe, no?
This is a discussion about an extremely basic functionality that PHP hasn't
introduced up until now. I think it's an extremely great addition, but
requires to focus first on the most basic aspect of it. Literally every
beginner, mid-level, experienced and most senior PHP developers will work
with PHP arrays on way or another. As such, a basic functionality like this
should remain as basic as possible. If needed, PHP can port more helper
functions into the core to cater for Fibers in the future.
In my opinion, the only problem is the ambiguity of returning null
which
might mean the array is empty or might mean the first value is truly null.
If we get a warning box on PHP Docs recommending people to pair this with
empty()
before using it, it gives users coverage for everything they will
need most of the time. Personally, I think I'd prefer the function to throw
an exception than to return null
when array is empty to avoid ambiguity
and force folks to use empty()
, but that would also mean complicating the
function more due to edge cases, which as I stated in this email, I'd
rather have the simplest thing possible and let userland fill in the
additional complexities needed.
--
Marco Deleu
On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson brandonja991@gmail.com
wrote:There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.Hmm, since the naming array_first and array_last doesn't clarify that
it's returning a key or a value. What if it returned both as ?[key,
value].That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();Hey Marco,
This function signature can be accomplished by userland once we have
array_key_first()
andarray_first()
.This would always mean you have to keep them right next to each other,
it would be a best practice to do so and to split them up should be a
code smell in any static analysis."You" (general you) don't always have to keep them right next to each other. Each function is self-sufficient and independent. Maybe on your personal bubble you might need to always keep them next to each other, which is why I suggested creating your own userland function that returns key and value together.
There is no way to tell if a Fiber
is involved in any function call in PHP, thus if you split them apart
and call a function, it is possible that your current Fiber is
suspended and another Fiber mutates the variable you are referencing
(this is especially true in Classes, not so much in pure functions).I might be completely wrong here, but on my personal bubble, I consider Fibers to be a corner (a fraction) of PHP compared to non-Fibers PHP. Although Fibers took the approach to not "paint" [what color is] your function, it doesn't mean that Fibers can be used without taking precaution, as with any new tool.
Since they would always have to be right next to each other, it is
easier to just combine them into a single atomic function call, which
would negate the need for static analysis to be involved or surprises.It's much better to keep
array_first()
as simple as possible and let everyone build their own
approach to go about it since we have so many approaches.There is only one right approach that prevents Fibers from messing up
your day, and it would be considerable boilerplate code that you'd
have to type every time, as well as involve static analysis and watch
for "people who don't know" better in code reviews.You say only one approach, but a return signature of
: [$key, $value]
or thearray_key(array $array, &$key = null)
makes it at least 2 approaches that would be fibers-safe, no?This is a discussion about an extremely basic functionality that PHP hasn't introduced up until now. I think it's an extremely great addition, but requires to focus first on the most basic aspect of it. Literally every beginner, mid-level, experienced and most senior PHP developers will work with PHP arrays on way or another. As such, a basic functionality like this should remain as basic as possible. If needed, PHP can port more helper functions into the core to cater for Fibers in the future.
In my opinion, the only problem is the ambiguity of returning
null
which might mean the array is empty or might mean the first value is truly null. If we get a warning box on PHP Docs recommending people to pair this withempty()
before using it, it gives users coverage for everything they will need most of the time. Personally, I think I'd prefer the function to throw an exception than to returnnull
when array is empty to avoid ambiguity and force folks to useempty()
, but that would also mean complicating the function more due to edge cases, which as I stated in this email, I'd rather have the simplest thing possible and let userland fill in the additional complexities needed.--
Marco Deleu
Hey Marco,
I might be completely wrong here, but on my personal bubble, I consider Fibers to be a corner (a fraction) of PHP compared to non-Fibers
Fibers are part of PHP and are being used in more and more libraries.
You may be using them and be totally unaware that you are using them.
I'm not saying we need to "cater" to them, per se, but adding two new
functions that will (most likely) be used on the same data structure,
at nearly the same time, is just asking for devs to get bit by a
concurrency bug. Maybe not this year, or anytime relatively soon, but
eventually, as Fibers and async PHP becomes more popular.
IMHO, it just makes sense to combine them into a single function
(however that looks like). You sidestep a whole class of bugs, and
documentation/education issues, and make the whole world a tiny bit
more reliable. Keeping them separate only looks "simpler" if you only
consider first-order effects.
That's all I'm saying.
On Wed, Oct 18, 2023 at 9:29 AM Robert Landers landers.robert@gmail.com
wrote:
On Wed, Oct 18, 2023 at 4:31 AM Robert Landers landers.robert@gmail.com
wrote:On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson <
brandonja991@gmail.com>
wrote:There is also a technique to make the return value
[$key => $value]
instead of just a value, but this loses simplicity.Hmm, since the naming array_first and array_last doesn't clarify
that
it's returning a key or a value. What if it returned both as ?[key,
value].That opens quite a few use possibilities:
$first = array_first($array);
$value = $first[1] ?? throw new Exception();[,$value] = array_first($array) ?? [null, null];
[,$value] = array_first($array) ?? throw new Exception();Hey Marco,
This function signature can be accomplished by userland once we have
array_key_first()
andarray_first()
.This would always mean you have to keep them right next to each other,
it would be a best practice to do so and to split them up should be a
code smell in any static analysis."You" (general you) don't always have to keep them right next to each
other. Each function is self-sufficient and independent. Maybe on your
personal bubble you might need to always keep them next to each other,
which is why I suggested creating your own userland function that returns
key and value together.There is no way to tell if a Fiber
is involved in any function call in PHP, thus if you split them apart
and call a function, it is possible that your current Fiber is
suspended and another Fiber mutates the variable you are referencing
(this is especially true in Classes, not so much in pure functions).I might be completely wrong here, but on my personal bubble, I consider
Fibers to be a corner (a fraction) of PHP compared to non-Fibers PHP.
Although Fibers took the approach to not "paint" [what color is] your
function, it doesn't mean that Fibers can be used without taking
precaution, as with any new tool.Since they would always have to be right next to each other, it is
easier to just combine them into a single atomic function call, which
would negate the need for static analysis to be involved or surprises.It's much better to keep
array_first()
as simple as possible and let everyone build their own
approach to go about it since we have so many approaches.There is only one right approach that prevents Fibers from messing up
your day, and it would be considerable boilerplate code that you'd
have to type every time, as well as involve static analysis and watch
for "people who don't know" better in code reviews.You say only one approach, but a return signature of
: [$key, $value]
or thearray_key(array $array, &$key = null)
makes it at least 2
approaches that would be fibers-safe, no?This is a discussion about an extremely basic functionality that PHP
hasn't introduced up until now. I think it's an extremely great addition,
but requires to focus first on the most basic aspect of it. Literally every
beginner, mid-level, experienced and most senior PHP developers will work
with PHP arrays on way or another. As such, a basic functionality like this
should remain as basic as possible. If needed, PHP can port more helper
functions into the core to cater for Fibers in the future.In my opinion, the only problem is the ambiguity of returning
null
which might mean the array is empty or might mean the first value is truly
null. If we get a warning box on PHP Docs recommending people to pair this
withempty()
before using it, it gives users coverage for everything they
will need most of the time. Personally, I think I'd prefer the function to
throw an exception than to returnnull
when array is empty to avoid
ambiguity and force folks to useempty()
, but that would also mean
complicating the function more due to edge cases, which as I stated in this
email, I'd rather have the simplest thing possible and let userland fill in
the additional complexities needed.--
Marco DeleuHey Marco,
I might be completely wrong here, but on my personal bubble, I consider
Fibers to be a corner (a fraction) of PHP compared to non-FibersFibers are part of PHP and are being used in more and more libraries.
You may be using them and be totally unaware that you are using them.
I'm not saying we need to "cater" to them, per se, but adding two new
functions that will (most likely) be used on the same data structure,
at nearly the same time, is just asking for devs to get bit by a
concurrency bug. Maybe not this year, or anytime relatively soon, but
eventually, as Fibers and async PHP becomes more popular.IMHO, it just makes sense to combine them into a single function
(however that looks like). You sidestep a whole class of bugs, and
documentation/education issues, and make the whole world a tiny bit
more reliable. Keeping them separate only looks "simpler" if you only
consider first-order effects.That's all I'm saying.
I completely understand what you're saying and I don't disagree with the
thought process. What I disagree with is your statement that you will
always use array_first() together with array_key_first()
. When talking
about standard lists (indexed from 0 to upper-bound), array_first() is an
order of magnitude more useful than array_key_first()
as we always know
what the first key is: 0.
Here's another thought process: suppose PHP never gets array_first(). In
your Fiber scenarios, you need to use array_key_first()
and
$array[array_key_first()]
and deal with any edge cases around this. You
have found issues, dealt with it and you're now aware of them. It's really
nice that you want to avoid others from going through the same pain as you
did, but the fact is array_first()
or $array[0]
is not only ALWAYS used
together with needing to know the key or not ALWAYS used with Fibers.
What I'm saying is: don't force a design functionality only for your use
case, especially as basic and fundamental as PHP Arrays. I don't want to be
forced to write [$value, $_] = array_first()
just because there's a
corner of PHP functionality that needs special treatment. If this was
fibers_array_first() I wouldn't mind at all.
Keeping them separate only looks "simpler" if you only consider
first-order effects.
Keeping them together only makes sense if you disregard first-order
effects. By "first-order effects" I read "basic functionality" and this is
where our disagreement relies. I wouldn't want PHP to provide the most
basic functionality you can do in an array with a thought process that
disregards the most basic usage.
--
Marco Deleu
I completely understand what you're saying and I don't disagree with the thought process. What I disagree with is your statement that you will always use array_first() together with
array_key_first()
. When talking about standard lists (indexed from 0 to upper-bound), array_first() is an order of magnitude more useful thanarray_key_first()
as we always know what the first key is: 0.
This is simply not true, 0 is not always the first key in a list,
especially after filtering it. Hence there is a need for this function
in the first place.
Here's another thought process: suppose PHP never gets array_first(). In your Fiber scenarios, you need to use
array_key_first()
and$array[array_key_first()]
and deal with any edge cases around this. You have found issues, dealt with it and you're now aware of them. It's really nice that you want to avoid others from going through the same pain as you did, but the fact isarray_first()
or$array[0]
is not only ALWAYS used together with needing to know the key or not ALWAYS used with Fibers.
PHP chose to implement Fibers in this way and it should be cognizant
of them when implementing new features. That's all I'm saying. Whether
anyone who matters, actually cares, is another story. All I can do is
say something. You can only lead a horse to water, after all, you
can't force it to drink.
What I'm saying is: don't force a design functionality only for your use case, especially as basic and fundamental as PHP Arrays. I don't want to be forced to write
[$value, $_] = array_first()
just because there's a corner of PHP functionality that needs special treatment. If this was fibers_array_first() I wouldn't mind at all.
If we went with the array return scenario:
// assuming it is in [value, key] form
[$value] = array_first($arr);
[,$key] = array_first($arr);
[$value, $key] = array_first($arr);
Or with the approach I suggested:
$value = array_first($arr);
array_first($arr, $key);
$value = array_first($arr, $key);
I don't think this is asking for much, nor complicated. Both
approaches seem simpler and less verbose than:
[$value, $key] = [array_first($arr), array_key_first($arr)];
At the end of the day, I'll be happy with any solution implemented,
because it is still far better than what we have currently.
Robert Landers
Software Engineer
Utrecht NL
On Wed, 18 Oct 2023 at 17:05, Robert Landers landers.robert@gmail.com
wrote:
This is simply not true, 0 is not always the first key in a list,
especially after filtering it. Hence there is a need for this function
in the first place.
Just to clarify this point: If 0 is not the first key, then it's not a list.
After filtering a list, you get an array that may or may not be a list:
https://3v4l.org/VegUr
Regardless, to add my 2 cents, I'd keep things simple and vote for this
signature:
array_first(array $array): mixed
array_last(array $array): mixed
returning the first/last element, or null
if the array is empty.
Or, alternatively:
array_first(array $array, mixed $default = null): mixed
array_last(array $array, mixed $default = null): mixed
returning $default
if the array is empty.
Both look fine to me.
- Benjamin
This is simply not true, 0 is not always the first key in a list,
especially after filtering it. Hence there is a need for this function
in the first place.Just to clarify this point: If 0 is not the first key, then it's not a list.
After filtering a list, you get an array that may or may not be a list:
https://3v4l.org/VegUr
I don't see how array_is_list
is relevant to array_first
and
array_last
. PHP arrays are ordered:
$foo = [
"first" => 1,
"third" => 3,
];
It would be perfectly fine to use array_first
or array_last
with
$foo
. I think probably you would use array_key_first
and
array_key_last
so you also get the key and not just the value, but I
don't see any need to reduce array_first
and array_last
to only be
logical or correct with arrays that uphold array_is_list
.
On Wed, 18 Oct 2023 at 17:47, Levi Morrison levi.morrison@datadoghq.com
wrote:
I don't see how
array_is_list
is relevant toarray_first
and
array_last
. PHP arrays are ordered:$foo = [ "first" => 1, "third" => 3, ];
It would be perfectly fine to use
array_first
orarray_last
with
$foo
. I think probably you would usearray_key_first
and
array_key_last
so you also get the key and not just the value, but I
don't see any need to reducearray_first
andarray_last
to only be
logical or correct with arrays that upholdarray_is_list
.
I didn't mean that array_first/last should only work on lists; they should
work on any array as you mentioned. I was just correcting a statement about
lists.
Sorry if I wasn't clear.
- Benjamin
On Wed, Oct 18, 2023 at 12:04 PM Robert Landers landers.robert@gmail.com
wrote:
I completely understand what you're saying and I don't disagree with the
thought process. What I disagree with is your statement that you will
always use array_first() together witharray_key_first()
. When talking
about standard lists (indexed from 0 to upper-bound), array_first() is an
order of magnitude more useful thanarray_key_first()
as we always know
what the first key is: 0.This is simply not true, 0 is not always the first key in a list,
especially after filtering it. Hence there is a need for this function
in the first place.
To give back on the same format, "this is simply not true". Here are the
facts:
- https://www.php.net/manual/en/function.array-is-list.php
- Determines if the given array is a list. An array is considered a list if
its keys consist of consecutive numbers from 0 to count($array)-1." - https://3v4l.org/JZS9N#v8.2.11
At this point I have nothing else to add to this conversation. You will
either accept that it is actually possible to use array_first()
without
using array_key_first()
or you'll keep believing that your knowledge and
experience is the only correct one.
I believe my reservations have been registered, I would not like to have
array_first()
behave in a non-obvious way (i.e. involving array $key)
because it's useful for Fibers users. I believe that writing your own
wrapper that always returns key and value simultaneously is easy and
straight-forward and may even make it into the core in the future. Rather
than trying to solve deep convoluted issues on version 1, I believe PHP
could introduce the simplest version of the function first and later on add
an array_first_key_value() in the future if needed.
In fact, I encourage you to propose an RFC for array_first_key_value()
as
a solution for the problem you're raising.
--
Marco Deleu
I believe my reservations have been registered, I would not like to have
array_first()
behave in a non-obvious way (i.e. involving array $key)
because it's useful for Fibers users. I believe that writing your own
wrapper that always returns key and value simultaneously is easy and
straight-forward and may even make it into the core in the future. Rather
than trying to solve deep convoluted issues on version 1, I believe PHP
could introduce the simplest version of the function first and later on add
an array_first_key_value() in the future if needed.
I think there's a fundamental misunderstanding here. Fibers are not threads. They do not do preemptive multitasking. If a give function call stack does not explicitly suspend itself, then a fiber WILL NOT change the current context.
If we assume that array_first(), being an internal function, does not explicitly suspend a fiber internally (which I think is a pretty safe assumption), then this code cannot possibly have a race condition in it:
$key = array_key_first($arr);
$value = array[$key];
The concerns about this having some kind of race condition around fibers are, as far as I am aware, entirely unfounded, and we should not consider them, as they do not exist. (Obviously if those two lines are separated by some other call, and that other call suspends a fiber, then it's possible there would be a race condition. But in that case the operation is not atomic anyway so all bets are completely off. Which is why you shouldn't be using shared mutable state arrays at all in the first place, fibers are not, but that's another story.)
As far as the not-found error case goes, I cite my previous article on the subject here:
https://peakd.com/hive-168588/@crell/much-ado-about-null
More to the point, PHP arrays are untyped. That means there is absolutely no possible sentinel value that we can guarantee will never be an array value, because even if we defined some one-off enum to serve as a sentinel, that could be put into an array quite easily, even if it's dumb to do. null
is the default sentinel value, but runs into various problems because its meaning in different contexts may be different.
The question is whether null being a legit value in an array being accessed with array_first/array_last is a common enough case that we need to worry about it. I highly doubt it, frankly. I cannot think of a non-contrived case where that would be true. (An array with random null values in it that you don't want to filter out entirely seems like an edge case to me.)
That means for the vast majority of use cases, this is completely fine:
$v = array_first($arr) ?? $default;
Because the cases where you care to differentiate between "there is no first value" and "there is a first value but it is a non-value" are small. And, as others have noted, in those cases count()
isn't hard to use.
So no, we don't need to do anything fancier than that.
To the other points raised:
Absolutely not to an in/out by-ref parameter. That is an abomination and I will vote against any API that does that, without hesitation. Let's not even discuss it.
As far as the naming, most array functions that have a value version and key version don't specify "value", only the key. The unspecified version is the value version. (array_diff vs array_diff_key, array_intersect vs array_intersect_key, sort vs ksort, etc.) Pretty much nowhere do we specify "_value" in the function name.
https://www.php.net/manual/en/ref.array.php
That means array_first/array_last is consistent with the current API, and array_first_value would be the confusing oddball. For that reason, no, we should not do that and just use array_first/array_last.
With all that said, I do support simple array_first/array_last functions, with just a null-for-not-found return.
--Larry Garfield
You may be using them and be totally unaware that you are using them.
Emphasis on that. Take promises for example. Anyone using libraries
that incorporate promises either are using fibers or will likely be
using them in the near future. And I'd say that one pattern is
probably used enough to be considered more than just a corner of php.
On Wed, Oct 18, 2023 at 10:29 AM Brandon Jackson brandonja991@gmail.com
wrote:
You may be using them and be totally unaware that you are using them.
Emphasis on that. Take promises for example. Anyone using libraries
that incorporate promises either are using fibers or will likely be
using them in the near future. And I'd say that one pattern is
probably used enough to be considered more than just a corner of php.
If you have 5 developers dealing with issues originated from Fibers and a
billion developers using it oblivious that they are using it, why
array_first()
, a function targeted at a billion developers, needs to
cater for issues being faced by 5 developers?
I don't mean to discredit/reduce/invalidate the work/efforts that
developers working with Fibers encounter, but my point is that if you're
using Fibers without knowing it, then any inner problem of Fibers do not
mean anything to you as the developers providing the library/functionality
will have to find ways to avoid exposing an API with broken behavior.
Whether today or 1 year from now 100% of PHP code will be taking advantage
of Fibers or not is irrelevant to this discussion.
--
Marco Deleu
This function signature can be accomplished by userland once we have
array_key_first()
andarray_first()
. It's much better to keeparray_first()
as simple as possible and let everyone build their own approach to go about it since we have so many approaches.
The goal wasn't necessarily to keep them together. The goal was to
introduce an arguably simple way to:
- Be able to get the first/last value of an array.
- Know if the value was actually in existence or not, rather than
just blindly returning null when it could be a valid value. - Accompany multiple use cases like needing to return a default if
not found or throwing an exception. - Offer a way to know if the value existed or not and act accordingly
without additional logic checking the key. - Address the seeming genericness of the function name.
- If I were someone who seen the name for the first time. I'd see it
and ask array_first what? And proceed to the docs.
The different approaches are trying to figure out the best way to know
whether the result was the actual value from the array or some baked
in language default null.
I get your desire to keep things simple, but IMO returning a value
that does not conflict with possibly valid values or somehow indicates
the value was not present is important, and should come before
simplicity. Which likely means involving the key somehow.
On Wed, Oct 18, 2023 at 10:11 AM Brandon Jackson brandonja991@gmail.com
wrote:
I get your desire to keep things simple, but IMO returning a value
that does not conflict with possibly valid values or somehow indicates
the value was not present is important, and should come before
simplicity. Which likely means involving the key somehow.
The only portion in your email I disagree with is this ending. I believe
there are enough use-cases where if the first value is "valid null" or
"default null" it won't matter. The developer will treat them both the
same. Perhaps you disagree with this and want to avoid ambiguity at all
costs. My proposal to avoid ambiguity would be throwing an exception
instead of involving the key because involving the key can be a composition
between array_first()
* and array_key_first()
.
Although I would prefer the function to throw, I think it will have the
same effect as this key discussion: complicate something that can be
simple. If the developer needs to distinguish between "default null" and
"value null", they are able to do so by running empty()
on the array
prior to asking for array_first()
. It's actually better than a try/catch,
to be honest.
Ultimately, there's 2 parallel discussion that somewhat intertwine
themselves: Fibers ("async" code) and ambiguity ("value null" vs "default
null") and while there are options that may cater for both of them, there
are also options that cater only for each of them individually. Trying to
over-pollute a function as simple as array_first()
to cater for these
edge cases is where I think the problem is because userland will always be
able to tackle these issues by wrapping the basic functionality provided by
core.
- If naming is an issue to you, I'd also be fine with
array_value_first()
.
--
Marco Deleu
The only portion in your email I disagree with is this ending. I believe there are enough use-cases where if the first value is "valid null" or "default null" it won't matter. The developer will treat them both the same. Perhaps you disagree with this and want to avoid ambiguity at all costs. My proposal to avoid ambiguity would be throwing an exception instead of involving the key because involving the key can be a composition between
array_first()
* andarray_key_first()
.Although I would prefer the function to throw, I think it will have the same effect as this key discussion: complicate something that can be simple. If the developer needs to distinguish between "default null" and "value null", they are able to do so by running
empty()
on the array prior to asking forarray_first()
. It's actually better than a try/catch, to be honest.
Sure in many use cases undefined and null can be equivalent, but there
are other use cases and considering the fact that php does not have a
user level "undefined" value. It should at least attempt to not be
ambiguous when possible. Instead of being ambiguous by default,
requiring the user to do additional work to not be ambiguous.
I do think the method is a great opportunity to avoid ambiguity,
without a huge sacrifice on cost. As you said, throwing an exception
would only further complicate things. Sure an empty check would get
the job done, but again I believe it should not require such
additional logic just to not be ambiguous.
Ultimately, there's 2 parallel discussion that somewhat intertwine themselves: Fibers ("async" code) and ambiguity ("value null" vs "default null") and while there are options that may cater for both of them, there are also options that cater only for each of them individually. Trying to over-pollute a function as simple as
array_first()
to cater for these edge cases is where I think the problem is because userland will always be able to tackle these issues by wrapping the basic functionality provided by core.
My argument was purely for ambiguity and the other reasons outlined.
While the possible edge cases from fibers usage arguably may not be a
great primary reason to offer such functionality, it is a great
supporting argument.
- If naming is an issue to you, I'd also be fine with
array_value_first()
.
If the rfc does maintain only returning the value
array_value_first()
IMO is ideal.
- With array_first being so general, I would think it's only fair that
the naming is reserved for something that touches on multiple parts of
the array.- If someone did want to open an rfc adding the above functionality
they would have to opt for something like array_first_key_value which
having a group of key/value operator methodsarray_key_first
,
array_first
, andarray_first_key_value
would be absolutely
atrocious IMO.
- If someone did want to open an rfc adding the above functionality
- Naming consistency with array_key_first would be nice. For new
comers to the language I think it is a reasonable assumption when you
see array_key_first being used. That array_value_first should also
exist that does the same thing for values, and array_first might be a
slight curve ball.- They are going to do some googling and probably be pointed to some
outdated way of doing things, like using array slice or back to
array_key_first. As time goes on blogs and other places like stack
overflow will update there solutions, and or people will re-ask hoping
there's a more up to date/efficient solution, and hopefully then
someone will actually provide the latest answer ofarray_first
.
- They are going to do some googling and probably be pointed to some
On Wed, Oct 18, 2023 at 2:49 PM Brandon Jackson brandonja991@gmail.com
wrote:
The only portion in your email I disagree with is this ending. I believe
there are enough use-cases where if the first value is "valid null" or
"default null" it won't matter. The developer will treat them both the
same. Perhaps you disagree with this and want to avoid ambiguity at all
costs. My proposal to avoid ambiguity would be throwing an exception
instead of involving the key because involving the key can be a composition
betweenarray_first()
* andarray_key_first()
.Although I would prefer the function to throw, I think it will have the
same effect as this key discussion: complicate something that can be
simple. If the developer needs to distinguish between "default null" and
"value null", they are able to do so by runningempty()
on the array
prior to asking forarray_first()
. It's actually better than a try/catch,
to be honest.Sure in many use cases undefined and null can be equivalent, but there
are other use cases and considering the fact that php does not have a
user level "undefined" value. It should at least attempt to not be
ambiguous when possible. Instead of being ambiguous by default,
requiring the user to do additional work to not be ambiguous.I do think the method is a great opportunity to avoid ambiguity,
without a huge sacrifice on cost. As you said, throwing an exception
would only further complicate things. Sure an empty check would get
the job done, but again I believe it should not require such
additional logic just to not be ambiguous.
My statement about throwing exceptions is, to me, exactly equivalent to the
discussion of $key and $value. I believe being ambiguous is fine in this
case. If we collectively decide that ambiguity is unacceptable, then my
vote is on Exception over involving $key on array_first()
. I would go as
far to say that if the only option is to have array_first()
returning
$key and $value simultaneously, I probably would prefer if array_first()
does not get implemented at all.
- If naming is an issue to you, I'd also be fine with
array_value_first()
.
If the rfc does maintain only returning the value
array_value_first()
IMO is ideal.
- With array_first being so general, I would think it's only fair that
the naming is reserved for something that touches on multiple parts of
the array.
- If someone did want to open an rfc adding the above functionality
they would have to opt for something like array_first_key_value which
having a group of key/value operator methodsarray_key_first
,
array_first
, andarray_first_key_value
would be absolutely
atrocious IMO.- Naming consistency with array_key_first would be nice. For new
comers to the language I think it is a reasonable assumption when you
see array_key_first being used. That array_value_first should also
exist that does the same thing for values, and array_first might be a
slight curve ball.
- They are going to do some googling and probably be pointed to some
outdated way of doing things, like using array slice or back to
array_key_first. As time goes on blogs and other places like stack
overflow will update there solutions, and or people will re-ask hoping
there's a more up to date/efficient solution, and hopefully then
someone will actually provide the latest answer ofarray_first
.
Everything you mention about function naming I believe gets invalidated by
Larry's comment regarding all of PHP array_()
function family. They don't
have value
in their name when working with array values and they have
key
when working with array keys. With that, array_first() cannot be
"consistent" with array_key_first()
without being inconsistent with dozens
of PHP array functions.
Larry's comment is enough to close down the discussion on the function name
as there's no room for anything other than array_first()
in my opinion.
--
Marco Deleu
Sure in many use cases undefined and null can be equivalent, but there
are other use cases and considering the fact that php does not have a
user level "undefined" value. It should at least attempt to not be
ambiguous when possible. Instead of being ambiguous by default,
requiring the user to do additional work to not be ambiguous.I do think the method is a great opportunity to avoid ambiguity,
without a huge sacrifice on cost. As you said, throwing an exception
would only further complicate things. Sure an empty check would get
the job done, but again I believe it should not require such
additional logic just to not be ambiguous.
Can we have ultimately a flag in the function for throwing an exception in
case of empty array?
Kind regards,
Jorg