Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath
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
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
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)
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
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
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
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
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
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
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
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
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
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
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
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
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
> 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
> 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
> 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
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
> 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
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
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
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
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
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)
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
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
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
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