Here is a typical billing example which uses exceptions:
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
addVat('apples');
function addVat($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument 1 passed to '.FUNCTION.' must be of the type int|float, '.gettype($amount).' given');
}
return round($amount*1.19, 2);
}
Instead of multiple strict scalar hints (e.g. function addVat(int|float $amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}
Regards
Thomas
Dmitry Stogov wrote on 02.02.2015 10:12:
hi,
could you please write down few use cases, when strict scalar type hints
are really useful.Thanks. Dmitry.
Thomas Bley wrote:
Here is a typical billing example which uses exceptions:
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);addVat('apples');
function addVat($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument 1 passed to '.FUNCTION.' must be of the type int|float, '.gettype($amount).' given');
}
return round($amount*1.19, 2);
}Instead of multiple strict scalar hints (e.g. function addVat(int|float $amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}
Have you considered
addVat(-1);
--
Christoph M. Becker
Instead of multiple strict scalar hints (e.g. function addVat(int|float $amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}
Have you consideredaddVat(-1);
Also addVat(1.235); which will be rounded to two decimal places ...
silently in this case.
A negative amount may be acceptable - credit note - and a one off price
may be a finer fraction, but this example shows a couple of other
potential errors.
As I have already said ... 'strict' may well only be a subset of the
error check. A "numeric" type would introduce the problem of scale of
number. Something which any of the database extensions already manage on
a field by field basis.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Yes, we currently have negative values for invoices and positive for vouchers ...
Christoph Becker wrote on 02.02.2015 22:17:
Thomas Bley wrote:
Here is a typical billing example which uses exceptions:
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);addVat('apples');
function addVat($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument 1 passed to '.FUNCTION.'
must be of the type int|float, '.gettype($amount).' given');
}
return round($amount*1.19, 2);
}Instead of multiple strict scalar hints (e.g. function addVat(int|float
$amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}Have you considered
addVat(-1);
--
Christoph M. Becker
Thomas Bley wrote:
Yes, we currently have negative values for invoices and positive for vouchers ...
Christoph Becker wrote on 02.02.2015 22:17:
Thomas Bley wrote:
Here is a typical billing example which uses exceptions:
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);addVat('apples');
function addVat($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument 1 passed to '.FUNCTION.'
must be of the type int|float, '.gettype($amount).' given');
}
return round($amount*1.19, 2);
}Instead of multiple strict scalar hints (e.g. function addVat(int|float
$amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}Have you considered
addVat(-1);
Well, my point was that even a strict type system doesn't necessarilly
catch all erroneous/undesired arguments. Even if addVat() properly
handles negative numbers, and maybe even zeroes, there are functions
that can't.
IMHO strict typing in a dynamic language is overvalued. While it
certainly helps to catch some errors, it doesn't do so during compile
time, at least not for all cases (consider call_user_func()
etc.)[1]
And frankly, I don't see what's wrong with a weak type hint in this case:
function addVat(float $amount) {...}
You're returning a float, anyway.
[1] There may be other benefits of having strict type hints. One of
these would be potential optimizations, but I have some doubts whether
this is feasible with optional weak/strict type hinting on the call side.
OTOH, strict type hints would require a lot of manual conversions.
--
Christoph M. Becker
Hi Christoph,
And frankly, I don't see what's wrong with a weak type hint in this case:
function addVat(float $amount) {...}
You're returning a float, anyway.
Given you’re dealing with currency, and given the fairly serious issues with precision loss with int->float conversions and vice-versa… I would be highly concerned if you used a weak type hint there.
OTOH, strict type hints would require a lot of manual conversions.
Sure, they do. But they’re explicit manual conversions, ones you can easily grep for and that are obvious when reading code.
--
Andrea Faulds
http://ajf.me/
Hi Andrea,
Andrea Faulds wrote:
Hi Christoph,
And frankly, I don't see what's wrong with a weak type hint in this case:
function addVat(float $amount) {...}
You're returning a float, anyway.
Given you’re dealing with currency, and given the fairly serious issues with precision loss with int->float conversions and vice-versa… I would be highly concerned if you used a weak type hint there.
Well, considering the given function body ($amount * 1.19), that doesn't
seem to be an issue. In the general case, if one has to deal with
currency, float is problematic anyway. I'd rather use a rational type
in this case (i.e. an immutable class with GMP[1] numerator and
denominator properties and the respective methods), which could be
combined with the actual currency (i.e. a "Money" class), if necessary.
OTOH, strict type hints would require a lot of manual conversions.
Sure, they do. But they’re explicit manual conversions, ones you can easily grep for and that are obvious when reading code.
Indeed, code is read far more often than it's written (hopefully :)),
but still it might be annoying for many PHP programmers to write these
explicit manual conversions in the first place.[2]
[1] Or int, if your Big Integer Support RFC will pass (which I would
welcome, BTW).
[2] I'm aware that your current Scalar Type Hints RFC would not require
these manual conversions, but that doesn't seem to be the topic of
this thread. :)
--
Christoph M. Becker
Hi again,
Indeed, code is read far more often than it's written (hopefully :)),
but still it might be annoying for many PHP programmers to write these
explicit manual conversions in the first place.[2]
Well, they only have to if they choose to use strict typing. ;)
Andrea Faulds
http://ajf.me/
Am Mon, 02 Feb 2015 23:38:21 +0100
schrieb Christoph Becker cmbecker69@gmx.de:
Hallo,
addVat(-1);
Well, my point was that even a strict type system doesn't necessarilly
catch all erroneous/undesired arguments. Even if addVat() properly
handles negative numbers, and maybe even zeroes, there are functions
that can't.
What about scalar type declaration in userland?
namespace mytypes;
declare scalartype amount($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument amount
must be of the type int|float, '.gettype($amount).' given');
}
}
function addVat(mytypes\amount $amount) {
return round($amount*1.19, 2);
}
addVat(42) // OK
addVat("42") // OK
addVat(-42) // OK
addVat(42.0) // OK
addVat(true) // Exception
var mytypes\amount $amount = 0;
$amount = 42; // OK
$amount = "42"; // OK
$amount = true; // Exception
tschuess
[|8:)
I would prefer:
function addVat($amount) {
validateAmount($amount);
return round($amount*1.19, 2);
}
function validateAmount($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument amount must be of the type int|float, '.gettype($amount).' given');
}
}
Regards
Thomas
Sven Drieling wrote on 03.02.2015 20:07:
Am Mon, 02 Feb 2015 23:38:21 +0100
schrieb Christoph Becker cmbecker69@gmx.de:Hallo,
addVat(-1);
Well, my point was that even a strict type system doesn't necessarilly
catch all erroneous/undesired arguments. Even if addVat() properly
handles negative numbers, and maybe even zeroes, there are functions
that can't.What about scalar type declaration in userland?
namespace mytypes;
declare scalartype amount($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument amount
must be of the type int|float, '.gettype($amount).' given');
}
}function addVat(mytypes\amount $amount) {
return round($amount*1.19, 2);
}addVat(42) // OK
addVat("42") // OK
addVat(-42) // OK
addVat(42.0) // OK
addVat(true) // Exceptionvar mytypes\amount $amount = 0;
$amount = 42; // OK
$amount = "42"; // OK
$amount = true; // Exceptiontschuess
[|8:)
Hi all,
function addVat($amount) {
validateAmount($amount);
return round($amount*1.19, 2);
}function validateAmount($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument amount must be of the
type int|float, '.gettype($amount).' given');
}
}
I use such code where runtime check is required.
I prefer following for better performance/readability. i.e. Pre/Post
conditions are inside of function definition.
If PHP supports native DbC, runtime checks are omitted and script runs
faster. NOTE: Dev time checks are
done in in/out block with proper DbC design. Runtime check should be in
function body.
function addVat($amount)
in {
// precondition check
assert(!is_int($amount) && !is_float($amount));
// OR
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument amount must be of the type
int|float, '.gettype($amount).' given');
}
}
out {
// postcondition check
assert(is_numeric($__return_vlaue) && $__return_value > 0 &&
$__return_value < MAX_AMOUNT);
}
{
// function body
return round($amount*1.19, 2);
}
Type hints are useful for simple runtime check.
Much less lines to write ;) It also encourage users to validate their app
inputs. This is important benefits for secure apps.
Things like these encourage proper DbC design naturally. Therefore, I'm +1
for all of these.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi Sven,
What about scalar type declaration in userland?
It’s one of many suggestions. I really, really don’t think it’s a good idea.
Rather than having two models (as the RFC suggests), we’d have n models, where n is the number of existent PHP frameworks and libraries. Every single application would have its own approach. It’d be chaotic, and not terribly user-friendly.
Andrea Faulds
http://ajf.me/
Hi,
Here is a typical billing example which uses exceptions:
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);addVat('apples');
function addVat($amount) {
if (!is_int($amount) && !is_float($amount)) {
throw new InvalidArgumentException('Argument 1 passed to '.FUNCTION.' must be of the type int|float, '.gettype($amount).' given');
}
return round($amount*1.19, 2);
}Instead of multiple strict scalar hints (e.g. function addVat(int|float $amount){...}), I would prefer to have "numeric" as strict type:
function addVat(numeric $amount){...}
That is an example where a weak hint to float would be better.
Here's a more appropriate example that I gave in the other thread:
http://marc.info/?l=php-internals&m=142142272705938&w=2
Cheers,
Andrey.