# What do we need strict scalar type hints for?

- Thread: https://externals.io/message/81653
- Original archive: https://news-web.php.net/php.internals/81653
- Started by Thomas Bley on 2015-02-02T21:03:49+00:00
- Messages: 13
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #81653 — Thomas Bley — 2015-02-02T21:03:49+00:00

URL: https://externals.io/message/81653#81653

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.

---

## #81654 — Christoph Becker — 2015-02-02T21:17:25+00:00

URL: https://externals.io/message/81653#81654 · In reply to: #81653

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

---

## #81655 — Andrey Andreev — 2015-02-02T21:18:12+00:00

URL: https://externals.io/message/81653#81655 · In reply to: #81653

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.

---

## #81659 — Lester Caine — 2015-02-02T21:41:50+00:00

URL: https://externals.io/message/81653#81659 · In reply to: #81654

> > […]
> Have you considered
> 
>   addVat(-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

---

## #81660 — Thomas Bley — 2015-02-02T21:42:54+00:00

URL: https://externals.io/message/81653#81660 · In reply to: #81654

Yes, we currently have negative values for invoices and positive for vouchers ...


Christoph Becker wrote on 02.02.2015 22:17:

> Thomas Bley wrote:
> 
> > […]
> 
> Have you considered
> 
>  addVat(-1);
> 
> -- 
> Christoph M. Becker

---

## #81664 — Christoph Becker — 2015-02-02T22:38:21+00:00

URL: https://externals.io/message/81653#81664 · In reply to: #81660

Thomas Bley wrote:

> Yes, we currently have negative values for invoices and positive for vouchers ...
> 
> 
> Christoph Becker wrote on 02.02.2015 22:17:
> 
> > […]

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

---

## #81668 — Andrea Faulds — 2015-02-02T22:51:34+00:00

URL: https://externals.io/message/81653#81668 · In reply to: #81664

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/

---

## #81671 — Christoph Becker — 2015-02-02T23:34:46+00:00

URL: https://externals.io/message/81653#81671 · In reply to: #81668

Hi Andrea,

Andrea Faulds wrote:

> Hi Christoph,
> 
> > […]
> 
> 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.

> > […]
> 
> 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

---

## #81674 — Andrea Faulds — 2015-02-02T23:51:35+00:00

URL: https://externals.io/message/81653#81674 · In reply to: #81671

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/

---

## #81732 — Sven Drieling — 2015-02-03T19:07:57+00:00

URL: https://externals.io/message/81653#81732 · In reply to: #81664

Am Mon, 02 Feb 2015 23:38:21 +0100
schrieb Christoph Becker <cmbecker69@gmx.de>:

Hallo,

> > […]
> 
> 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:)

---

## #81737 — Thomas Bley — 2015-02-03T20:23:36+00:00

URL: https://externals.io/message/81653#81737 · In reply to: #81732

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,
> 
> > […]
> 
> 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:)

---

## #81740 — Yasuo Ohgaki — 2015-02-03T20:51:50+00:00

URL: https://externals.io/message/81653#81740 · In reply to: #81737

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

---

## #81743 — Andrea Faulds — 2015-02-03T22:29:16+00:00

URL: https://externals.io/message/81653#81743 · In reply to: #81732

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/
