# Nightmares on type hints, annotations, and aop...

- Thread: https://externals.io/message/83053
- Original archive: https://news-web.php.net/php.internals/83053
- Started by Bishop Bettini on 2015-02-18T12:18:16+00:00
- Messages: 7
- 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

---

## #83053 — Bishop Bettini — 2015-02-18T12:18:16+00:00

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

After a spate of literal coding nightmares, I woke needing to commit these
thoughts to the list.  These may have been raised before, I can't remember,
these debate has been raging for so long.


THING 1: Hints are just is_* wrappers

function f(scalar $s, int $i) { }

effectively is sugar for:

function f($s, $i) {
    if (! is_scalar($s)) throw new \InvalidArgumentException();
    if (! is_int($i)) throw new \InvalidArgumentException();
}


THING 2: Hints are truthy callables

function my_mixed($m) {
    return (null === $m || is_string($m));
}
function f(is_scalar $s, is_int $i, my_mixed $m) {};


THING 3: Pre- and post- blocks to define contracts, establish formal join
points, with or without hints from above

function f($s, $i, $m)
before {
    if (! is_scalar($s)) throw new \InvalidArgumentException;
},
inside {
    $fp = fopen($s, 'r');
    return [ $i, $m ];
},
after ($retval) {
    assert(is_array($retval) && 2 === count($retval));
},
finally ($retval) {
    fclose($fp);
    if ($retval instanceof \Exception) {
        // I got here by an unhandled exception
    }
}

weave('before', 'f', function ($s, $i, $m) {
    syslog(LOG_DEBUG, __POINTCUT__); // is 'f'
}


I had to get these off my chest. Forgive me their implementation ignorance.
I am yet tired and uncaffeinated. To the void I commit their bodies...

bishop

---

## #83074 — francois@php.net — 2015-02-18T14:54:03+00:00

URL: https://externals.io/message/83053#83074 · In reply to: #83053

Hi Bishop,

> De : bishop.bettini@gmail.com [mailto:bishop.bettini@gmail.com] De la part de Bishop Bettini
>
> THING 1: Hints are just is_* wrappers

Wrong. Only *strict* types are.

> THING 2: Hints are truthy callables
> 
> function my_mixed($m) {
>     return (null === $m || is_string($m));
> }
> function f(is_scalar $s, is_int $i, my_mixed $m) {};

Not sure I understand 'truthy callables'. Your example is a definition of 'strict-only' union types. It's a planned feature.

> THING 3: Pre- and post- blocks to define contracts, establish formal join
> points, with or without hints from above

Contracts are fine but cannot completely replace type hints. I initially followed this road but reverted to thinking that both tools have their use. Contracts can implement performance-intensive checks but, because of this, cannot be executed in production. Type hints are performance-constrained but always executed. Another benefit of type hints is that PHP does not provide a consistent set of 'weak' is_xxx() functions yet. Checking for an integer in PHP, for instance, when you're ready to accept 31, 31.0, or '31', is relatively complex and unintuitive, while 'int $arg'  is readable. If `is_int()` did a intuitive 'PHP way' check, contracts would be an alternative, but it is too counter-intuitive as it exists now. And BC makes changing is_xxx() behavior impossible, of course.

> I had to get these off my chest. Forgive me their implementation ignorance.
> I am yet tired and uncaffeinated.

No problem. Every goodwill is welcome.

> To the void I commit their bodies...

Sorry, my english is too poor for that. Can you explain?

Regards

François

---

## #83258 — Bishop Bettini — 2015-02-20T02:33:41+00:00

URL: https://externals.io/message/83053#83258 · In reply to: #83074

>
> > […]
> of 'strict-only' union types. It's a planned feature.
>

In my nightmare, users mobbed me after class, angry that scalar type hints
were confusing.  They couldn't believe I would test them on it.  I tired
calming them by describing weak- vs. strict- typing.  I implored the
benefit of aligning internal and external types.  I referenced The Dragon
Book.

The more I talked, the angrier the users became... and the more desperate I
became to find something that worked.

I scribbled on the white board of my dream:

function my_mixed($m) {
     return (null === $m || is_string($m));
}
function f(is_scalar $s, is_int $i, my_mixed $m) {
    printf('%s! %d, or %s', $s, $i, $m ?: '');
}

And in a moment, the torrent quieted.  They got this.  The hints aren't
keywords.  The "hints" are functions.  Functions like is_int or
is_resource.  Or user-defined functions.  The engine passes each formal
parameter's "function hint" the value of the corresponding actual
parameter. If the function returns false, the "hint" is violated and the
script crashes E_RECOVERABLE.

Anyway, I have contemplated my dream these last couple of days.  I'm sure
the tension of it reflects the heat of this debate, and the timing reflects
Andrea's departure.  The syntax my mind invented is, maybe, odd.  But I
think the syntax reflects something important about scalar type hints: they
must be intuitive to users.  It's true some of the is_* functions have
warts.  But users have grown up with them.  I've used them for nearly 13
years.  Users understand the semantics of is_*.  Maybe scalar type hints
should leverage that understanding.

I wonder if in trying to erase some of the coercion oddities, to align
internal and external types, and to formally codify the weak and strong
type rules that we're straying from the necessary intent: providing the
user benefit in a timely manner.

Sincerely,
bishop

PS: The fantasy syntax my dream invented can be emulated:

function hint_int($i) { return is_int($i) ? $i : throw new
InvalidArgumentException(); }

function add($a, $b) { $a = hint_int($a); $b = hint_int($b); return $a +
$b; }

On Wed, Feb 18, 2015 at 9:54 AM, François Laupretre <francois@php.net>
wrote:

> Hi Bishop,
>
> > […]
> part de Bishop Bettini
> > […]
>
> Wrong. Only *strict* types are.
>
> > […]
>
> Not sure I understand 'truthy callables'. Your example is a definition of
> 'strict-only' union types. It's a planned feature.
>
> > […]
>
> Contracts are fine but cannot completely replace type hints. I initially
> followed this road but reverted to thinking that both tools have their use.
> Contracts can implement performance-intensive checks but, because of this,
> cannot be executed in production. Type hints are performance-constrained
> but always executed. Another benefit of type hints is that PHP does not
> provide a consistent set of 'weak' is_xxx() functions yet. Checking for an
> integer in PHP, for instance, when you're ready to accept 31, 31.0, or
> '31', is relatively complex and unintuitive, while 'int $arg'  is readable.
> If `is_int()` did a intuitive 'PHP way' check, contracts would be an
> alternative, but it is too counter-intuitive as it exists now. And BC makes
> changing is_xxx() behavior impossible, of course.
>
> > […]
> ignorance.
> > […]
>
> No problem. Every goodwill is welcome.
>
> > […]
>
> Sorry, my english is too poor for that. Can you explain?
>
> Regards
>
> François

---

## #83265 — Zeev Suraski — 2015-02-20T05:49:08+00:00

URL: https://externals.io/message/83053#83265 · In reply to: #83053

Bishop,

Pardon me for saying so, but I don't think you're on to a huge scoop here.
Scalar type hints - of all the kinds we've been talking about here, be them
strict, weak or coercive - can be easily emulated with a couple of lines of
code, we all know that.  It's been known for years that strict hints are
is_*() else error equivalent, that weak hints are (mostly) just casts, etc.
Saying the class type hints can be emulated with `is_a()` calls wouldn't shock
anybody either.

However, the conclusion you seem to draw from that, few language designers
would agree with.  Adding first-class, reflectable, analyzable syntax - is
worlds apart from the situation today - regardless of what type of scalar
hinting we talk about.  Once we introduce language-level syntax for this
pattern, usage will *explode* compared to what it is today.  Explode, not
increase.  Tools would be updated to support (and take advantage) of this
new data - in a way they can't practically do with userland 'emulation' of
this behavior.  Best practices will be updated.  Doc formats will be
changed.  Etc etc.

Last, note that you only focused on userland functions.  Things are a bit
different with internal functions.  The different proposals on the table all
propose to change - in one way or another - the way internal functions
behave.  This is much less intuitive to emulate using userland code, for
obvious reasons.

So no, I don't think we're making a bigger deal out of it than it is.
Scalar type hints are a huge deal, and the fact you can emulate them in
userland code today doesn't change that in any way.

Thanks,

Zeev

> -----Original Message-----
> From: bishop.bettini@gmail.com [mailto:bishop.bettini@gmail.com] On
> Behalf Of Bishop Bettini
> Sent: Wednesday, February 18, 2015 2:18 PM
> To: PHP internals
> Subject: [PHP-DEV] Nightmares on type hints, annotations, and aop...
>
> After a spate of literal coding nightmares, I woke needing to commit these
> thoughts to the list.  These may have been raised before, I can't
> remember,
> these debate has been raging for so long.
>
>
> THING 1: Hints are just is_* wrappers
>
> function f(scalar $s, int $i) { }
>
> effectively is sugar for:
>
> function f($s, $i) {
>     if (! is_scalar($s)) throw new \InvalidArgumentException();
>     if (! is_int($i)) throw new \InvalidArgumentException(); }
>
>
> THING 2: Hints are truthy callables
>
> function my_mixed($m) {
>     return (null === $m || is_string($m)); } function f(is_scalar $s,
> is_int $i,
> my_mixed $m) {};
>
>
> THING 3: Pre- and post- blocks to define contracts, establish formal join
> points, with or without hints from above
>
> function f($s, $i, $m)
> before {
>     if (! is_scalar($s)) throw new \InvalidArgumentException; }, inside {
>     $fp = fopen($s, 'r');
>     return [ $i, $m ];
> },
> after ($retval) {
>     assert(is_array($retval) && 2 === count($retval)); }, finally
> ($retval) {
>     fclose($fp);
>     if ($retval instanceof \Exception) {
>         // I got here by an unhandled exception
>     }
> }
>
> weave('before', 'f', function ($s, $i, $m) {
>     syslog(LOG_DEBUG, __POINTCUT__); // is 'f'
> }
>
>
> I had to get these off my chest. Forgive me their implementation
> ignorance.
> I am yet tired and uncaffeinated. To the void I commit their bodies...
>
> bishop

---

## #83267 — Yasuo Ohgaki — 2015-02-20T06:34:50+00:00

URL: https://externals.io/message/83053#83267 · In reply to: #83053

Hi Bishop,



> THING 2: Hints are truthy callables
>
> function my_mixed($m) {
>     return (null === $m || is_string($m));
> }
> function f(is_scalar $s, is_int $i, my_mixed $m) {};
>
>
This is interesting idea. I'm sure it will be much slower than type hints
as it
calls functions, but it's still interesting idea. i.e. Cost of calling
functions are
not cheap. Inline optimization will help, but it increases byte code size.

Type hint implementation is a lot simpler than this.

THING 3: Pre- and post- blocks to define contracts, establish formal join
> points, with or without hints from above
>
> function f($s, $i, $m)
> before {
>     if (! is_scalar($s)) throw new \InvalidArgumentException;
> },
> inside {
>     $fp = fopen($s, 'r');
>     return [ $i, $m ];
> },
> after ($retval) {
>     assert(is_array($retval) && 2 === count($retval));
> },
> finally ($retval) {
>     fclose($fp);
>     if ($retval instanceof \Exception) {
>         // I got here by an unhandled exception
>     }
> }
>
> weave('before', 'f', function ($s, $i, $m) {
>     syslog(LOG_DEBUG, __POINTCUT__); // is 'f'
> }
>

Although it has similarities, AOP and DbC cannot share blocks/etc. AOP is
for production codes, DbC is _not_ for production codes, but only for
development
and testing. These are 2 distinct features.

Regards,

>
--
Yasuo Ohgaki
yohgaki@ohgaki.net

---

## #83279 — Lester Caine — 2015-02-20T08:47:13+00:00

URL: https://externals.io/message/83053#83279 · In reply to: #83265

> Pardon me for saying so, but I don't think you're on to a huge scoop here.
> Scalar type hints - of all the kinds we've been talking about here, be them
> strict, weak or coercive - can be easily emulated with a couple of lines of
> code, we all know that.  It's been known for years that strict hints are
> is_*() else error equivalent, that weak hints are (mostly) just casts, etc.
> Saying the class type hints can be emulated with `is_a()` calls wouldn't shock
> anybody either.

I think I may have realised just why *I* am having a problem with a lot
of this discussion ... I've used ADOdb from day one which already does
this ... *I* had not realised that core PHP did not bother with the
management of data types that ADOdb is layering on top ...

Hence my question yesterday which I will reword ... If PHP creates a new
variable what does it store by default?

-- 
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

---

## #83324 — francois@php.net — 2015-02-20T16:52:08+00:00

URL: https://externals.io/message/83053#83324 · In reply to: #83265

> De : Zeev Suraski [mailto:zeev@zend.com]
> 
> So no, I don't think we're making a bigger deal out of it than it is.
> Scalar type hints are a huge deal, and the fact you can emulate them in
> userland code today doesn't change that in any way.

Agreed, of course, but I respectfully suggest you may be too negative : I'd love to see poetic intent more often, and considering type hints as contracts is a powerful way to explore the concept, that very few suggested.

Cheers

François
