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
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
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.
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,
De : bishop.bettini@gmail.com [mailto:bishop.bettini@gmail.com] De la
part de Bishop BettiniTHING 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 aboveContracts 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.
Ifis_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
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 abovefunction 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
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 withis_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
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
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