Re: [RFC] Duration class
| From: | Larry Garfield | Date: | Wed, 01 Jul 2026 18:18:44 +0000 |
| Subject: | Re: [RFC] Duration class | ||
| References: | 1 2 3 4 5 6 7 8 9 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131667@lists.php.net to get a copy of this message | ||
On Wed, Jul 1, 2026, at 12:22 PM, Tim Düsterhus wrote:
> Hi
>
> Am 2026-06-23 15:04, schrieb Tim Düsterhus:
>> Both Derick and I were receptive to the
Duration::sum()
>> suggestion.
>>
>> One big benefit I am personally seeing is that it would allow to rename
>> the negate(), multiplyBy(),
>> and divideBy() methods to use “past
>> tense” (is that the correct term?) to indicate that they return a copy,
>> without requiring awkward naming like added().
>> ->sub() is also
>> technically redundant due to the existence of negative Durations, thus
>> there is no need for a mirrored pair like multiplication / division,
>> since the information can be encoded in the Duration object itself.
>>
>> To avoid readers making assumptions, can you spell out your arguments
>> against replacing ->add() and
>> ->sub() by a unified ::sum()
>> method?
>
> To close this out ourselves: While having a static sum() method
> works
> for Durations, since the Duration with addition forms an
> abelian
> group, this doesn't work for the other future-scope classes where
> addition doesn't form an (abelian) group. More specifically: Adding two
> Instants together is not a meaningful operation. Adding a Duration to an
> Instant however is. Using something like:
>
> $epoch = Instant::fromUnixtime(0);
> $onePointFiveHoursLater = Instant::sum($epoch,
> Duration::fromMinutes(30), Duration::fromHours(1));
>
> would be very weird. Instead ->add() is the obvious
> operation here:
>
> $epoch = Instant::fromUnixtime(0);
> $onePointFiveHoursLater = $epoch
> ->add(Duration::fromMinutes(30))
> ->add(Duration::fromHours(1));
>
> notably this would also work then:
>
> $epoch = Instant::fromUnixtime(0);
> $onePointFiveHoursLater = $epoch
> ->add(
> Duration::fromMinutes(30)
> ->add(Duration::fromHours(1)
> );
>
> making the Instant + Duration -> Instant operation a “right group
> action”.
How about that. Forgetting to respond to this thread meant you gave a good response for me.
Thanks, Tim. :-)
> We will thus keep instance methods for “addition” and “subtraction”. If
> someone has a suggestion regarding naming (particularly with regard to
> negate() vs negated() and multiplyBy() and multipliedBy()), I'll be
> happy to discuss that. Java uses plus, minus, multipliedBy, dividedBy
> and negated. Golang is just using an integer (meaning you just use the
> operators). Rust’s std::time::Duration uses add, sub, mul, div (with
> saturating and checked variants), but also overloads operators. Rust’s
> chrono::TimeDelta is similar to std::time::Duration, but doesn't have
> the saturating variants. JavaScript’s Temporal uses add, sub, negated
> and doesn't support multiplication and division.
>
> Please keep the divide**By**() (Duration / int -> Duration)
> vs
> divide**Into**() (Duration / Duration -> (int, Duration))
> suggestion
> in mind when having opinions about the naming. See:
> https://news-web.php.net/php.internals/131634
negated() would be consistent with the "ed means return new" pattern found in many
languages, so I would strongly recommend following that pattern.
For the others, my inclination is to go short (add, sub) for easier typing and a more compact
result, but that's not a make-or-break issue for me.
--Larry Garfield