Code References

php.internals

Sterling Hughes

23 years ago
Hi, I figure I'll just throw this out into the wilderness, I want closures and function pointers in PHP. In other words I want the ability to do: $var = function ($a, $b) { return $a + $b; }; And then $var can contain a code reference to the anonymous function. Having code references is an infinitely useful feature in my experience, and I know other people have some really cool uses of closures for lightweight templating (with mod_perl.) [1] I'd also like function pointers, which are optimized callbacks of some sort, so you can go: function my_compare($a, $b) { if ($a > $b) return 1; if ($a < $b) return -1; return 0; } sort($ar, <my_compare>); And compare doesn't need to be resolved at runtime, but rather can be a compile time feature. -Sterling [1] I say code references on purpose. This doesn't need to mean full fledged closures, which are probably overkill (although, they would be nice too ;)
-- "That stuff's easy compared to installing Horde" - Alan Knowles, In response to my applause for creating a LALR parser for PHP.

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 09:16, Sterling Hughes wrote:
> Hi, > > I figure I'll just throw this out into the wilderness, I want closures > and function pointers in PHP. In other words I want the ability to do: >
^^^^ I meant code references of course. -Sterling
-- "Science is like sex: sometimes something useful comes out, but that is not the reason we are doing it." - Richard Feynman

George Schlossnagle

23 years ago
Excuse my ignorance, but how does this differ from the features offered by create_function? (Other than having nicer aesthetics.) On Monday, May 19, 2003, at 09:16 AM, Sterling Hughes wrote:

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote:
> Excuse my ignorance, but how does this differ from the features offered > by create_function? (Other than having nicer aesthetics.) >
create_function is runtime for one thing, this would be compile time (code reference, doesn't need to be relookedup). And then of course there are aesthetics, its incredibly ugly to do anything remotely complex with create_function. Also you would be able to do: <% function output_header($header) { $header('Hello World'); } output_header(function ($title) { %> <html> <head> <title>$title</title> </head> <body> <% } %> -Sterling
-- "The three most dangerous things in the world are a programmer with a soldering iron, a hardware type with a program patch and a user with an idea." - Unknown

Wez Furlong

23 years ago
use perl; This isn't exactly readable... --Wez. On Mon, 19 May 2003, Sterling Hughes wrote:

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 10:55, Wez Furlong wrote:
> use perl;
Python, Ruby, LISP, Java, C, whatever, all support this in some form or another (whether it be function pointers or code references.)
> > This isn't exactly readable... >
Its more readable to me. At least the concept of code references is. When you want to have a lot of callbacks with relatively low overhead, code references are the way to go (we could also have sort and friends cache the initial lookup, instead of call_user_func() on the function name over and over and over and over again, but code references are cleaner imho). As for anonymous functions, well, compared to create_function(), it is faster, neater, and allows for more possibilities. -Sterling
-- Good judgement comes from experience, and experience comes from bad judgement. - Fred Brooks

Wez Furlong

23 years ago
I'm not against a fast way of performing function callbacks, but the example that you chose wasn't an obvious thing for the human mind to parse. Why not compromize and aim for the callable type that Andrei was talking about, and have create_function() return one of those? --Wez. On Mon, 19 May 2003, Sterling Hughes wrote:

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 11:06, Wez Furlong wrote:
> I'm not against a fast way of performing function callbacks, but the > example that you chose wasn't an obvious thing for the human mind to parse. >
Are you saying I'm not human? :))) Yeah, perhaps my example wasn't beautiful, but I was demonstrating something not possible with create_function(). Anonymous functions are cleaner than create_function in any event.
> Why not compromize and aim for the callable type that Andrei was talking > about, and have create_function() return one of those? >
Part of this is essentially a callable type. -Sterling
-- "That stuff's easy compared to installing Horde" - Alan Knowles, In response to my applause for creating a LALR parser for PHP.

Zeev Suraski

23 years ago
At 16:34 19/05/2003, Sterling Hughes wrote:
>On Mon, 2003-05-19 at 10:55, Wez Furlong wrote: > > use perl; > >Python, Ruby, LISP, Java, C, whatever, all support this in some form or >another (whether it be function pointers or code references.)
And so does PHP, through create_function, using PHPish syntax. create_function is not related in any way to call_user_func(), it's fairly fast, and will be faster. I don't see any additional things that are supported by this syntax, other than a tiny performance gain, that comes at the price of significantly reduced functionality (the code cannot contain anything dynamic, whereas with create_function, it can). Zeev

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 11:09, Zeev Suraski wrote:
> At 16:34 19/05/2003, Sterling Hughes wrote: > >On Mon, 2003-05-19 at 10:55, Wez Furlong wrote: > > > use perl; > > > >Python, Ruby, LISP, Java, C, whatever, all support this in some form or > >another (whether it be function pointers or code references.) > > And so does PHP, through create_function, using PHPish > syntax. create_function is not related in any way to call_user_func(), > it's fairly fast, and will be faster. I don't see any additional things > that are supported by this syntax, other than a tiny performance gain, that > comes at the price of significantly reduced functionality (the code cannot > contain anything dynamic, whereas with create_function, it can). >
That's why one has eval. Create_function() is a really hacky way of having closures/callbacks. Its not only inefficient, its ugly. create_function() is hardly ever used because its such an inelegant (and inefficient) way of doing things. From a syntax perspective anonymous functions are much clearer (the problem with single quotes is you need to then escape all single quotes). (responding to a previous message re conditional compilation) What about when a compiler cache is introduced? Every high performance application most likely uses a compiler cache. Introducing a code reference, would remove that overhead, and would seriously simplify and improve callback code (I have a patch which optimizes nearly all of the callback code in php5, which I'll send shortly, but its cleaner if we had the concept of code references.) -Sterling
-- "Reductionists like to take things apart. The rest of us are just trying to get it together." - Larry Wall, Programming Perl, 3rd Edition

George Schlossnagle

23 years ago
On Monday, May 19, 2003, at 09:56 AM, Sterling Hughes wrote:
> On Mon, 2003-05-19 at 11:09, Zeev Suraski wrote: >> At 16:34 19/05/2003, Sterling Hughes wrote: >>> On Mon, 2003-05-19 at 10:55, Wez Furlong wrote: >>>> use perl; >>> >>> Python, Ruby, LISP, Java, C, whatever, all support this in some form >>> or >>> another (whether it be function pointers or code references.) >> >> And so does PHP, through create_function, using PHPish >> syntax. create_function is not related in any way to >> call_user_func(), >> it's fairly fast, and will be faster. I don't see any additional >> things >> that are supported by this syntax, other than a tiny performance >> gain, that >> comes at the price of significantly reduced functionality (the code >> cannot >> contain anything dynamic, whereas with create_function, it can). >> > > That's why one has eval. > > Create_function() is a really hacky way of having closures/callbacks. > Its not only inefficient, its ugly. create_function() is hardly ever > used because its such an inelegant (and inefficient) way of doing > things. From a syntax perspective anonymous functions are much clearer > (the problem with single quotes is you need to then escape all single > quotes).
I agree with you completely on the aesthetics. The quoting makes it as hard to read as a double-quoted perl eval. Zeev is right re: the performance though. The eval is only performed once (though it is of course an eval), which is only marginally more expensive than compiling it completely at script compile time, and that assumes that you always end up compiling it.

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 11:28, George Schlossnagle wrote:
> On Monday, May 19, 2003, at 09:56 AM, Sterling Hughes wrote: > > > On Mon, 2003-05-19 at 11:09, Zeev Suraski wrote: > >> At 16:34 19/05/2003, Sterling Hughes wrote: > >>> On Mon, 2003-05-19 at 10:55, Wez Furlong wrote: > >>>> use perl; > >>> > >>> Python, Ruby, LISP, Java, C, whatever, all support this in some form > >>> or > >>> another (whether it be function pointers or code references.) > >> > >> And so does PHP, through create_function, using PHPish > >> syntax. create_function is not related in any way to > >> call_user_func(), > >> it's fairly fast, and will be faster. I don't see any additional > >> things > >> that are supported by this syntax, other than a tiny performance > >> gain, that > >> comes at the price of significantly reduced functionality (the code > >> cannot > >> contain anything dynamic, whereas with create_function, it can). > >> > > > > That's why one has eval. > > > > Create_function() is a really hacky way of having closures/callbacks. > > Its not only inefficient, its ugly. create_function() is hardly ever > > used because its such an inelegant (and inefficient) way of doing > > things. From a syntax perspective anonymous functions are much clearer > > (the problem with single quotes is you need to then escape all single > > quotes). > > I agree with you completely on the aesthetics. The quoting makes it as > hard to read as a double-quoted perl eval. > > Zeev is right re: the performance though. The eval is only performed > once (though it is of course an eval), which is only marginally more > expensive than compiling it completely at script compile time, and that > assumes that you always end up compiling it. >
Well, right. As I've mentioned beforehand, speed is really a secondary factor, although it does exist, and the concept of code references (passing around function pointers as opposed to function names) would make php faster anywhere callbacks are used. But its also a cleanliness and ease-of-use factor. If you look at the amount create_function() is used in PHP code, its next to nil. With other scripting languages such features are commonly used (and very *useful* imho). One could assume this is because PHP users don't need it, but I think its more due to the way its kludged in (imho again). I think a clear way of having function pointers, and then a nice syntax for declaring anonymous subroutines (read: I don't want to stash my code inside a variable), would be something really useful. -Sterling
>
-- "The three most dangerous things in the world are a programmer with a soldering iron, a hardware type with a program patch and a user with an idea." - Unknown

Rasmus Lerdorf

23 years ago
On 19 May 2003, Sterling Hughes wrote:
> Well, right. As I've mentioned beforehand, speed is really a secondary > factor, although it does exist, and the concept of code references > (passing around function pointers as opposed to function names) would > make php faster anywhere callbacks are used. > > But its also a cleanliness and ease-of-use factor. If you look at the > amount create_function() is used in PHP code, its next to nil. With > other scripting languages such features are commonly used (and very > *useful* imho). One could assume this is because PHP users don't need > it, but I think its more due to the way its kludged in (imho again). I > think a clear way of having function pointers, and then a nice syntax > for declaring anonymous subroutines (read: I don't want to stash my code > inside a variable), would be something really useful.
I really don't like the idea of having a second syntax for what is essentially exactly the same thing and having that second syntax be different in a subtle way. The runtime vs. compile time difference is going cause confusion for people trying to use it. Sort of like the tens of thousands of questions we had regarding the difference between include and require before that mess was cleaned up. So, I am very much against introducing it just because you think it is prettier (which I don't disagree with). The fact that this feature isn't used that much today is a damn good thing as far as I am concerned. It doesn't exactly lend itself to readable code. People who know what they are doing and understand when to use an anonymous function can handle the syntax. -Rasmus

Andi Gutmans

23 years ago
At 10:42 AM 5/19/2003 -0400, Sterling Hughes wrote:
>Well, right. As I've mentioned beforehand, speed is really a secondary >factor, although it does exist, and the concept of code references >(passing around function pointers as opposed to function names) would >make php faster anywhere callbacks are used. > >But its also a cleanliness and ease-of-use factor. If you look at the >amount create_function() is used in PHP code, its next to nil. With >other scripting languages such features are commonly used (and very >*useful* imho). One could assume this is because PHP users don't need >it, but I think its more due to the way its kludged in (imho again). I >think a clear way of having function pointers, and then a nice syntax >for declaring anonymous subroutines (read: I don't want to stash my code >inside a variable), would be something really useful.
I must agree with the opposition about the introduction of 'code references'. Personally, I don't think code which makes extensive use of code references is very readable in general so saying that create_function() is ugly is interesting :) Anyway, I think create_function() is there, it works, and I don't see a convincing reason for something slightly different. Andi

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 13:48, Andi Gutmans wrote:
> At 10:42 AM 5/19/2003 -0400, Sterling Hughes wrote: > >Well, right. As I've mentioned beforehand, speed is really a secondary > >factor, although it does exist, and the concept of code references > >(passing around function pointers as opposed to function names) would > >make php faster anywhere callbacks are used. > > > >But its also a cleanliness and ease-of-use factor. If you look at the > >amount create_function() is used in PHP code, its next to nil. With > >other scripting languages such features are commonly used (and very > >*useful* imho). One could assume this is because PHP users don't need > >it, but I think its more due to the way its kludged in (imho again). I > >think a clear way of having function pointers, and then a nice syntax > >for declaring anonymous subroutines (read: I don't want to stash my code > >inside a variable), would be something really useful. > > I must agree with the opposition about the introduction of 'code references'. > Personally, I don't think code which makes extensive use of code references > is very readable in general so saying that create_function() is ugly is > interesting :) > Anyway, I think create_function() is there, it works, and I don't see a > convincing reason for something slightly different. >
Well, you're all wrong. But your collective wrongness has convinced me to drop it :) -Sterling
> Andi
-- "The three most dangerous things in the world are a programmer with a soldering iron, a hardware type with a program patch and a user with an idea." - Unknown

Zeev Suraski

23 years ago
At 16:56 19/05/2003, Sterling Hughes wrote:
>On Mon, 2003-05-19 at 11:09, Zeev Suraski wrote: > > At 16:34 19/05/2003, Sterling Hughes wrote: > > >On Mon, 2003-05-19 at 10:55, Wez Furlong wrote: > > > > use perl; > > > > > >Python, Ruby, LISP, Java, C, whatever, all support this in some form or > > >another (whether it be function pointers or code references.) > > > > And so does PHP, through create_function, using PHPish > > syntax. create_function is not related in any way to call_user_func(), > > it's fairly fast, and will be faster. I don't see any additional things > > that are supported by this syntax, other than a tiny performance gain, > that > > comes at the price of significantly reduced functionality (the code cannot > > contain anything dynamic, whereas with create_function, it can). > > > >That's why one has eval.
?
>Create_function() is a really hacky way of having closures/callbacks. >Its not only inefficient, its ugly. create_function() is hardly ever >used because its such an inelegant (and inefficient) way of doing >things. From a syntax perspective anonymous functions are much clearer >(the problem with single quotes is you need to then escape all single >quotes).
I can't really argue with this. For me the issues you raise here are really tiny nuances. Fact is that there's nothing your suggestion does that create_function doesn't; Whether or not your suggested syntax is clearer than that of create_function is definitely open for debate, but considering create_function is already in, the question on whether we should add something new is really a no brainer. Escaping with single quotes is really, just another tiny nuance. Single quotes are not that common at all.
>(responding to a previous message re conditional compilation) > >What about when a compiler cache is introduced? Every high performance >application most likely uses a compiler cache. Introducing a code >reference, would remove that overhead, and would seriously simplify and >improve callback code (I have a patch which optimizes nearly all of the >callback code in php5, which I'll send shortly, but its cleaner if we >had the concept of code references.)
Then your suggestion would be negligibly faster, probably unmeasurable unless the only thing you do is call that anonymous function in a loop. That's my point, though. I'm not trying to convince you that create_function is better (even though I think it is). I'm trying to illustrate to you that it's at least as good as what you have in mind, and it's already there. Zeev

George Schlossnagle

23 years ago
On Monday, May 19, 2003, at 09:23 AM, Sterling Hughes wrote:
> On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote: >> Excuse my ignorance, but how does this differ from the features >> offered >> by create_function? (Other than having nicer aesthetics.) >> > > create_function is runtime for one thing, this would be compile time > (code reference, doesn't need to be relookedup).
Isn't that different semantics than the variable assignments everywhere else in PHP? Sounds like it's more of a constant....
> And then of course > there are aesthetics, its incredibly ugly to do anything remotely > complex with create_function.
No argument on that one. :)

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 11:11, George Schlossnagle wrote:
> On Monday, May 19, 2003, at 09:23 AM, Sterling Hughes wrote: > > > On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote: > >> Excuse my ignorance, but how does this differ from the features > >> offered > >> by create_function? (Other than having nicer aesthetics.) > >> > > > > create_function is runtime for one thing, this would be compile time > > (code reference, doesn't need to be relookedup). > > Isn't that different semantics than the variable assignments everywhere > else in PHP? Sounds like it's more of a constant....
Nope. Its evaluated at runtime, compiled at compile time. Whereas create_function() is compiled and evaluated at runtime. -Sterling
-- "The three most dangerous things in the world are a programmer with a soldering iron, a hardware type with a program patch and a user with an idea." - Unknown

Zeev Suraski

23 years ago
At 16:46 19/05/2003, Sterling Hughes wrote:
>Nope. Its evaluated at runtime, compiled at compile time. Whereas >create_function() is compiled and evaluated at runtime.
That's only an advantage for create_function. It doesn't get evaluated unless it's necessary. Like your suggestion, it gets compiled just once. I think that this whole thread originates in a misperception as to how create_function() works. Zeev

Zeev Suraski

23 years ago
At 16:23 19/05/2003, Sterling Hughes wrote:
>On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote: > > Excuse my ignorance, but how does this differ from the features offered > > by create_function? (Other than having nicer aesthetics.) > > > >create_function is runtime for one thing, this would be compile time >(code reference, doesn't need to be relookedup). And then of course >there are aesthetics, its incredibly ugly to do anything remotely >complex with create_function.
Yikes. I really think create_function is more than enough for what we need in PHP. Whether or not there's an extra lookup for such an expensive operation (fcall) should not be the reason to add such a feature. It's a beast from another family of languages (functional languages), we need a VERY good reason to introduce it. You can do pretty stuff very easily with create_function and single quotes or heredocs. Zeev

Sterling Hughes

23 years ago
On Mon, 2003-05-19 at 10:59, Zeev Suraski wrote:
> At 16:23 19/05/2003, Sterling Hughes wrote: > >On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote: > > > Excuse my ignorance, but how does this differ from the features offered > > > by create_function? (Other than having nicer aesthetics.) > > > > > > >create_function is runtime for one thing, this would be compile time > >(code reference, doesn't need to be relookedup). And then of course > >there are aesthetics, its incredibly ugly to do anything remotely > >complex with create_function. > > Yikes. I really think create_function is more than enough for what we need > in PHP. Whether or not there's an extra lookup for such an expensive > operation (fcall) should not be the reason to add such a feature. It's a
Well, its much more than a lookup, its an eval. Also, I can tell you haven't used create_function that much. Even though I use closures alot (when I program Perl), I stay away from create_function() because its ugly (sorry :) $ref = create_function ('$a, $b', <<<HEREDOC \$c = \$a + \$b; \$d = \$c * \$a; return $\d; HEREDOC;); compared to: $ref = function ($a, $b) { $c = $a + $b; $d = $c + $a; return $d; } And that's in the *simplest* of cases. For anything moderately complex, create_function isn't an option. (Plus you have the eval overhead at runtime, and a function lookup.) What I'm proposing is easier, and also faster.
> beast from another family of languages (functional languages), we need a > VERY good reason to introduce it. You can do pretty stuff very easily with > create_function and single quotes or heredocs. >
As I said to Wez, function pointers/code references are in virtually every language I know of. Anonymous functions are in Perl, Python, Ruby, LISP and possibly others. -Sterling
-- "Nothing is particularly hard if you divide it into small jobs." - Henry Ford

Zeev Suraski

23 years ago
At 16:41 19/05/2003, Sterling Hughes wrote:
>On Mon, 2003-05-19 at 10:59, Zeev Suraski wrote: > > At 16:23 19/05/2003, Sterling Hughes wrote: > > >On Mon, 2003-05-19 at 10:47, George Schlossnagle wrote: > > > > Excuse my ignorance, but how does this differ from the features offered > > > > by create_function? (Other than having nicer aesthetics.) > > > > > > > > > >create_function is runtime for one thing, this would be compile time > > >(code reference, doesn't need to be relookedup). And then of course > > >there are aesthetics, its incredibly ugly to do anything remotely > > >complex with create_function. > > > > Yikes. I really think create_function is more than enough for what we > need > > in PHP. Whether or not there's an extra lookup for such an expensive > > operation (fcall) should not be the reason to add such a feature. It's a > >Well, its much more than a lookup, its an eval.
No it isn't. It's a lookup.
> Also, I can tell you >haven't used create_function that much. Even though I use closures alot >(when I program Perl), I stay away from create_function() because its >ugly (sorry :) > >$ref = create_function ('$a, $b', <<<HEREDOC >\$c = \$a + \$b; >\$d = \$c * \$a; >return $\d; >HEREDOC;); > >compared to: > >$ref = function ($a, $b) { > $c = $a + $b; > $d = $c + $a; > return $d; >}
How about
>$ref = create_function('$a, $b', ' > $c = $a + $b; > $d = $c + $a; > return $d;
'); ?
>And that's in the *simplest* of cases. For anything moderately complex, >create_function isn't an option. (Plus you have the eval overhead at >runtime, and a function lookup.) What I'm proposing is easier, and also >faster.
Look, Sterling, the performance gain is going to be negligible. Contrary to your perception, it does not use eval() any more than your proposed solution would - the compiler has to be invoked to parse the code, just as much the compiler will have to parse the code in your case. In both cases, the code gets compiled just once. From a performance point of view, the difference boils down to a slightly slower lookup. From looks point of view, if you try to make it look nice, you can, very easily, as I illustrated. Using single quotes you only have to escape single quotes and backslashes, certainly not a big price to pay.
> > beast from another family of languages (functional languages), we need a > > VERY good reason to introduce it. You can do pretty stuff very easily > with > > create_function and single quotes or heredocs. > > > >As I said to Wez, function pointers/code references are in virtually >every language I know of. Anonymous functions are in Perl, Python, >Ruby, LISP and possibly others.
And as I said in reply, they also exist in PHP. Zeev

George Schlossnagle

23 years ago
On Monday, May 19, 2003, at 11:13 AM, Zeev Suraski wrote:
> At 16:41 19/05/2003, Sterling Hughes wrote: >> Well, its much more than a lookup, its an eval. > > No it isn't. It's a lookup.
I'm on neither side of this, but the create funciton code certainly looks like it does an eval: eval_code_length = sizeof("function " LAMBDA_TEMP_FUNCNAME) +Z_STRLEN_PP(z_function_args) +2 /* for the args parentheses */ +2 /* for the curly braces */ +Z_STRLEN_PP(z_function_code); eval_code = (char *) emalloc(eval_code_length); sprintf(eval_code, "function " LAMBDA_TEMP_FUNCNAME "(%s){%s}", Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code)); eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC); retval = zend_eval_string(eval_code, NULL, eval_name TSRMLS_CC);

Wez Furlong

23 years ago
It evals the string at the time it is called to create an "anonymous" function. From then on, its a function, just like any other, and is called just like any other. --Wez. On Mon, 19 May 2003, George Schlossnagle wrote:

Zeev Suraski

23 years ago
At 18:22 19/05/2003, George Schlossnagle wrote:
>On Monday, May 19, 2003, at 11:13 AM, Zeev Suraski wrote: > >>At 16:41 19/05/2003, Sterling Hughes wrote: >>>Well, its much more than a lookup, its an eval. >> >>No it isn't. It's a lookup. > >I'm on neither side of this, but the create funciton code certainly looks >like it does an eval:
Look into the code. It's not an eval any more than Sterling's suggestion. Zeev

George Schlossnagle

23 years ago
On Monday, May 19, 2003, at 11:23 AM, Zeev Suraski wrote:
> At 18:22 19/05/2003, George Schlossnagle wrote: > >> On Monday, May 19, 2003, at 11:13 AM, Zeev Suraski wrote: >> >>> At 16:41 19/05/2003, Sterling Hughes wrote: >>>> Well, its much more than a lookup, its an eval. >>> >>> No it isn't. It's a lookup. >> >> I'm on neither side of this, but the create funciton code certainly >> looks like it does an eval: > > Look into the code. It's not an eval any more than Sterling's > suggestion.
Sure (as you can see from my subsequent followup to Sterling, I agree with you completely.) It is an eval though (at declaration time; eval once, call many). That was my whole point. George

Zeev Suraski

23 years ago
Anything that create_function() doesn't do? Zeev At 16:16 19/05/2003, Sterling Hughes wrote: