[PROPOSAL] "use" keyword
Le 25/07/2014 20:52, Michaël Rouges a écrit :
Hi all,
There is any plan around un functionnality like the "use" keyword, in PHP.
Why something like that? Because, in JS, there is no way to inject some variables, without touch the this object known in a function.
Can you give an example of what you call "injecting some variables"? More generally, can you give a concrete example of what you're trying to achieve?
Thanks,
I am not sure I understand your problem but AFAIK php introduced "use" to simulate JavaScript implicit outer scope access instead of the explicit global context php is (in)famous for, it comes quite as a surprise you are asking JS to simulate PHP here :-)
`var test, fn;
fn = new Function('value', 'return function (){console.log(value);}');
fn('hello');`
I don't see why would you pass through Function instead of just wrapping that function.
var fn = (function(floatNum, genericString){
return function (anotherArg) {
console.log(floatNum, genericString, anotherArg);
};
}(
// here the equivalent of your "use"
Math.random(),
'whatever'
));
fn('yo'.sup());
will produce something like:
0.3651656119618565, whatever, <sup>yo</sup>
Best
On Fri, Jul 25, 2014 at 11:52 AM, Michaël Rouges <michael.rouges at gmail.com> wrote:
Hi all,
There is any plan around un functionnality like the "use" keyword, in PHP.
PHP's use() syntax is because PHP doesn't have actual lexical closures; it's a hack around the lack.
Why something like that? Because, in JS, there is no way to inject some variables, without touch the this object known in a function.
"Injecting variables into a function" is typically done by passing arguments.
The lone possible way is with ownmade functions, in the same context, by :
`var test, fn;
fn = new Function('value', 'return function (){console.log(value);}');
fn('hello');`
This is functionally identical to:
fn = function(value) { return function() { console.log(value); }; fn("hello")
Using the Function constructor here doesn't seem to offer anything at all over just writing a normal function. Am I missing something?
Sure... I make a library that that needs to share a private variable with all methods of an instance passed by arguments on my lib' method.
var lib;
(function () {
var shared;
shared = 'a shared value';
lib = {
method: function method(foreignObject) {
var property;
for (property in foreignObject) {
if (foreignObject.hasOwnProperty('property') {
if (typeof foreignObject === 'function') {
// how to pass the "shared" variable
// preserving the inside this in foreignObject
methods
// and without to touch the methods args?
}
}
}
}
};
}());```
The nearest way is something like this :
var foreignObject;
foreignObject = { method: function method(shared) { console.log(shared); } };
lib.method(foreignObject);
And, in place of the lib.method comments :
foreignObject[property] = foreignObject[property].bind(foreignObject, shared);
It's really boring, because :
- it don't works with non-writable methods,
- it risks to loose the inside this of the methods (if not equal to
foreignObject),
- it forces to have a 'shared' arguments on each foreignObject method
Better? :)
Michaël Rouges - https://github.com/Lcfvs - @Lcfvs
function wrap(method) { return function () { var args = [].slice.call(arguments); args[0] = shared; return method.aply(this, args); }; }
foreignObject[property] = wrap(foreignObject[property]);
?
you still have the problem with the non writable methods ... but hey, that's exactly the reason people make methods non writable .. you know, if you don't own objects don't be that obtrusive ;-)
On Fri, Jul 25, 2014 at 12:56 PM, Michaël Rouges <michael.rouges at gmail.com> wrote:
Hi David.
Sure... I make a library that that needs to share a private variable with all methods of an instance passed by arguments on my lib' method.
var lib; (function () { var shared; shared = 'a shared value'; lib = { method: function method(foreignObject) { var property; for (property in foreignObject) { if (foreignObject.hasOwnProperty('property') { if (typeof foreignObject === 'function') { // how to pass the "shared" variable // preserving the inside this in foreignObject methods // and without to touch the methods args? } } } } }; }());```
Ah, so you've got a "private" variable (declared in a closure) that you want to share with other objects which aren't created in the same closure.
This is what Symbols/WeakMaps were made for. Precisely how to use them depends on exactly what you're going for and what your constraints are, but I'm confident you could bodge something together with a WeakMap without too much trouble.
On Fri, Jul 25, 2014 at 4:25 PM, Michaël Rouges <michael.rouges at gmail.com>
wrote:
@Andrea :
Yeah, I don't really want to rewrite the methods, I only want to share my "shared" variable with these methods.
Furthermore, your code don't works because "method" don't knows "shared".
You could temporarily (or not) share the data as a property of the foreign object's method itself.
the method knows shared as soon as you define it inside your closure ...
var lib;
(function () {
var shared;
shared = 'a shared value';
function wrap(method) {
return function () {
var args = [].slice.call(arguments);
args[0] = shared;
return method.aply(this, args);
};
}
lib = {
method: function method(foreignObject) {
var property;
for (property in foreignObject) {
if (foreignObject.hasOwnProperty('property')) {
if (typeof foreignObject[property] === 'function') {
foreignObject[property]
= wrap(foreignObject[property]);
}
}
}
}
};
}());
... take care ...
forgot to fix one of many typos in your initial example too ... if (foreignObject.hasOwnProperty(property)) {
...
On Fri, Jul 25, 2014 at 4:29 PM, Tab Atkins Jr. <jackalmage at gmail.com>
wrote:
On Fri, Jul 25, 2014 at 12:56 PM, Michaël Rouges <michael.rouges at gmail.com> wrote:
Hi David.
Sure... I make a library that that needs to share a private variable with all methods of an instance passed by arguments on my lib' method.
var lib; (function () { var shared; shared = 'a shared value'; lib = { method: function method(foreignObject) { var property; for (property in foreignObject) { if (foreignObject.hasOwnProperty('property') { if (typeof foreignObject === 'function') { // how to pass the "shared" variable // preserving the inside this in foreignObject methods // and without to touch the methods args? } } } } }; }());```
Ah, so you've got a "private" variable (declared in a closure) that you want to share with other objects which aren't created in the same closure.
This is what Symbols/WeakMaps were made for.
I'd be interested to see what your approach would be—afaict, this would require exposing the Symbol or WeakMap to whatever scope the foreign object is defined in and then there's no point in using either.
@ TJ, Rick :
I'm really interested too!
On an another side, my next idea, for the same goal, is a thing like :
Function.prototype.attachContext()
Where an "attachContext" call can share the context of the current scope with the related function.
Michaël Rouges - Lcfvs - @Lcfvs
On Fri, Jul 25, 2014 at 4:39 PM, Michaël Rouges <michael.rouges at gmail.com>
wrote:
@ TJ, Rick :
I'm really interested too!
On an another side, my next idea, for the same goal, is a thing like :
Function.prototype.attachContext()
Where an "attachContext" call can share the context of the current scope with the related function.
var attachContext = Function.prototype.attachContext; Function.prototype.attachContext = function(context) { malice(context); attachContext.call(this, context); };
On Fri, Jul 25, 2014 at 1:35 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
On Fri, Jul 25, 2014 at 4:29 PM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
Ah, so you've got a "private" variable (declared in a closure) that you want to share with other objects which aren't created in the same closure.
This is what Symbols/WeakMaps were made for.
I'd be interested to see what your approach would be—afaict, this would require exposing the Symbol or WeakMap to whatever scope the foreign object is defined in and then there's no point in using either.
Yeah, upon actually walking through my desired example, I found that the Symbol/Weakmap is irrelevant. Here's what I was thinking, using only existing stuff:
(function(){
var shared1;
function ForeignObject() { /* Uses shared1 somehow */ }
ForeignObject.setSharedSecret(val) {
shared1 = val;
}
})();
(function(){
var shared2 = "the real secret";
function MyObject() { /*...*/ }
MyObject.exposeSharedSecret(cb) {
cb(shared2);
}
})();
MyObject.exposeSharedSecret(ForeignObject.setSharedSecret);
Um, no, I was thinking something like :
var fn;
fn = function fn() {
// After the context is attached fn scope already knows "shared"
};
(function () {
var shared;
shared = 'message';
fn.attachContext();
}());```
Michaël Rouges - https://github.com/Lcfvs - @Lcfvs
as a knonw convention in your code that would work but I have no idea what was anymore the first request at this point.
Best
- I don't understand what you are trying to do and why
- I don't think any of this woul dhave been solved anyway with "use" , neither in PHP
Hope others can help more.
Best
On Fri, Jul 25, 2014 at 4:53 PM, Tab Atkins Jr. <jackalmage at gmail.com>
wrote:
On Fri, Jul 25, 2014 at 1:35 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
On Fri, Jul 25, 2014 at 4:29 PM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
Ah, so you've got a "private" variable (declared in a closure) that you want to share with other objects which aren't created in the same closure.
This is what Symbols/WeakMaps were made for.
I'd be interested to see what your approach would be—afaict, this would require exposing the Symbol or WeakMap to whatever scope the foreign object is defined in and then there's no point in using either.
Yeah, upon actually walking through my desired example, I found that the Symbol/Weakmap is irrelevant. Here's what I was thinking, using only existing stuff:
(function(){ var shared1; function ForeignObject() { /* Uses shared1 somehow */ } ForeignObject.setSharedSecret(val) { shared1 = val; } })(); (function(){ var shared2 = "the real secret"; function MyObject() { /*...*/ } MyObject.exposeSharedSecret(cb) { cb(shared2); } })(); MyObject.exposeSharedSecret(ForeignObject.setSharedSecret);
Neither of these objects is in scope here.
let's do this way: you write down in some working PHP what you are trying to achieve and I'll give you back the equivalent JS, if possible ... otherwise I think I cannot help much here.
Best
P.S. Rick ... lol, true that, but if you imagine those functions returned and used outside that IFI the sharing technique would work somehow, although I still cannot think of any concrete or useful application
On Fri, Jul 25, 2014 at 5:13 PM, Michaël Rouges <michael.rouges at gmail.com>
wrote:
@Andrea :
There is no real equivalent in PHP.
I only used the "use" keyword as example to suggest, in your mind, an ability to share vars with a foreign function without to touch the foreign function arguments. ;)
Perhaps you missed it, but I demonstrated exactly this: gist.github.com/rwaldron/7a3fe8bd49831978846e
On Fri, Jul 25, 2014 at 4:57 PM, Michaël Rouges <michael.rouges at gmail.com>
wrote:
Um, no, I was thinking something like :
var fn; fn = function fn() { // After the context is attached fn scope already knows "shared" }; (function () { var shared; shared = 'message'; fn.attachContext(); }());```
It's as if attachContext creates pointers to all bindings in the Lexical and Variable Environment? If any of those bindings are for references, this creates an object capabilities leak.
@ Rick :
I don't missed but thanks :)
Your example works but not in an private channel between the 2 scopes.
And on your next post, yeah, it's exactly that sharing the pointers... but in single way (A to B) or (B to A)
And I think to an another Function.prototype method to prevent this effect, a few like a Object.preventExtensions().
Michaël Rouges - Lcfvs - @Lcfvs
that's the nonsense I am talking about. In php "use" is defined at function definition time, it's not something you can attach later on.
In JS you can use .call and .apply passing any context to any different function, unless already bound to another context, so you have already way more power than PHP methods or generic callbacks, with or without "use"
If you talk about variables as outer scope variables, then I don't udnerstand how you create functions that rely on abstract values around them without knowing what are these values about ... what does it mean sharing variables?
There's a lot of mixed and in my opinion unclear content that has not much to do with "use" or PHP and rather what you are trying to achieve concretely which is still a mystery to me.
Then, trying to understand what brought you here, I've realized here ( Lcfvs/XEncoder.js/blob/master/XEncoder.js#L49 ) you might want to clear-up a little bit, and a part of this thread, how context and scope work in JavaScript, maybe you have all answers already, you just don't see them ;-)
Best
@ Andrea :
.call, .apply and .bind change the this in the function, then it can't catch the goal and it doesn't work with non-writable methods again.
It's why my detailled example ( esdiscuss.org/topic/proposal-use-keyword#content-4) is written with object methods (to etablish all constraints).
And don't worry... dont make a fixation on the PHP use, read the last Rick's post. ;)
Michaël Rouges - Lcfvs - @Lcfvs
.call, .apply works with every non-writable method you want ... Rick answered, I've fixed your broken example (parens missing, checks on the method instead of the object itself, etc ...) and finally Tab wrote what's the closest thing you can think of between two closures, once you export outside those two functions.
I'd done here, good luck with your task.
Best
@ Rick :
Or a more controlled solution might be to create a method able to only attach one pointer at a time.
What do You think about it?
I see where this might be convenient, but the down sides are much larger,
similar to with
, eval
, or arbitrary global variables. It essentially
destroys the ability of compilers, tools, and people to statically analyze
the code.
I'm all for laziness in code (e.g. destructuring), but not when it causes significant problems.
Michaël, sorry, but I think this is a lost cause.
There is any plan around un functionnality like the "use" keyword, in PHP.
Why something like that? Because, in JS, there is no way to inject some variables, without touch the this object known in a function.
The lone possible way is with ownmade functions, in the same context, by :
`var test, fn;
fn = new Function('value', 'return function (){console.log(value);}');
fn('hello');`
Really boring to share some private variables...
Michaël Rouges - Lcfvs - @Lcfvs