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

2024-03-17 Thread Alexander Pravdin
Sorry for the so late reply, but I would like to continue the
discussion on this topic.


On Tue, Dec 12, 2023 at 10:04 PM G. P. B.  wrote:

>> I didn't know that the strict types directive was a mistake. My intention is 
>> to be able to write clean all-decimal units of code and not break the 
>> backward compatibility. The old code should work as it was before. At the 
>> same time, there are use cases when the whole class/project should be 
>> written with decimals only. As a user, I want to do that without complex 
>> language structures and excessive typehints or explicit conversions. The 
>> all-decimal code  should be as clean as it is now with floats. This is why I 
>> proposed this directive. Can you suggest something better to achieve the 
>> same?
>
>
> The issue is that I don't think having arbitrary precision decimals as a core 
> language feature is a necessity compared to rational types.
> A cast from rational to float wouldn't produce a large round trip, whereas 
> trying to figure out arbitrary precision is more difficult.
> But in any case, having a declare/INI or whatever that changes the behaviour 
> of the engine/language is not a good design choice.

How can we introduce the ability to write user code in default
decimals and at the same time keep the old way of working as it was
before, to not introduce any troubles into the existing code and not
introduce performance issues? As a user, I would like to have a
choice. When I need speed and I don't care about rounding errors, I
will use default floats. When I need precise calculations and can
sacrifice some performance, I will use default decimals. And I would
like to be able to switch between these modes selectively, not
app-wide. Just give me a choice and inform me in the documentation
about the differences and pros/cons of both types.


I'm not in the context of the core team plans regarding "strict
types". Could you share some details here? What is the current plan
regarding it? To make strict types on by default eventually? Or
something else?



>> If you can suggest a better way of working with fractional numbers - please 
>> do :) But IMO limiting the language by 64 bits is not a good way. It is more 
>> easy to go over the limit than you may think :) Especially in some 
>> intermediary values while performing complex calculations. I could be wrong, 
>> but fractional numbers limited to 64 bits sound like a bandaid. The language 
>> will tell users "hey, you can do something general, but if you want 
>> something else please don't use me at all or involve bandaids with 
>> extensions". My key point is not only to allow working with decimals, but 
>> also to make all the alternatives useless, cover their functionality by 
>> builtin tools, to free users from thinking about workarounds and bandaids. 
>> From my POV, introducing a new decimal type that does not cover the 
>> GMP/bcmath/ext-decimal functionality is pointless and a waste of time.
>
>
> Again, the use cases for arbitrary precision numbers seems rather limited, 
> and having this as an extension does not seem problematic at all.
> My current issue is that there is no way to represent "small" numbers such as 
> 0.1 or 5.8 exactly.
> Arbitrary precision is a totally different ballpark, be that for integers 
> and/or fractional values and makes everything slow, just look at Python who 
> is *finally* investing time and money to make the most common numbers (those 
> that fit in a machine word) not be abysmally slow.

Honestly speaking, my current pain point is that I need to work with
precise money calculations in business automation and accounting
fields. I would like to see a good tool in the PHP language to do
that. As an engineer, I understand that it should be fast enough. I
suggested mpdecimal as a good enough option. If you could suggest
something else that would fit the majority of user needs, I'm totally
for it.



>> How quickly you would be able to read something like this: 
>> gmp_add(gmp_mul(gmp_div(gmp_sub($value, $add), $value2, $factor, 
>> gmp_sin($value3), gmp_intval($value))) ?
>>
>> This absence of intuitive readability makes the development and support 
>> difficult and it's better to choose another language. This is what I want to 
>> change and make PHP powerful enough for this kind of applications.
>
> GMP supports operator overloading, so you do not need to write this, and as 
> far as I see, ext/decimal *also* supports operator overloading so you can 
> just write it using the normal arithmetic operations.
> Moreover, it supports type casts so you can just do (int) $GMP instead of 
> gmp_intval($GMP);
> And it also supports using the comparisons operatos on it instead of using 
> gmp_cmp()
>
> The only thing that is, currently, not possible to do is a cast _to_ GMP 
> using (GMP), but maybe that's something that could be added to the engine for 
> internal objects, but I'm not sure about this.

If GMP can be converted to a scalar builtin language 

Re: [PHP-DEV] Supporting object types in BCMath

2024-03-17 Thread Jordan LeDoux
On Sun, Mar 17, 2024 at 5:05 PM Saki Takamachi  wrote:

> Hi Jordan,
>
> > Using a BCNum inside a loop is the use case, where every loop would
> result in memory allocation for a new object, as well as the overhead of
> the constructor, etc.
> >
> > Granted, only people who REALLY know what they are doing should be doing
> this. Though my library which essentially IS a wrapped for BCMath that is
> upgradeable if you install other extensions (like ext-decimal) does support
> both, I suggest using primarily immutables in my docs.
> >
> > That said, the C library itself for BCMath is insanely inefficient as
> far as arbitrary precision math goes, so I would suggest that people don't
> get their hopes up too much on the performance front.
>
> I just sent an email, and you're right about performance. Therefore, the
> point of this proposal seems to be simply to improve convenience.
>
> Regards.
>
> Saki


I've done a lot of performance tuning on my arbitrary precision library,
and will simply state for everyone here that I think the amount of
development effort involved in improving performance of the BCMath library
is almost certainly going to see a return on your effort that is not worth
it. There have been discussions over the last year on possibly working on
bundling a new arbitrary precision C library and providing something that
is performant enough to be generally useful in core, but that's not even at
the RFC stage, just investigations.

I wouldn't say that improving BCMath is a waste of time, but there is also
probably lower hanging fruit once you get past things like Saki has here.
DevEx improvements.

Jordan


Re: [PHP-DEV] Supporting object types in BCMath

2024-03-17 Thread Saki Takamachi
Hi Jordan,

> Using a BCNum inside a loop is the use case, where every loop would result in 
> memory allocation for a new object, as well as the overhead of the 
> constructor, etc.
> 
> Granted, only people who REALLY know what they are doing should be doing 
> this. Though my library which essentially IS a wrapped for BCMath that is 
> upgradeable if you install other extensions (like ext-decimal) does support 
> both, I suggest using primarily immutables in my docs.
> 
> That said, the C library itself for BCMath is insanely inefficient as far as 
> arbitrary precision math goes, so I would suggest that people don't get their 
> hopes up too much on the performance front.

I just sent an email, and you're right about performance. Therefore, the point 
of this proposal seems to be simply to improve convenience.

Regards.

Saki

Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2

2024-03-17 Thread Ilija Tovilo
Hi Rowan

On Sun, Mar 17, 2024 at 3:41 PM Rowan Tommins [IMSoP]
 wrote:
>
> The remaining difference I can see in the current RFC which seems to be
> unnecessary is that combining  with set is only allowed on virtual
> properties. Although it may be "virtual" in the strict sense, any 
> hook must actually be referring to some value stored somewhere - that
> might be a backed property, another field on the current class, a
> property of some other object, etc:
>
> public int $foo {  => $this->foo; set { $this->foo = $value; } }
>
> public int $bar {  => $this->_bar; set { $this->_bar = $value; } }
>
> public int $baz {  => $this->delegatedObj->baz; set {
> $this->delegatedObj->baz = $value; } }
>
> This sentence from the RFC applies equally to all three of these examples:
>
>  > That is because any attempted modification of the value by reference
> would bypass a |set| hook, if one is defined.
>
> I suggest that we either trust the user to understand that that will
> happen, and allow combining  and set on any property; or we do not
> trust them, and forbid it on any property.

I'm indeed afraid that people will blindly make their array properties
by-reference, without understanding the implications. Allowing
by-reference behavior for virtual read/write properties is a tradeoff,
for cases where it  may be necessary. Exposing private properties
by-reference is already possible outside of hooks
(https://3v4l.org/VNhf7), that's not something we can prevent for
secondary backing properties. However, we can at least make sure that
a reference to the baking value of a hooked property doesn't escape.

I realize this is somewhat inconsistent, but I believe it is
reasonable. If you want to expose the underlying property
by-reference, you need to jump through some additional hoops.

> > Apart from the things already mentioned, it's unclear to me whether,
> > with such `set;` declarations, a `get`-only backed property should
> > even be legal. With the complete absence of a write operation, the
> > assignment within the `set` itself would fail. To make this work, the
> > absence of `set;` would need to mean something like "writable, but
> > only within another hook", which introduces yet another form of
> > asymmetric visibility.
>
> Any write inside the get hook already by-passes the set hook and refers
> to the underlying property, so there would be no need for any default
> set behaviour other than throwing an error.
>
> It's not likely to be a common scenario, but the below works with the
> current implementation https://3v4l.org/t7qhR/rfc#vrfc.property-hooks
>
> class Example {
>  public int $nextNumber {
>  get {
>  $this->nextNumber ??= 0;
>  return $this->nextNumber++;
>  }
>  // Mimic the current behaviour of a virtual property:
> https://3v4l.org/cAfAI/rfc#vrfc.property-hooks
>  set => throw new Error('Property Example::$nextNumber is
> read-only');
>  }
> }

Again, it depends on how you think about it. As you have argued, for a
get-only property, the backing value should not be writable without an
explicit `set;` declaration. You can interpret `set;` as an
auto-generated hook, or as a marker that indicates that the backing
value is accessible without a hook. As mentioned in my previous
e-mail, auto-generated hooks is something we'd really like to avoid.
So, if the absence of `set;` means that the backing value is not
writable, the hook itself must be exempt from this rule.

Another thing to consider: The current implementation inherits the
backing value and all hooks from its parent. If the suggestion is to
add an explicit `set;` declaration to make it more obvious that the
property is writable, how does this help overridden properties?

```php
class P {
public $prop {
get => strtolower($this->prop);
set;
}
}

class C extends P {
public $prop {
get => strtoupper(parent::$prop::get());
}
}
```

Even though `P::$prop` signals that it is writable, there is no such
indication in `C::$prop`. You may suggest to also add `set;` to the
child, but then what if the parent adds a custom implementation for
`set;`?

```php
class P {
public $prop {
get => strtolower($this->prop);
set {
echo $value, "\n";
$this->prop = $value;
}
}
}

class C extends P {
public $prop {
get => strtoupper(parent::$prop::get());
set;
}
}
```

The meaning for `set;` is no longer clear. Does it mean that there's a
generated hook that accesses the backing field? Does it mean that the
backing field is accessible without a hook? Or does it mean that it
accesses the parent hook? The truth is, with inheritance there's no
way to look at the property declaration and fully understand what's
going on, unless all hooks must be spelled out for the sake of clarity
(e.g. `get => parent::$prop::get()`).

> We are already allowing more than Kotlin by letting hooks call out to a

Re: [PHP-DEV] Supporting object types in BCMath

2024-03-17 Thread Saki Takamachi
Hi,

I created a prototype, although it's pretty rough. It can overload operators 
and calculate not only between `BcNum` but also between `BcNum` and `int` or 
`string`.
https://github.com/php/php-src/pull/13741

I compared the execution times.

Test code:
```


Re: [PHP-DEV] Supporting object types in BCMath

2024-03-17 Thread Jordan LeDoux
On Sat, Mar 16, 2024 at 8:39 AM Saki Takamachi  wrote:

> Hi Barney,
>
> Thanks, that's what I was starting to worry about too. It seems like a
> good idea to support only immutability, as you say earlier in your proposal.
>
> Regards.
>
> Saki


Using a BCNum inside a loop is the use case, where every loop would result
in memory allocation for a new object, as well as the overhead of the
constructor, etc.

Granted, only people who REALLY know what they are doing should be doing
this. Though my library which essentially IS a wrapped for BCMath that is
upgradeable if you install other extensions (like ext-decimal) does support
both, I suggest using primarily immutables in my docs.

That said, the C library itself for BCMath is insanely inefficient as far
as arbitrary precision math goes, so I would suggest that people don't get
their hopes up too much on the performance front.

Jordan


Re: [PHP-DEV] [RFC][Discussion] Raising zero to the power of negative number

2024-03-17 Thread Jorg Sowa
Thank you Marc for your opinion. It makes sense to me that we should have
the possibility to mimic the IEEE-754 standard, thus we should have `fpow`
function as well. I have updated the RFC and would like to start the voting
if there are no new comments.

Kind regards,
Jorg Sowa


Re: [PHP-DEV] Re: [RFC] [Discussion] [VOTE] Rounding Integers as int

2024-03-17 Thread Vincent Langlet
Hi,

IMHO, the more meaningful cases of the RFC are missing :

round(float, precision: >= 0): int|float // only cast to float for int overflow
ceil(float): int|float // only cast to float for int overflow
floor(float): int|float // only cast to float for int overflow

Calling ceil or floor on integer is meaningless, because it will return the
same value.
The RFC should be "Prefer int as return value when possible".

Le dim. 17 mars 2024 à 15:00, Bob Weinand  a écrit :

> On 17.3.2024 13:23:04, Marc Bennewitz wrote:
> > Hello internals,
> >
> > I have opened the vote for the "Rounding Integers as int" RFC:
> > https://wiki.php.net/rfc/integer-rounding
> >
> > Do to Easter weekend the vote will run for two weeks and two days
> > until Tue the 2nd of April 2024.
> >
> > Best regards,
> >
> > Marc Bennewitz
>
> Hey Marc,
>
> I've voted no; it should be just changed without any force_float
> parameter. Just always return int when possible (and the input was int).
> If users wish to have the old behaviour, they should just explicitly
> cast via (float).
>
> The effective BC break of that would be quite small if some things which
> return float today now would return int. I cannot imagine many cases
> where this would actually be unwanted. And as said, explicit (float)
> casts are always possible.
>
> I also dislike force_float, as it cannot just be added to a function in
> any code which shall be backwards compatible to 8.3 and older. It would
> just emit Uncaught Error: Unknown named parameter $force_float.
>
> Bob
>


Re: [PHP-DEV] [Pre-RFC] Improve language coherence for the behaviour of offsets and containers

2024-03-17 Thread Rowan Tommins [IMSoP]

On 11/03/2024 12:52, Gina P. Banyard wrote:

I would like to get some initial feedback on an RFC I've been working on for 
the last 5–6 months.
The RFC attempts to explain, and most importantly, improve the semantics around 
$container[$offset] as PHP is currently widely inconsistent.

[...]

RFC: 
https://github.com/Girgias/php-rfcs/blob/master/container-offset-behaviour.md



Hi Gina,

I've just read through this thoroughly, and am simultaneously impressed 
with your investigation, and amazed at how many inconsistencies you found.



I think the proposed granular interfaces absolutely make sense, given 
the different uses people have for such offsets. My only hesitation is 
that if you want "everything", things become quite verbose:


class Foo implements DimensionFetchable, DimensionWritable, 
FetchAppendable, DimensionUnsettable { ... }


function 
bar(DimensionFetchable 
$container) { ... }


Unfortunately, I can't think of an easy solution to this without some 
form of type aliases.



As an experiment, I tried writing a variation of Python's "defaultdict" 
[1] using all the new hooks (without actually testing it against any 
implementation). Here's what I came up with: 
https://gist.github.com/IMSoP/fbd60c5379ccefcab6c5af25eacc259b


Most of it is straight-forward, but a couple of things stood out:

* Separating offsetFetch from offsetGet is really useful, because we can 
avoid "auto-vivifying" a key that's only been read, never updated. In 
other words, isset($foo['a']) can remain false after running 
var_dump($foo['a']), but $foo['a']++ should still work.


* The fetchAppend hook is quite confusing to implement, because it's 
used in a few subtly different scenarios. For instance, if it's actually 
$container[][$offset] = $value there is an implicit requirement that 
fetchAppend should return array|DimensionWritable, but presumably that 
has to be enforced after fetchAppend has returned. I'm not sure if 
there's anything that can be improved here; it probably just needs some 
examples in the user manual.


[1] 
https://docs.python.org/3/library/collections.html#collections.defaultdict



Over all, I think this is a really great proposal, and hope it proceeds 
smoothly.


Regards,

--
Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC[ Property accessor hooks, take 2

2024-03-17 Thread Rowan Tommins [IMSoP]

On 17/03/2024 00:01, Ilija Tovilo wrote:

For clarity, you are asking for a way to make the "virtualness" of
properties more explicit, correct?



Either more explicit, or less important: the less often the user needs 
to know whether a property is virtual, the less it matters how easily 
they can find out.





Please let me know if
you are aware of any other potentially non-intuitive cases.



I agree that while they may not be immediately obvious to the user, most 
of the distinctions do make sense once you think about them.


The remaining difference I can see in the current RFC which seems to be 
unnecessary is that combining  with set is only allowed on virtual 
properties. Although it may be "virtual" in the strict sense, any  
hook must actually be referring to some value stored somewhere - that 
might be a backed property, another field on the current class, a 
property of some other object, etc:


public int $foo {  => $this->foo; set { $this->foo = $value; } }

public int $bar {  => $this->_bar; set { $this->_bar = $value; } }

public int $baz {  => $this->delegatedObj->baz; set { 
$this->delegatedObj->baz = $value; } }


This sentence from the RFC applies equally to all three of these examples:

> That is because any attempted modification of the value by reference 
would bypass a |set| hook, if one is defined.


I suggest that we either trust the user to understand that that will 
happen, and allow combining  and set on any property; or we do not 
trust them, and forbid it on any property.





Apart from the things already mentioned, it's unclear to me whether,
with such `set;` declarations, a `get`-only backed property should
even be legal. With the complete absence of a write operation, the
assignment within the `set` itself would fail. To make this work, the
absence of `set;` would need to mean something like "writable, but
only within another hook", which introduces yet another form of
asymmetric visibility.



Any write inside the get hook already by-passes the set hook and refers 
to the underlying property, so there would be no need for any default 
set behaviour other than throwing an error.


It's not likely to be a common scenario, but the below works with the 
current implementation https://3v4l.org/t7qhR/rfc#vrfc.property-hooks


class Example {
    public int $nextNumber {
    get {
    $this->nextNumber ??= 0;
    return $this->nextNumber++;
    }
    // Mimic the current behaviour of a virtual property: 
https://3v4l.org/cAfAI/rfc#vrfc.property-hooks
    set => throw new Error('Property Example::$nextNumber is 
read-only');

    }
}




Fair enough. 1 and 2 are reasons why we added the `$field` macro as an
alternative syntax in the original draft. I don't quite understand
point 3. In Kotlin, `field` is only usable within its associated hook.
Other languages I'm aware of do not provide a way to access the
backing value directly, neither inside nor outside the accessor.



We are already allowing more than Kotlin by letting hooks call out to a 
method, and have that method refer back to the raw value. 
Hypothetically, we could allow *any* method to access it, using some 
syntax like $this->foo::raw. As a spectrum from least access to most access:


1) $field - accessible only in the lexical scope of the hook

2) $this->foo - accessible in the dynamic scope of the hook, e.g. a hook 
calling $this->doSomething(__PROPERTY__);


3) $this->foo::raw - accessible anywhere in the class, e.g. a public 
clearAll() method by-passing hooks


Whichever we provide for backed properties, option 3 is available for 
virtual properties anyway, and common with __get/__set: store a value in 
a private property, and have a public hooked property providing access 
to it.


I understand now that option 2 fits most easily with the implementation, 
and with decisions around inheritance and upgrade of existing code; but 
the other options do have their advantages from a user's point of view.





I personally do not feel strongly about whether asymmetric types make
it into the initial implementation. Larry does, however, and I think
it is not fair to exclude them without providing any concrete reasons
not to. I will spend time in the following days cleaning up tests, and
I will try my best to try to break asymmetric types. If I (or anybody
else) can't find a way to do so, I don't see a reason to remove them.



My concern is more about the external impact of what is effectively a 
change to the type system of the language: will IDEs give correct 
feedback to users about which assignments are legal? will tools like 
PhpStan and Psalm require complex changes to analyse code using such 
properties? will we be prevented from adding some optimisation to 
OpCache because these properties break some otherwise safe assumption?


Maybe I'm being over-cautious, but those are the kinds of questions I 
would expect to come up if this feature had its own RFC.


Regards,

--
Rowan 

[PHP-DEV] Re: [RFC] [Discussion] [VOTE] Rounding Integers as int

2024-03-17 Thread Bob Weinand

On 17.3.2024 13:23:04, Marc Bennewitz wrote:

Hello internals,

I have opened the vote for the "Rounding Integers as int" RFC:
https://wiki.php.net/rfc/integer-rounding

Do to Easter weekend the vote will run for two weeks and two days 
until Tue the 2nd of April 2024.


Best regards,

Marc Bennewitz


Hey Marc,

I've voted no; it should be just changed without any force_float 
parameter. Just always return int when possible (and the input was int).
If users wish to have the old behaviour, they should just explicitly 
cast via (float).


The effective BC break of that would be quite small if some things which 
return float today now would return int. I cannot imagine many cases 
where this would actually be unwanted. And as said, explicit (float) 
casts are always possible.


I also dislike force_float, as it cannot just be added to a function in 
any code which shall be backwards compatible to 8.3 and older. It would 
just emit Uncaught Error: Unknown named parameter $force_float.


Bob


Re: [PHP-DEV] Re: [RFC] [Discussion] [VOTE] Rounding Integers as int

2024-03-17 Thread Marc Bennewitz


On 17.03.24 14:10, Tim Düsterhus wrote:

Hi

On 3/17/24 13:23, Marc Bennewitz wrote:

I have opened the vote for the "Rounding Integers as int" RFC:
https://wiki.php.net/rfc/integer-rounding


Please also update the Status within the RFC itself and move it to the 
correct section in the RFC overview at: https://wiki.php.net/rfc


Thank you for the reminder. Updated the status and moved in correct 
section now.





Best regards
Tim Düsterhus



OpenPGP_0x3936ABF753BC88CE.asc
Description: OpenPGP public key


OpenPGP_signature.asc
Description: OpenPGP digital signature


[PHP-DEV] Re: [RFC] [Discussion] [VOTE] Rounding Integers as int

2024-03-17 Thread Tim Düsterhus

Hi

On 3/17/24 13:23, Marc Bennewitz wrote:

I have opened the vote for the "Rounding Integers as int" RFC:
https://wiki.php.net/rfc/integer-rounding


Please also update the Status within the RFC itself and move it to the 
correct section in the RFC overview at: https://wiki.php.net/rfc


Best regards
Tim Düsterhus


[PHP-DEV] [RFC] [Discussion] [VOTE] Rounding Integers as int

2024-03-17 Thread Marc Bennewitz

Hello internals,

I have opened the vote for the "Rounding Integers as int" RFC:
https://wiki.php.net/rfc/integer-rounding

Do to Easter weekend the vote will run for two weeks and two days until Tue the 
2nd of April 2024.

Best regards,

Marc Bennewitz



OpenPGP_0x3936ABF753BC88CE.asc
Description: OpenPGP public key


OpenPGP_signature.asc
Description: OpenPGP digital signature