Adrian

Can you give more details for how the variables would be used? If the
variables are declared in a function, then there must be code that uses
them; how would this code know which variables exist? Is there e.g. a
globally known list of variables that will be provided? Or will the
variables e.g. only be used in strings to generate html code?

You can generate the syntax tree for function that contains the definitions
from the dictionary, and then use `eval` to create the function.
(Alternatively, you can use a macro or a generated function.) This is
indeed one of the strengths of Julia, and it requires neither string
manipulation, nor parsing, nor creating files nor include.

Here is an example:

fun_expr(var, val) = quote
    function f(x)
        $var = $val
        x + y
    end
end

eval(fun_expr(:y, :42))

`fun_expr` creates a syntax tree (an `Expr`) that defines a function. The
function is quoted. The function arguments `var` and `val` are inserted
into that function, forming an assignment. Thus `var` better be an
identifier (or something else that can be on the left of an assignment
operator), and `val` can be an arbitrary value. Given how the function
looks, `var` essentially has to be `y` since it's used in the next line; of
course, this was just my arbitrary choice.

The call to `eval` then passes the respective arguments, choosing the
symbol `y` for the variable name, and the value `42` as value, and defines
the function `f`. If you then call `f(2)`, the result is 44.

Of course, you can define this function `f` only once. Julia does not allow
changing functions. If you want to create many different functions, you
would use anonymous functions instead.

Having said this -- it's not clear that this is indeed the right way to
address your problem; there might be a better solution. Can you elaborate
on why you want to access dictionary elements as local variables?

-erik



On Sun, Aug 14, 2016 at 11:13 AM, Adrian Salceanu <adrian.salce...@gmail.com
> wrote:

> Thanks
>
> Maybe I wasn't clear enough - otherwise, can you please elaborate, I'm
> definitely still poking around, any clarifications would be highly
> appreciated.
>
> > creating a new module
> -> the module is available at compile time (the users of the templating
> system will place the vars in there, by convention).
>
> > parse julia code
> -> it's not really parsing julia code, it has no meaning at the point.
> It's simply basic string processing and it's fast - tried with a 10K lines
> HTML file, no sweat.
>
> > defining globals
> -> why are they globals? include_string() is used inside a function,
> inside a module within the app.
>
> > eval in a module
> -> true, but then what can we do? That's the way of doing metaprogramming
> in Julia, and it's widely used, isn't it?
> I guess that would be the price for not having to do
> print("<html><head>...") like our ancestors used to in PHP or ASP, when not
> being chased by tigers (or something around that age).
>
>
> duminică, 14 august 2016, 15:01:47 UTC+2, Yichao Yu a scris:
>>
>>
>>
>> On Sun, Aug 14, 2016 at 6:13 PM, Adrian Salceanu <adrian....@gmail.com>
>> wrote:
>>
>>> Variables contained in a module and then parsed Julia code included
>>> within a function using include_string().
>>>
>>> Any obvious performance issues with this approach?
>>>
>>
>> Everything about it?
>> Literally every steps are hitting the slow path that is only meant to
>> execute at compile time and not runtime. Including
>>
>> Creating a new module, parse julia code, eval in a module, defining
>> globals.
>>
>>
>>>
>>>
>>> duminică, 14 august 2016, 12:11:06 UTC+2, Adrian Salceanu a scris:
>>>>
>>>> OK, actually, that's not nearly half as bad. Variables contained in a
>>>> module
>>>>
>>>> include("src/Ejl_str.jl")
>>>> using Ejl
>>>>
>>>>
>>>> module _
>>>>   couñtry = "España"
>>>>   lang = "en"
>>>> end
>>>>
>>>>
>>>> function render_template()
>>>>   tpl_data = ejl"""
>>>> <% if _.lang == "en" :>
>>>> Hello from me, ...
>>>> <: else :>
>>>> Hola
>>>> <: end %>
>>>>
>>>>
>>>> %= _.couñtry == "España" ? "Olé" : "Aye"
>>>> moo
>>>> """
>>>>
>>>>
>>>>   include_string(join(tpl_data, "\n"))
>>>>   join(____output, "\n")
>>>> end
>>>>
>>>>
>>>> render_template() |> println
>>>>
>>>> Hello from me, ...
>>>>
>>>>
>>>> Olé
>>>> moo
>>>>
>>>>
>>>> duminică, 14 august 2016, 11:20:37 UTC+2, Adrian Salceanu a scris:
>>>>>
>>>>> Thanks
>>>>>
>>>>> Yes, I've thought about a few ways to mitigate some of these issues:
>>>>>
>>>>> 1. in the app I can setup a module (like Render) and evaluate into
>>>>> this module exclusively.
>>>>> Hence, another approach might be to have some helper methods that
>>>>> setup the variables in the module and then eval the template itself inside
>>>>> the module too (must try though). So something in the lines of:
>>>>> set(:foo, "foo")
>>>>> set(:bar, [1, 2, 3])
>>>>> parse_tpl(ejl"""$(foo) and $(bar)""")
>>>>> # all the above gets parsed in Render
>>>>>
>>>>> 2. break the parsing in 2 steps:
>>>>> a. reading the template string and parse it to generated Julia code
>>>>> (as strings) (an array of Julia code lines) - cache it
>>>>> b. (load strings from cache and) eval the code together with the vars
>>>>>
>>>>> ===
>>>>>
>>>>> Another approach (which is how it's done in one of the Ruby templating
>>>>> engine) is to generate a full function definition, whose body parses the
>>>>> template and takes the variables as params. And then eval and execute the
>>>>> function with its params. However, I'm still struggling with the
>>>>> metaprogramming API as for instance parse() chokes on multiple lines, and 
>>>>> I
>>>>> couldn't find a functional equivalent of a quote ... end blocks. But I'm
>>>>> hoping include_string() will do the trick (must test though).
>>>>>
>>>>>
>>>>> sâmbătă, 13 august 2016, 15:20:01 UTC+2, Yichao Yu a scris:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Sat, Aug 13, 2016 at 8:06 PM, Adrian Salceanu <
>>>>>> adrian....@gmail.com> wrote:
>>>>>>
>>>>>>> That's pretty difficult as my goal is to use embedded Julia as the
>>>>>>> templating language. Similar to Ruby's ERB, ex:
>>>>>>> http://www.stuartellis.eu/articles/erb/
>>>>>>>
>>>>>>> So say in the template I have something like
>>>>>>>
>>>>>>> <% if foo == "bar" %>
>>>>>>> Bar
>>>>>>> <% else %>
>>>>>>> Baz
>>>>>>> <% end %>
>>>>>>>
>>>>>>> The idea is to use Julia itself to parse the code block and Julia
>>>>>>> will raise an error is foo is not defined. So I can't really look it up.
>>>>>>>
>>>>>>
>>>>>> It's ok to use the julia syntax and parser but it's a pretty bad idea
>>>>>> to use the julia runtime to actually evaluating the expression, and
>>>>>> absolutely not by making them reference to local variables.
>>>>>>
>>>>>> For a start you are not allowed to reference local variables by names
>>>>>> anyway.
>>>>>> You also shouldn't allow reference to/overwrite of other local
>>>>>> variables (i.e. the template namespace should be fully isolated and
>>>>>> independent of any scope in the template engine).
>>>>>>
>>>>>> Since you want to eval, it seems that efficiency is not an issue, in
>>>>>> which case you can create an anonymous module and eval/create globals in
>>>>>> that module. This should also be reasonably fast if you are only using 
>>>>>> the
>>>>>> template once.
>>>>>>
>>>>>> If you want to use it multiple time and compile the template, you
>>>>>> should then scan for variable references in the expressions and process 
>>>>>> it
>>>>>> from there.
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> I can either do
>>>>>>>
>>>>>>> <% if _[:foo] == "bar" %>
>>>>>>>
>>>>>>> or
>>>>>>>
>>>>>>> <% if _(:foo) == "bar" %>
>>>>>>>
>>>>>>> but it's not that nice.
>>>>>>>
>>>>>>>
>>>>>>> sâmbătă, 13 august 2016, 13:24:18 UTC+2, Yichao Yu a scris:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Sat, Aug 13, 2016 at 7:13 PM, Adrian Salceanu <
>>>>>>>> adrian....@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> Thanks
>>>>>>>>>
>>>>>>>>> It's for a templating engine. The user creates the document (a
>>>>>>>>> string) which contains interpolated variables placeholders and 
>>>>>>>>> markup. When
>>>>>>>>> the template is rendered, the placeholders must be replaced with the
>>>>>>>>> corresponding values from the dict.
>>>>>>>>>
>>>>>>>>> The lines in the template are eval-ed and so Julia will look for
>>>>>>>>> the variables in the scope. So the vars should be already defined.
>>>>>>>>>
>>>>>>>>
>>>>>>>> You should explicitly look up those variables in the dict instead.
>>>>>>>>
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Yes, ultimately I can force the user to use a dict (or rather a
>>>>>>>>> function for a bit of semantic sugar) - which is preferable from a
>>>>>>>>> performance perspective, but less pretty end error prone from the user
>>>>>>>>> perspective.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>
>>


-- 
Erik Schnetter <schnet...@gmail.com>
http://www.perimeterinstitute.ca/personal/eschnetter/

Reply via email to