Open ceymard opened 12 years ago
Eg. In the CouchDB NodeJS driver, you can specify "views" directly in a Javascript object. Theses views are functions that are passed to
.toString()
, which gives their text body.
I think relying on Function::toString
isn't optimal in those cases. Can't you just:
"function(){#{ Coco.compile code, {+bare} }}"
toString
has its advantages, and no I can' t rely on compile at runtime since it is inefficient and has the drawback of needing a useless dependency (whereas coco is just a dev dependency right now).
Inlining is in fact the only viable approach, aside writing the code directly in javascript (yuck).
I can' t rely on compile at runtime since it is inefficient and has the drawback of needing a useless dependency
So precompiling ("function(){#{ fs.readFileSync 'lib/fun.js' }}"
) doesn't work?
it is inefficient as well, since it requires execution at runtime.
I understand that they are ways to circumvent the issue, but I'm not interested in circumventing ; I really would like for it to work out-of-the-box.
If you're not against the principle of the idea in general, I could try to provide a patch if implementing it bothers you.
it is inefficient as well, since it requires execution at runtime.
Execution as in File IO, and caching isn't an option?:
js = "function(){#{ fs.readFileSync 'lib/fun.js' }}"'
...
views: js
I understand that they are ways to circumvent the issue, but I'm not interested in circumventing ; I really would like for it to work out-of-the-box.
Adding the proposed option is circumventing as well.
If you're not against the principle of the idea in general, I could try to provide a patch if implementing it bothers you.
I'm mildly against more options for producing different compilations. The patch would have to be shockingly elegant to be merged. ;)
Adding the proposed option is circumventing as well.
I don't really get this feeling ; this option would not require me having to code differently than usual at all, just turning a switch on and off.
I'm mildly against more options for producing different compilations. The patch would have to be shockingly elegant to be merged. ;)
Understandable, I'll see what's doable if and when I have time :)
@satyr In https://github.com/satyr/coco/blob/master/src/ast.co#L2005, just inline the function if we're in the special mode.
function utility
if <special mode>
"(#{UTILITIES[it]})"
else
Scope.root.assign \__ + it, UTILITIES[it]
Apart from bloating the compiled code, any problems? :D
Ehrm, how does it work exactly ?
@ceymard That function is used like this:
case \^ then return "#{ utility \clone }(#{ it.compile o, LEVEL_LIST })"
So, normally, utility(name)
makes sure that the helper function is in the global scope and returns its name so that it can be called. My suggestion would instead just return the functions code so that it would be inlined. And yes, that's going to look really ugly in the output - but then again, that probably doesn't matter.
Sorry, I still don't get it.
Say I have a function declared as such :
function a (arg)
arg <<< arg
This gets compiled into
function a(arg){
return __import(arg, arg);
}
function __import(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
What do I do so that the a()
function either contains __import
, or has a version of __import
inlined directly into it with your proposal ?
The output would look like this:
function a(arg){
return (function __import(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
})(arg, arg);
}
Uh, if that's your question, I didn't think about how to turn that on/off.
Yes that was the question :)
@satyr : why not add some kind of keyword to the functions to tag them as inlined or selfcontained, or some other keyword ? Having it would then trigger thejh's compilation. Thoughts ?
why not add some kind of keyword to the functions to tag them as inlined or selfcontained, or some other keyword ?
You mean something like a inlined <<< b
? Looks horrible.
@satyr He said "the functions", not "the operators". How about this?
(foo, bar) inlined ->
a <<< b
(foo, bar) inlined ->
Horrible too.
Note that I'm not yet convinced about the use cases for this proposal.
I really understand the couch usecase. When I have a bunch of small map functions, I don't want one file for each. So, I have to manually read in the file, chop it in seperate methods and run them through coco, right?
@thejh that's exactly the use case I wanted to solve.
And yes, I meant something linke function(whatever) inlined
or inline function(whatever)
, except inline
doesn't seem to be accurate.
More like standalone function thefunc(args) ...
or function thefunc(args) standalone
, which makes their body not call anything from outer scope that isn't explicitely called inside.
As you said, it is not a very common use case, but a very annoying issue to deal with, which is why I think the ugliness of this construct is largely outweighted by its usefulness and rareness (ie you won't find it too often in your code, but when you do, you'll be happy it's there, however ugly you think it is :) ).
So, I have to manually read in the file, chop it in seperate methods and run them through coco, right?
You should be doing that as that's what the Couch API expects--a JS code that's executed in a separate environment. Like I said above, Function::toString
is unreliable.
@ceymard Time to build an inlining postprocessor for JS! :D
If you're interested, you might want to use https://github.com/thejh/node-astjourney for that - it can read the JS AST into a nice structure, you can walk and modify it, and finally, you can write it out. Actually, I'd appreciate having someone use my libs. :D
Function::toString
is unreliable in javascript preprocessors, like coco, because of the afore mentionned problem (creating objects in outer scope).
It is, however very used in many node.js projects, and is reliable enough to actually be used. It would be nice we could use it too in coco.
@ceymard Actually, wouldn't a preprocessor that can also inline your own helpers be better?
@thejh coco is already a preprocessor, I don't see the point of multiplying the number of external tools I need to build my code.
About using your project, I try to stay clear from ASTs when I don't need them, and here I don't think I do :)
@ceymard But you could argue that although coco is a preprocesor, inlining is a completely different job.
@ceymard Quickly coded this, would it work for you? https://github.com/thejh/node-astjourney/tree/master/example
It would be great if there was a flag on the command line that would allow inlining helper functions.
Eg. In the CouchDB NodeJS driver, you can specify "views" directly in a Javascript object. Theses views are functions that are passed to
.toString()
, which gives their text body.Another example ; in my template language (JinJS), I declare filters that are to be embedded into the resulting templates the same way.
The problem is that whenever I use, say,
import
, the__import
function is defined at toplevel, therefore rendering the isolated.toString()
functions useless since this part is not embedded.So, it would be cool that a switch could allow us to generate
a <<< b
asThis may be complicated, I don't know, but it would sure be useful, since I could still use coco instead of having to going back to javascript in those cases.