3 ms·
> Having to explicitly list a function's free variables with "use" is a hideous consequence of not having lexical scope from the start, so again it's understand
by trebor 13y ago
> Having to explicitly list a function's free variables with "use" is a hideous consequence of not having lexical scope from the start, so again it's understandable.
No, it's a clear avoidance of the problems of the Javascript lexical scope. Yes, it'd be nice to have that "for free", but there's far worse that could happen if you had free access to all variables. The GC complexity alone would outweigh the benefit.
> Likewise, the parser doesn't realise that functions may be stored in objects:
A contrived example actually. First, the interpreter only interprets "$foo->quux()" as a method call on a non-existent method. You are not accessing a property of the object, ever, through a method call like that. Instead, you have the option to implement __call.
class foo {
public $quux;
public function __call($method, $args) {
if (property_exists($this, $method) && is_callable($this->$method)) {
return call_user_func_array($this->$method, $args);
}
}
}
$foo = new foo;
$foo->quux = function () { echo 'hello'; };
$foo->quux();
Changing this behavior could single-handedly break compatibility with all libraries making use of __get/__call methods. It could have been implemented, yes, and probably should have been. However, most people using PHP aren't throwing closures on an object (the closure won't have access to $this scope till 5.4 or later, you know) and expecting them to work like a method.
I may address the other points later, but I'm pretty sure that if you'd take a look and try writing idiomatic PHP you'd find it easier than assuming that your idioms from other languages will work directly and without modification.
- chriswarbo 13y ago> No, it's a clear avoidance of the problems of the Javascript lexical scope. Do you mean problems with the way Javascript implements lexical scope (no "let" blocks until recently, hoisting, global-by-default, etc.) or problems with lexical scope in general? Lexical scope's been around since at least ALGOL60, but really started to shine in Scheme. I agree that there's a tradeoff for GC, and as I said it's understandable why "use" acts the way it does, since lexical scope wasn't in there from the start (where it could have informed other scoping policies). > A contrived example actually. I agree, but it's contrived precisely because PHP's OO and functional features don't play well together, so everybody's learned not to do it. > First, the interpreter only interprets "$foo->quux()" as a method call on a non-existent method. You are not accessing a property of the object, ever, through a method call like that. That's exactly my point! :) > Instead, you have the option to implement __call. Yes, this is a decent workaround for a self-contained library/app/etc. but it shouldn't really be necessary. > Changing this behavior could single-handedly break compatibility with all libraries making use of __get/__call methods. That's an issue, but I don't think it would be as calamatous as you say :) It would mainly alter behaviour for those who are putting functions in their objects, but as you say that's not commonly done! > However, most people using PHP aren't throwing closures on an object (the closure won't have access to $this scope till 5.4 or later, you know) and expecting them to work like a method. I wasn't saying that a function property should act like a method semantically (ie. be called with an implicit $this argument), only that it should be possible to call it like a method syntactically, ie. the syntax "A(B)" should call "A" with arguments "B". Note that it's not just functions; quux could be anything callable. > I'm pretty sure that if you'd take a look and try writing idiomatic PHP you'd find it easier than assuming that your idioms from other languages will work directly and without modification. I've been writing PHP since 4.2, so I'm perfectly aware of what does and does not work. I'm pointing out what could work, and make PHP much nicer. Sticking to standard practice is a good idea when writing libraries and applications, but is stifling when brainstorming for a new version of PHP. My problem with idiomatic PHP is that it's usually incredibly verbose, usually because everything's been collapsed down to be first-order, which leads to boilerplate (eg. repeated build-up and tear-down code) and copypasta ("multiply_all_foos" and "sum_all_foos" which are the same except for the operator, or "Foo->multiply" and "Foo->sum" if you prefer). A few higher-order functions, like function composition and partial application, can cut down this bloat tremendously. It's just jarring when this bumps into a completely unnecessary PHP quirk, like having to put "call_user_func" all over the place ;)
- trebor 13y ago> Do you mean problems with the way Javascript implements lexical scope (no "let" blocks until recently, hoisting, global-by-default, etc.) or problems with lexical scope in general? In general. It's powerful to be able to reach out of your immediate scope to access something outside it, but then everything from the defining scope must be retained for later. Because of variable variables, which can be either wickedly difficult to debug or incredibly handy, virtually anything from the defining scope could be accessed in a way the interpreter couldn't predict. In some ways, I can already see the mess that could ensue. Which is precisely I appreciated the "use ()" syntax. > I wasn't saying that a function property should act like a method semantically (ie. be called with an implicit $this argument), only that it should be possible to call it like a method syntactically, ie. the syntax "A(B)" should call "A" with arguments "B". Note that it's not just functions; quux could be anything callable. I guess I can see the value in that. However, that leads to ambiguity during debugging, especially if you've included a dependency and haven't thoroughly vetted it. In that case, you need some XDebug magic to know if $foo->quux was a closure, callable array or string, invoke-able object, or a method. Then you need to determine its call semantics, etc. I don't think "anything callable" is appropriate. But I do think anonymous functions, closures, and invoke-able objects are. You could then make strings and arrays invokable by wrapping them in a class, but without trying to execute an erroneous string or array. > I'm pointing out what could work, and make PHP much nicer. Yeah, your suggestions could work. Whether it would make PHP better or worse depends on the programmer, and the change's second-order effects on how the object model works. But I'm skeptical of its benefit. It would probably wind up muddying the execution logic till at least 1 patch level further. I'd have to see some real-world examples of how this would be useful to fully convince me. Call me paranoid if you wish, but I wouldn't want a novice programmer stumbling on that change by accident. I can already envision the spaghetti they'd use it to write, then we'd have to come bail them out. ;)