Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Saki Takamachi
Hi Barney, Jordan,

I would like to thank you all again for discussing this RFC in great detail. I 
believe that the specification for the `BCMath\Number` class is in very good 
shape due to the detailed discussions and the great amount of feedback. Now 
that we have been able to brush up the specifications so far, I would be very 
happy if we could have a good discussion about the concerns that still exist.

> Coming back to this point, I think these are basic features that people would 
> expect to be there - I think I would find just slightly frustrating to start 
> learning how to use a class like this and then
> find that it doesn't have these functions. Casting and calling `intval` or 
> `floatval` all feel like slightly awkward workarounds that shouldn't be 
> needed in a greenfield project. We know that the string
> inside the object is always a numeric string, so it should be easier to parse 
> it as an int than to parse it as a date or a JSON document. Code doing the 
> latter should stand out as odd looking.

> The class cannot guarantee that it can return a value in the type you request 
> however, so the way that is handled would need to be decided. The value can 
> easily be outside of the range of an int. Should it return a float silently 
> in that case for `toInt()`? What if the value is beyond the range of a float? 
> That would be a very rare situation, as floats can represent extremely large 
> numbers (with very reduced accuracy), but I would expect it to throw an 
> exception if that happened. Ideally an exception that I could catch and 
> ignore, since I can almost surely deal with that error in most situations.
> 
> What about a number that is so small that it can't fit in a float? Similar 
> situation, though I expect it would occur slightly more often than a number 
> being too large to fit in a float, even though it would also be rare.
> 
> I think these helper functions belong in the RFC, but they aren't quite 
> straightforward, which is what I think Saki was alluding to.

> Yes I agree there are subtleties to work out for these functions. I don't 
> think there's such a thing as a number to small to fit in a float. Converting 
> from decimal to float is always an approximation, sometimes the best 
> approximation available as a float will be either 0 or -0.

If there is a demand for such functionality, I think it should of course be 
included in the RFC. However, as Jordan mentioned, proper error handling is 
required. IMHO, I think the following specifications are good:

- toInt(): If it has a decimal part, round it to an integer according to the 
rounding mode. If the result is too large to be represented as an int, it will 
not be converted to a float and will throw an exception meaning it cannot be 
converted to an int.
- toFloat(): If the result is too large or too small, throws an exception 
meaning it cannot be converted, just like int. Also, if the value is within the 
representable range but the precision is too fine, such as 
`1.0001`, it will be rounded according to the rounding mode. 
However, if round to a precision of 17 or 18 digits, the error will end up 
being very large, so refer to the value defined in `PHP_FLOAT_DIG` and use 15 
digits as the maximum number of digits. This constant is 16 for IBM and 15 for 
others, but for consistency of operation it should be set to 15.


>> I don't think it will be possible to make a good Money class as a child of 
>> this. BcNum is a read-only class, so if the constructor of BcNum is final 
>> then the child class won't be able to take the currency as a constructor 
>> param, and won't be able to protect the invariant that currency must be 
>> initialized. If the constructor of BcNum were made non-final then BcNum 
>> wouldn't be able to protect the invariant of the numeric value always being 
>> initialized once the constructor has returned. And it should be 
>> straightforward to make a good money class as a composition of BcNum and a 
>> currency enum or string.
> 
> The RFC does not list the constructor as final, and I would not expect it to. 

>> There's probably not any good use case for a subclass to add properties, 
>> unless perhaps the subclass developers are willing do do away with some of 
>> the checks that would normally be done on a value object by the PHP runtime 
>> to keep it valid (maybe replacing them with static analysis checks). But 
>> there are lots of reasonable use cases for subclasses to add methods, even 
>> if they're effectively syntax sugar for static methods with a BcNum typed 
>> param.
> 
> I literally just provided in the quote you are replying to a good use case 
> for a subclass. You can do the same thing with composition yeah, and that 
> might even be better to a lot of people, but I don't think this RFC should 
> take a position AGAINST subclasses and in favor of composition. 

>> Having just written that I've now checked the behavior of DateTime - see 
>> 

Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Jordan LeDoux
On Thu, Apr 4, 2024 at 2:19 PM Barney Laurance 
wrote:

>
> I don't think it will be possible to make a good Money class as a child of
> this. BcNum is a read-only class, so if the constructor of BcNum is final
> then the child class won't be able to take the currency as a constructor
> param, and won't be able to protect the invariant that currency must be
> initialized. If the constructor of BcNum were made non-final then BcNum
> wouldn't be able to protect the invariant of the numeric value always being
> initialized once the constructor has returned. And it should be
> straightforward to make a good money class as a composition of BcNum and a
> currency enum or string.
>
> The RFC does not list the constructor as final, and I would not expect it
to.

> There's probably not any good use case for a subclass to add properties,
> unless perhaps the subclass developers are willing do do away with some of
> the checks that would normally be done on a value object by the PHP runtime
> to keep it valid (maybe replacing them with static analysis checks). But
> there are lots of reasonable use cases for subclasses to add methods, even
> if they're effectively syntax sugar for static methods with a BcNum typed
> param.
>
> I literally just provided in the quote you are replying to a good use case
for a subclass. You can do the same thing with composition yeah, and that
might even be better to a lot of people, but I don't think this RFC should
take a position AGAINST subclasses and in favor of composition.

> Having just written that I've now checked the behavior of DateTime - see
> https://3v4l.org/5DQZg . The constructor of that isn't final, so a child
> class can replace it with an empty constructor. But if it does that and
> leaves the value uninitialized then it blows up on a call to `format`.
> That's probably not something we should emulate. DateTimeImmutable behaves
> the same way.
>
Why not? Writing something like that obviously does not work, and the error
would be immediately apparent. Is it possible to create something that will
error? Of course. That's not an error that needs to be aggressively guarded
against, because the feedback is rapid and obvious.

Jordan


Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type

2024-04-04 Thread Jordan LeDoux
On Thu, Apr 4, 2024 at 2:28 PM Rowan Tommins [IMSoP] 
wrote:

>
>
> I haven't followed the discussion in the other thread, but I'm not sure
> what the use case would be for a "fixed scale decimal" that followed
> those rules.
>
> As mentioned before, the use case I've encountered is money
> calculations, where what people want to fix is the smallest unit of
> account - e.g. €0.01 for practical currency, or €0.0001 for detailed
> accounting / trading.
>
> If I write $total = 1.03_d2; $perPerson = $total / 2; I want a result of
> 0.51_d2 or 0.52_d2 - that's why I specified a scale of 2 in the first
> place.
>

Well, firstly most of the financial applications that I've worked in (I
work for a firm that writes accounting software right now) do not calculate
intermediate steps like this with fixed precision, or even have an interest
in doing so. They generally want maximum precision that is computationally
reasonable, and then round it according to their preferred method at the
end. Doing the calculations as you are suggesting would introduce a maximum
error of several cents/pence/etc. after only two or three calculations,
which is utterly useless for most applications that deal with money.

Truly "fixed-precision" is not something that decimal should even try to
be, in my opinion. The use cases where you CANNOT simply round the result
at the end to fit your display output or your storage location are very
minimal.


> If I want an accurate result of 0.515_d3, I would just specify 1.03_d,
> since the scale hasn't had any effect on the result.
>
> If I want a lossless split into [0.51_d2, 0.52_d2] I still need a
> function to exist somewhere, whether you spell that $total->split(2), or
> decimal_split($total, 2), etc. So it seems safer to also have
> $total->div(2, Round::DOWN) or decimal_div($total, 2, Round::DOWN) and
> have $total / 2 give an error.
>

I mean, what you are describing is how such OBJECTS are designed in other
languages like Python, but not scalars. Python also has (almost completely
unrestricted) userland operator overloading, which PHP does not, which
further makes the comparison a little murky.

This kind of precision restriction isn't something you would place on an
individual value, it's something you would place on all calculations.
That's why in Python this is done with a global runtime setting using
`getContext().perc` and `getContext().rounding`. A particular value having
a precision of X doesn't imply anything concrete about a calculation that
uses that value necessarily.


> Possibly, it could only error if the result doesn't fit in the scale, so
> that this would be fine: $total = 11.00_d2; $perPerson = $total / 2;
> assert($perPerson === 5.50_d2)
>
> Or possibly, it would just be an error to perform division on a fixed
> scale decimal, but allowed on a variable-fixed scale decimal.
>

Maybe we're just not understanding each other. Are you opposed to the idea
of doing this as a scalar? It certainly feels that way. This feels more
like an argument in favor of doing object-like numerics for this. I suppose
that isn't really that strange either, because as I noted such a value will
almost certainly need to be refcounted because it will not fit into the 64
bits available for a zval no matter what underlying library is used to
perform the math.

Jordan


Re: [PHP-DEV] [RFC][Concept] Data classes (a.k.a. structs)

2024-04-04 Thread Rowan Tommins [IMSoP]

On 03/04/2024 00:01, Ilija Tovilo wrote:
Data classes are classes with a single additional  > zend_class_entry.ce_flags flag. So unless customized, they behave as 
> classes. This way, we have the option to tweak any behavior we would 
> like, but we don't need to. > > Of course, this will still require an 
analysis of what behavior we > might want to tweak.


Regardless of the implementation, there are a lot of interactions we 
will want to consider; and we will have to keep considering new ones as 
we add to the language. For instance, the Property Hooks RFC would 
probably have needed a section on "Interaction with Data Classes".


On the other hand, maybe having two types of objects to consider each 
time is better than having to consider combinations of lots of small 
features.



On a practical note, a few things I've already thought of to consider:

- Can a data class have readonly properties (or be marked "readonly data 
class")? If so, how will they behave?
- Can you explicitly use the "clone" keyword with an instance of a data 
class? Does it make any difference?

- Tied into that: can you implement __clone(), and when will it be called?
- If you implement __set(), will copy-on-write be triggered before it's 
called?

- Can you implement __destruct()? Will it ever be called?




Consider this example, which would  > work with the current approach: > > 
$shapes[0]->position->zero!();


I find this concise example confusing, and I think there's a few things 
to unpack here...



Firstly, there's putting a data object in an array:

$numbers = [ new Number(42) ];
$cow = $numbers;
$cow[0]->increment!();
assert($numbers !== $cow);

This is fairly clearly equivalent to this:

$numbers = [ 42 ];
$cow = $numbers;
$cow[0]++;
assert($numbers !== $cow);

CoW is triggered on the array for both, because ++ and ->increment!() 
are both clearly modifications.



Second, there's putting a data object into another data object:

$shape = new Shape(new Position(42,42));
$cow = $shape;
$cow->position->zero!();
assert($shape !== $cow);

This is slightly less obvious, because it presumably depends on the 
definition of Shape. Assuming Position is a data class:


- If Shape is a normal class, changing the value of $cow->position just 
happens in place, and the assertion fails


- If Shape is a readonly class (or position is a readonly property on a 
normal class), changing the value of $cow->position shouldn't be 
allowed, so this will presumably give an error


- If Shape is a data class, changing the value of $shape->position 
implies a "mutation" of $shape itself, so we get a separation before 
anything is modified, and the assertion passes


Unlike in the array case, this behaviour can't be resolved until you 
know the run-time type of $shape.



Now, back to your example:

$shapes = [ new Shape(new Position(42,42)) ];
$cow = $shapes;
$shapes[0]->position->zero!(); assert($cow !== $shapes);

This combines the two, meaning that now we can't know whether to 
separate the array until we know (at run-time) whether Shape is a normal 
class or a data class.


But once that is known, the whole of "->position->zero!()" is a 
modification to $shapes[0], so we need to separate $shapes.




Without such a class-wide marker, you'll need to remember to add the
special syntax exactly where applicable.

$shapes![0]!->position!->zero();



The array access doesn't need any special marker, because there's no 
ambiguity. The ambiguous call is the reference to ->position: in your 
current proposal, this represents a modification *if Shape is a data 
class, and is itself being modified*. My suggestion (or really, thought 
experiment) was that it would represent a modification *if it has a ! in 
the call*.


So if Shape is a readonly class:

$shapes[0]->position->!zero();
// Error: attempting to modify readonly property Shape::$position

$shapes[0]->!position->!zero();
// OK; an optimised version of:
$shapes[0] = clone $shapes[0] with [
    'position' =>  (clone $shapes[0]->position with ['x'=>0,'y'=>0])
];

If ->! is only allowed if the RHS is either a readonly property or a 
mutating method, then this can be reasoned about statically: it will 
either error, or cause a CoW separation of $shapes. It also allows 
classes to mix aspects of "data class" and "normal class" behaviour, 
which might or might not be a good idea.



This is mostly just a thought experiment, but I am a bit concerned that 
code like this is going to be confusingly ambiguous:


$item->shape->position->zero!();

What is going to be CoW cloned, and what is going to be modified in 
place? I can't actually know without knowing the definition behind both 
$item and $item->shape. It might even vary depending on input.



Regards,

--
Rowan Tommins
[IMSoP]


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Mark Trapp
On Thu, Apr 4, 2024 at 2:16 PM Bilge  wrote:
> 
> On 04/04/2024 16:57, Tim Düsterhus wrote:
>> I think it would be reasonable to consider deprecating passing extra
>> arguments to a non-variadic function.
> 
> This seems like the only reasonable thing to do, to me. If this were the
> case, there should be no need for any new syntax, since we could simply
> deny passing extra arguments in the next major, no?
> 
> Bilge

I'd caution about being too hasty to deprecate and remove support for
this feature without understanding the underlying reasons why it has
been used historically, and without providing a better (not just
different) alternative for those use cases, lest an impossible upgrade
path is created.

While the variadic operator should be a 1:1 replacement for using
func_get_args(), is it enough of a benefit to force potentially tens
of thousands of codebases to change when they both accomplish the same
thing? What bad thing happens if PHP continues to support both
methods?

There is already enough friction to upgrade between major versions.
Introducing an optional attribute or syntax allows codebases that care
about signature strictness get that safety, while avoiding a
potentially costly and onerous upgrade for the community.

- Mark


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Ilija Tovilo
On Thu, Apr 4, 2024 at 5:58 PM Tim Düsterhus  wrote:
>
> On 4/4/24 16:36, Pablo Rauzy wrote:
> > I strongly agree in theory, but this could break existing code, and
> > moreover such a proposal was already rejected:
> > https://wiki.php.net/rfc/strict_argcount
>
> The RFC is 9 years old by now. My gut feeling is be that using an actual
> variadic parameter for functions that are variadic is what people do,
> because it makes the function signature much clearer. Actually variadic
> parameters are available since PHP 5.6, which at the time of the
> previous RFC was the newest version. Since then we had two major
> releases, one of which (7.x) is already out of support.
>
> I think it would be reasonable to consider deprecating passing extra
> arguments to a non-variadic function.

IIRC one of the bigger downsides of this change are closure calls that
may provide arguments that the callee does not care about.

https://3v4l.org/0QdoS

```
function filter($array, callable $c) {
$result = [];
foreach ($array as $key => $value) {
if ($c($value, $key)) {
$result[$key] = $value;
}
}
return $result;
}

var_dump(filter(['foo', '', 'bar'], function ($value) {
return strlen($value);
}));

// Internal functions already throw on superfluous args
var_dump(filter(['foo', '', 'bar'], 'strlen'));
```

The user may currently choose to omit the $key parameter of the
closure, as it is never used. In the future, this would throw. We may
decide to create an exemption for such calls, but I'm not sure
replacing one inconsistency with another is a good choice.

Ilija


Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type

2024-04-04 Thread Rowan Tommins [IMSoP]

On 04/04/2024 02:29, Jordan LeDoux wrote:
But when it comes to fixed-precision values, it should follow rules very 
similar to those we discussed in the BCMath thread:


- Addition and subtraction should return a value that is the largest 
scale/precision of any operands in the calculation.
- Division and multiplication should return a value that is the sum of 
the scale/precision of any operands + 2 or a default (perhaps 
configurable) value if the sum is small, to ensure that rounding occurs 
correctly. Near zero, floats have about 12-ish decimal digits of 
accuracy, and will return their full accuracy for example.



I haven't followed the discussion in the other thread, but I'm not sure 
what the use case would be for a "fixed scale decimal" that followed 
those rules.


As mentioned before, the use case I've encountered is money 
calculations, where what people want to fix is the smallest unit of 
account - e.g. €0.01 for practical currency, or €0.0001 for detailed 
accounting / trading.


If I write $total = 1.03_d2; $perPerson = $total / 2; I want a result of 
0.51_d2 or 0.52_d2 - that's why I specified a scale of 2 in the first place.


If I want an accurate result of 0.515_d3, I would just specify 1.03_d, 
since the scale hasn't had any effect on the result.


If I want a lossless split into [0.51_d2, 0.52_d2] I still need a 
function to exist somewhere, whether you spell that $total->split(2), or 
decimal_split($total, 2), etc. So it seems safer to also have 
$total->div(2, Round::DOWN) or decimal_div($total, 2, Round::DOWN) and 
have $total / 2 give an error.


Possibly, it could only error if the result doesn't fit in the scale, so 
that this would be fine: $total = 11.00_d2; $perPerson = $total / 2; 
assert($perPerson === 5.50_d2)


Or possibly, it would just be an error to perform division on a fixed 
scale decimal, but allowed on a variable-fixed scale decimal.


Regards,
--
Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Barney Laurance


On 04/04/2024 22:10, Jordan LeDoux wrote:



On Thu, Apr 4, 2024 at 1:59 PM Barney Laurance 
 wrote:


Hi again,

On 27/03/2024 00:40, Saki Takamachi wrote:

Do we also need `toFloat` and `toInt` functions? Seems like using explicit 
functions will be safer than casting.

For toInt I'd expect an exception if the value is outside the range of 
possible ints. For toFloat it might be nice to have a flag
argument to give the developer the choice of having it throw if the value 
is outside the range of floats or return INF or -INF,
or possibly the user should just check for infinite values themselves.

I was thinking about those features too. However, I'm concerned that 
proposing too many features will complicate the RFC and make it difficult to 
get it approved.


Coming back to this point, I think these are basic features that
people would expect to be there - I think I would find just
slightly frustrating to start learning how to use a class like
this and then
find that it doesn't have these functions. Casting and calling
`intval` or `floatval` all feel like slightly awkward workarounds
that shouldn't be needed in a greenfield project. We know that the
string
inside the object is always a numeric string, so it should be
easier to parse it as an int than to parse it as a date or a JSON
document. Code doing the latter should stand out as odd looking.



The class cannot guarantee that it can return a value in the type you 
request however, so the way that is handled would need to be decided. 
The value can easily be outside of the range of an int. Should it 
return a float silently in that case for `toInt()`? What if the value 
is beyond the range of a float? That would be a very rare situation, 
as floats can represent extremely large numbers (with very reduced 
accuracy), but I would expect it to throw an exception if that 
happened. Ideally an exception that I could catch and ignore, since I 
can almost surely deal with that error in most situations.


What about a number that is so small that it can't fit in a float? 
Similar situation, though I expect it would occur slightly more often 
than a number being too large to fit in a float, even though it would 
also be rare.


I think these helper functions belong in the RFC, but they aren't 
quite straightforward, which is what I think Saki was alluding to.




Yes I agree there are subtleties to work out for these functions. I 
don't think there's such a thing as a number to small to fit in a float. 
Converting from decimal to float is always an approximation, sometimes 
the best approximation available as a float will be either 0 or -0.

Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Barney Laurance

On 04/04/2024 01:54, Jordan LeDoux wrote:



On Tue, Apr 2, 2024 at 5:43 PM Saki Takamachi  wrote:


If make a class final, users will not be able to add arbitrary
methods, so I think making each method final. Although it is
possible to completely separate behavior between method and opcode
calculations, this is inconsistent and confusing to users and
should be avoided.


Right, if a class is not final but has only final methods
(including constructor) and no protected properties then it allows
people to extend it but not break any encapsulation or (I think)
impose any more BC requirements on the maintainer (unless we care
about conflicting with method names of child classes when
updating). It lets people just do something a bit like adding
'extension methods' in C#. I like it. People could write e.g.
`$bcChildNumber->isPrime()` instead of
`BcNumberUtils::isPrime($bcNumber)`


Yeah, I suspect the most common child class will be something like 
"Money" that additionally has a parameter denoting what currency the 
value is in, since that is by far the most common use case for 
arbitrary precision math in PHP. Making the calculation methods final 
should do fine in my opinion.


I don't think it will be possible to make a good Money class as a child 
of this. BcNum is a read-only class, so if the constructor of BcNum is 
final then the child class won't be able to take the currency as a 
constructor param, and won't be able to protect the invariant that 
currency must be initialized. If the constructor of BcNum were made 
non-final then BcNum wouldn't be able to protect the invariant of the 
numeric value always being initialized once the constructor has 
returned. And it should be straightforward to make a good money class as 
a composition of BcNum and a currency enum or string.


There's probably not any good use case for a subclass to add properties, 
unless perhaps the subclass developers are willing do do away with some 
of the checks that would normally be done on a value object by the PHP 
runtime to keep it valid (maybe replacing them with static analysis 
checks). But there are lots of reasonable use cases for subclasses to 
add methods, even if they're effectively syntax sugar for static methods 
with a BcNum typed param.


Having just written that I've now checked the behavior of DateTime - see 
https://3v4l.org/5DQZg . The constructor of that isn't final, so a child 
class can replace it with an empty constructor. But if it does that and 
leaves the value uninitialized then it blows up on a call to `format`. 
That's probably not something we should emulate. DateTimeImmutable 
behaves the same way.




Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Bilge

On 04/04/2024 16:57, Tim Düsterhus wrote:
I think it would be reasonable to consider deprecating passing extra 
arguments to a non-variadic function.


This seems like the only reasonable thing to do, to me. If this were the 
case, there should be no need for any new syntax, since we could simply 
deny passing extra arguments in the next major, no?


Bilge


Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Jordan LeDoux
On Thu, Apr 4, 2024 at 1:59 PM Barney Laurance 
wrote:

> Hi again,
>
> On 27/03/2024 00:40, Saki Takamachi wrote:
>
> Do we also need `toFloat` and `toInt` functions? Seems like using explicit 
> functions will be safer than casting.
>
> For toInt I'd expect an exception if the value is outside the range of 
> possible ints. For toFloat it might be nice to have a flag
> argument to give the developer the choice of having it throw if the value is 
> outside the range of floats or return INF or -INF,
> or possibly the user should just check for infinite values themselves.
>
> I was thinking about those features too. However, I'm concerned that 
> proposing too many features will complicate the RFC and make it difficult to 
> get it approved.
>
> Coming back to this point, I think these are basic features that people
> would expect to be there - I think I would find just slightly frustrating
> to start learning how to use a class like this and then
> find that it doesn't have these functions. Casting and calling `intval` or
> `floatval` all feel like slightly awkward workarounds that shouldn't be
> needed in a greenfield project. We know that the string
> inside the object is always a numeric string, so it should be easier to
> parse it as an int than to parse it as a date or a JSON document. Code
> doing the latter should stand out as odd looking.
>
>
>
The class cannot guarantee that it can return a value in the type you
request however, so the way that is handled would need to be decided. The
value can easily be outside of the range of an int. Should it return a
float silently in that case for `toInt()`? What if the value is beyond the
range of a float? That would be a very rare situation, as floats can
represent extremely large numbers (with very reduced accuracy), but I would
expect it to throw an exception if that happened. Ideally an exception that
I could catch and ignore, since I can almost surely deal with that error in
most situations.

What about a number that is so small that it can't fit in a float? Similar
situation, though I expect it would occur slightly more often than a number
being too large to fit in a float, even though it would also be rare.

I think these helper functions belong in the RFC, but they aren't quite
straightforward, which is what I think Saki was alluding to.

Jordan


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Pablo Rauzy

Le 04/04/2024 à 17:57, Tim Düsterhus a écrit :

Hi

On 4/4/24 16:36, Pablo Rauzy wrote:

I strongly agree in theory, but this could break existing code, and
moreover such a proposal was already rejected:
https://wiki.php.net/rfc/strict_argcount


The RFC is 9 years old by now. My gut feeling is be that using an 
actual variadic parameter for functions that are variadic is what 
people do, because it makes the function signature much clearer. 
Actually variadic parameters are available since PHP 5.6, which at the 
time of the previous RFC was the newest version. Since then we had two 
major releases, one of which (7.x) is already out of support.


I think it would be reasonable to consider deprecating passing extra 
arguments to a non-variadic function.


Well, if there is a consensus to agree on that, it would be even better!

Cheers,

--
Pablo


Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Barney Laurance

Hi again,

On 27/03/2024 00:40, Saki Takamachi wrote:

Do we also need `toFloat` and `toInt` functions? Seems like using explicit 
functions will be safer than casting.

For toInt I'd expect an exception if the value is outside the range of possible 
ints. For toFloat it might be nice to have a flag
argument to give the developer the choice of having it throw if the value is 
outside the range of floats or return INF or -INF,
or possibly the user should just check for infinite values themselves.

I was thinking about those features too. However, I'm concerned that proposing 
too many features will complicate the RFC and make it difficult to get it 
approved.


Coming back to this point, I think these are basic features that people 
would expect to be there - I think I would find just slightly 
frustrating to start learning how to use a class like this and then
find that it doesn't have these functions. Casting and calling `intval` 
or `floatval` all feel like slightly awkward workarounds that shouldn't 
be needed in a greenfield project. We know that the string
inside the object is always a numeric string, so it should be easier to 
parse it as an int than to parse it as a date or a JSON document. Code 
doing the latter should stand out as odd looking.




Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Larry Garfield
On Thu, Apr 4, 2024, at 3:49 PM, Tim Düsterhus wrote:
> Hi
>
> On 4/4/24 17:40, Vinicius Dias wrote:
>>> I like this concept, but instead of introducing a new syntax, have you
>>> considered leveraging attributes in the same way that PHP 8.3
>>> introduced #[Override]?
>>>
>>> #[Nonvariadic]
>>> function foo () {}
>>> foo(42); // warning: foo() expects exactly 0 arguments, 1 given
>>>
>>> I think the intent would be clearer and it would avoid introducing a new 
>>> syntax.
>>>
>> 
>> I agree that using an attribute would be better for this case.
>
> I disagree with an attribute being the right choice here. In contrast to 
> #[\Override], this proposal changes the behavior for the *caller* of the 
> function and likely also requires adjustments in child classes when 
> newly introduced in a parent class or interface.
>
> Thus it is part of the function's API and thus should be part of the 
> regular signature and not the attribute-based metadata.
>
> Best regards
> Tim Düsterhus

I would think following the pattern of dynamic properties would make the most 
sense.  Require an opt-in via attribute, with deprecation period.  And possibly 
just remove the functionality at some point in the future.

The core issue here IMO isn't the behavior itself, but the inconsistency.  
C-implemented functions reject extra args.  PHP-implemented functions ignore 
them (modulo variadics).  This is... a total mess that has bitten me more than 
I want to admit.  Normalizing it one way or the other would be a win.

--Larry Garfield


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Tim Düsterhus

Hi

On 4/4/24 16:36, Pablo Rauzy wrote:

I strongly agree in theory, but this could break existing code, and
moreover such a proposal was already rejected:
https://wiki.php.net/rfc/strict_argcount


The RFC is 9 years old by now. My gut feeling is be that using an actual 
variadic parameter for functions that are variadic is what people do, 
because it makes the function signature much clearer. Actually variadic 
parameters are available since PHP 5.6, which at the time of the 
previous RFC was the newest version. Since then we had two major 
releases, one of which (7.x) is already out of support.


I think it would be reasonable to consider deprecating passing extra 
arguments to a non-variadic function.


Best regards
Tim Düsterhus


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Tim Düsterhus

Hi

On 4/4/24 17:40, Vinicius Dias wrote:

I like this concept, but instead of introducing a new syntax, have you
considered leveraging attributes in the same way that PHP 8.3
introduced #[Override]?

#[Nonvariadic]
function foo () {}
foo(42); // warning: foo() expects exactly 0 arguments, 1 given

I think the intent would be clearer and it would avoid introducing a new syntax.



I agree that using an attribute would be better for this case.


I disagree with an attribute being the right choice here. In contrast to 
#[\Override], this proposal changes the behavior for the *caller* of the 
function and likely also requires adjustments in child classes when 
newly introduced in a parent class or interface.


Thus it is part of the function's API and thus should be part of the 
regular signature and not the attribute-based metadata.


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] [Discussion] Deprecate GET/POST sessions

2024-04-04 Thread Claude Pache



> Le 4 avr. 2024 à 01:08, Kamil Tekiela  a écrit :
> 
> If there are no more comments, I would like to put this RFC to vote in
> the next two days.


Hi,

1. In session_start(), it is possible to override ini settings like that:

```php
session_start([ 'use_cookies' => '1', 'use_only_cookies' => '1', 
'referer_check' => '' ]);
```

The relevant options should also be deprecated in that context.

2. A clarification: Suppose that I have  `session.use_only_cookie = 1` in my 
ini file (no deprecation warning), and I call 
`ini_set("session.use_only_cookie", "1")` in my code (no-op). Will the 
`ini_set(...)` invocation trigger a deprecation warning?

—Claude

Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Vinicius Dias
> I like this concept, but instead of introducing a new syntax, have you
> considered leveraging attributes in the same way that PHP 8.3
> introduced #[Override]?
>
> #[Nonvariadic]
> function foo () {}
> foo(42); // warning: foo() expects exactly 0 arguments, 1 given
>
> I think the intent would be clearer and it would avoid introducing a new 
> syntax.
>

I agree that using an attribute would be better for this case.


> I would personally prefer the void syntax, but that's really because 
> attributes look odd to me due to lack of habits (and also because it avoids 
> an additional line of code… which is probably not a solid enough reason when 
> it comes to language design decisions).


As a reader of the code, having the attribute is much more clear to me
than having something that looks like an argument.
Also, with attributes, the code is backwards-compatible, i.e., I can
add the attribute to my code without any errors or warnings even if I
don't use the latest version of PHP, and even in those cases, IDEs
could still help me.


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Claude Pache

> Le 4 avr. 2024 à 15:10, Kamil Tekiela  a écrit :
> 
> Why is passing extra arguments a problem at all?

In a parallel perfect and boring world, it is not a problem. In our world, 
disallowing extra arguments have two advantages:

* catching bugs;

* allowing to add new optional parameters to an existing function without 
fearing to break existing code.

—Claude



Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Pablo Rauzy

Le 04/04/2024 à 16:29, Claude Pache a écrit :

Le 4 avr. 2024 à 15:03, Mark Trapp  a écrit :

On Thu, Apr 4, 2024 at 5:43 AM Pablo Rauzy  wrote:

I like this concept, but instead of introducing a new syntax, have you
considered leveraging attributes in the same way that PHP 8.3
introduced #[Override]?

#[Nonvariadic]
function foo () {}
foo(42); // warning: foo() expects exactly 0 arguments, 1 given

I think the intent would be clearer and it would avoid introducing a new syntax.


Indeed, except that I think it should be better to have *by default* the same 
behaviour between built-in functions and user-defined functions:

```php
function foo() { }

foo(42);
// in PHP 8.x: Deprecated: foo() expects expects exactly 0 arguments, 1 given
// in PHP 9: Fatal error: foo() expects expects exactly 0 arguments, 1 given
```

and, in case you want a variadic function:

```php
#[Variadic]
function foo() { }
```

Alternatively, we don’t really need to introduce a new attribute, because one 
can just write:

```php
function foo(...$args) { }
```


—Claude


Hello Claude,

I strongly agree in theory, but this could break existing code, and 
moreover such a proposal was already rejected:

https://wiki.php.net/rfc/strict_argcount

Regards,

--
Pablo


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Claude Pache



> Le 4 avr. 2024 à 15:03, Mark Trapp  a écrit :
> 
> On Thu, Apr 4, 2024 at 5:43 AM Pablo Rauzy  wrote:
> 
> I like this concept, but instead of introducing a new syntax, have you
> considered leveraging attributes in the same way that PHP 8.3
> introduced #[Override]?
> 
> #[Nonvariadic]
> function foo () {}
> foo(42); // warning: foo() expects exactly 0 arguments, 1 given
> 
> I think the intent would be clearer and it would avoid introducing a new 
> syntax.
> 

Indeed, except that I think it should be better to have *by default* the same 
behaviour between built-in functions and user-defined functions:

```php
function foo() { }

foo(42);
// in PHP 8.x: Deprecated: foo() expects expects exactly 0 arguments, 1 given
// in PHP 9: Fatal error: foo() expects expects exactly 0 arguments, 1 given
```

and, in case you want a variadic function:

```php
#[Variadic]
function foo() { }
```

Alternatively, we don’t really need to introduce a new attribute, because one 
can just write:

```php
function foo(...$args) { }
```


—Claude


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Pablo Rauzy

Le 04/04/2024 à 15:03, Mark Trapp a écrit :

On Thu, Apr 4, 2024 at 5:43 AM Pablo Rauzy  wrote:

Hello all,

First, I'm new here, so let me start by warmly thanking everyone
involved in PHP development. I've started programming 22 years using it
as my first programming language, and still enjoy using it a lot :).

I've read the rfc:howto and the first step is to get feedback from this
mailing list about the intended proposal, so here is a short description
of what I have in mind:

Currently PHP does not warn when user-defined functions are called with
too many arguments. Changing this could break a lot of existing code,
but it would also be a very good verification to catch potential bugs.

I have an idea allowing this feature without breaking any existing code:
using the void keyword in a function arguments list to strictly limit
the number of arguments a user-defined function can receive, stopping it
on the void, which could only be used once and in the last position.

Currently, void is a return-only type so it isn't used in arguments list
in existing code, so I believe the new behavior would only concern newly
written code that explicitly wants to take advantage of this feature.

A few examples using functions (the same would apply to class methods,
callbacks, closures, etc.) :

  function foo (void) {}
  foo(42); // warning: foo() expects exactly 0 arguments, 1 given

  function bar ($a, $b, void) {}
  bar(1, 2, 3); // warning: bar() expects exactly 2 arguments, 3 given

  function baz ($a, $b=null, void) {}
  baz(1, 2, 3); // warning: baz() expects at most 2 arguments, 3 given

I have no knowledge of the PHP internals: would that be feasible without
breaking things? And, as importantly, would it be a welcome change?

Cheers,

Hi Pablo,

I like this concept, but instead of introducing a new syntax, have you
considered leveraging attributes in the same way that PHP 8.3
introduced #[Override]?

#[Nonvariadic]
function foo () {}
foo(42); // warning: foo() expects exactly 0 arguments, 1 given

I think the intent would be clearer and it would avoid introducing a new syntax.


Hello Mark,

I never used attributes so I didn't even think of it, but that would 
work too, yes :).


I would personally prefer the void syntax, but that's really because 
attributes look odd to me due to lack of habits (and also because it 
avoids an additional line of code… which is probably not a solid enough 
reason when it comes to language design decisions).


Regards,

--
Pablo


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Pablo Rauzy

Hello Kamil,

Le 04/04/2024 à 15:10, Kamil Tekiela a écrit :

Interesting proposal, but immediately I have two questions:
1. Why is passing extra arguments a problem at all? Is generating a
warning a good idea? If you would like to introduce a new syntax to
enforce non-variadic functions, shouldn't it be a runtime error then?
Generating a warning makes it look like the new syntax still allows
for variadic arguments, but passing the extra arguments now is somehow
a bad thing to do.
2. How does this affect func_get_args()? Will the function stop
working or continue working as before?


1. Indeed, if implemented it should be an error rather than a warning, 
you're right.


2. I don't see why func_get_args() should work differently, but that 
maybe my lack of knowledge of the internals of PHP. In any case I think 
it would be better if it worked the same.


Regards,

--
Pablo


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Kamil Tekiela
Hi Pablo,

Interesting proposal, but immediately I have two questions:
1. Why is passing extra arguments a problem at all? Is generating a
warning a good idea? If you would like to introduce a new syntax to
enforce non-variadic functions, shouldn't it be a runtime error then?
Generating a warning makes it look like the new syntax still allows
for variadic arguments, but passing the extra arguments now is somehow
a bad thing to do.
2. How does this affect func_get_args()? Will the function stop
working or continue working as before?

Regards,
Kamil


Re: [PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Mark Trapp
On Thu, Apr 4, 2024 at 5:43 AM Pablo Rauzy  wrote:
>
> Hello all,
>
> First, I'm new here, so let me start by warmly thanking everyone
> involved in PHP development. I've started programming 22 years using it
> as my first programming language, and still enjoy using it a lot :).
>
> I've read the rfc:howto and the first step is to get feedback from this
> mailing list about the intended proposal, so here is a short description
> of what I have in mind:
>
> Currently PHP does not warn when user-defined functions are called with
> too many arguments. Changing this could break a lot of existing code,
> but it would also be a very good verification to catch potential bugs.
>
> I have an idea allowing this feature without breaking any existing code:
> using the void keyword in a function arguments list to strictly limit
> the number of arguments a user-defined function can receive, stopping it
> on the void, which could only be used once and in the last position.
>
> Currently, void is a return-only type so it isn't used in arguments list
> in existing code, so I believe the new behavior would only concern newly
> written code that explicitly wants to take advantage of this feature.
>
> A few examples using functions (the same would apply to class methods,
> callbacks, closures, etc.) :
>
>  function foo (void) {}
>  foo(42); // warning: foo() expects exactly 0 arguments, 1 given
>
>  function bar ($a, $b, void) {}
>  bar(1, 2, 3); // warning: bar() expects exactly 2 arguments, 3 given
>
>  function baz ($a, $b=null, void) {}
>  baz(1, 2, 3); // warning: baz() expects at most 2 arguments, 3 given
>
> I have no knowledge of the PHP internals: would that be feasible without
> breaking things? And, as importantly, would it be a welcome change?
>
> Cheers,
>
> --
> Pablo

Hi Pablo,

I like this concept, but instead of introducing a new syntax, have you
considered leveraging attributes in the same way that PHP 8.3
introduced #[Override]?

#[Nonvariadic]
function foo () {}
foo(42); // warning: foo() expects exactly 0 arguments, 1 given

I think the intent would be clearer and it would avoid introducing a new syntax.

- Mark


[PHP-DEV] RFC idea: using the void type to control maximum arity of user-defined functions

2024-04-04 Thread Pablo Rauzy

Hello all,

First, I'm new here, so let me start by warmly thanking everyone 
involved in PHP development. I've started programming 22 years using it 
as my first programming language, and still enjoy using it a lot :).


I've read the rfc:howto and the first step is to get feedback from this 
mailing list about the intended proposal, so here is a short description 
of what I have in mind:


Currently PHP does not warn when user-defined functions are called with 
too many arguments. Changing this could break a lot of existing code, 
but it would also be a very good verification to catch potential bugs.


I have an idea allowing this feature without breaking any existing code: 
using the void keyword in a function arguments list to strictly limit 
the number of arguments a user-defined function can receive, stopping it 
on the void, which could only be used once and in the last position.


Currently, void is a return-only type so it isn't used in arguments list 
in existing code, so I believe the new behavior would only concern newly 
written code that explicitly wants to take advantage of this feature.


A few examples using functions (the same would apply to class methods, 
callbacks, closures, etc.) :


    function foo (void) {}
    foo(42); // warning: foo() expects exactly 0 arguments, 1 given

    function bar ($a, $b, void) {}
    bar(1, 2, 3); // warning: bar() expects exactly 2 arguments, 3 given

    function baz ($a, $b=null, void) {}
    baz(1, 2, 3); // warning: baz() expects at most 2 arguments, 3 given

I have no knowledge of the PHP internals: would that be feasible without 
breaking things? And, as importantly, would it be a welcome change?


Cheers,

--
Pablo


Re: [PHP-DEV] [RFC][Concept] Data classes (a.k.a. structs)

2024-04-04 Thread Kévin Dunglas
Data classes will be a very useful addition to "API Platform".

API Platform is a "resource-oriented" framework that strongly encourages
the use of "data-only" classes:
we use PHP classes both as a specification language to document the public
shape of web APIs (like an OpenAPI specification, but written in PHP
instead of JSON or YAML),
and as Data Transfer Objects containing the data to be serialized into JSON
(read), or the JSON payload deserialized into PHP objects (write).

Being able to encourage users to use structs (that's what we already call
this type of behavior-less class in our workshops) for these objects will
help us a lot.

Kévin


Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Saki Takamachi
Hi Chris,

> Looks very promising!
> 
> The default value for rounding is PHP_ROUND_TOWARD_ZERO. Is this because it 
> is the same as the BCMath functions for consistency only or do you expect 
> this to be the most used rounding mode?
> I didn't find any discussion about this choice, sorry if I missed it.

Thank you!

Yes, you're right, I've made it match the existing behavior of BCMath. And rest 
assured, there has been no discussion about that yet.

I haven't thought about it in detail yet, but maybe there are other ideal 
initial values?

Regards.

Saki

Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Christian Schneider
Am 04.04.2024 um 08:29 schrieb Saki Takamachi :
> I added some examples, corrected incorrect explanations, etc. Now that the 
> specifications have been fairly finalized and the RFC has been clarified, I 
> would like everyone to check it out again.
> 
> https://wiki.php.net/rfc/support_object_type_in_bcmath

Looks very promising!

The default value for rounding is PHP_ROUND_TOWARD_ZERO. Is this because it is 
the same as the BCMath functions for consistency only or do you expect this to 
be the most used rounding mode?
I didn't find any discussion about this choice, sorry if I missed it.

Regards,
- Chris


Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath

2024-04-04 Thread Saki Takamachi
Hi,

I added some examples, corrected incorrect explanations, etc. Now that the 
specifications have been fairly finalized and the RFC has been clarified, I 
would like everyone to check it out again.

https://wiki.php.net/rfc/support_object_type_in_bcmath

Regards.

Saki