AFAICT, it remains possible to do dynamic type generation if you (1) print the 
code that would define the type to a file, and (2) `include` the file.

function create_type_dynamically{T}(::Type{T})
    type_name = string("MyType", T)
    isdefined(Main, Symbol(type_name)) && return nothing
    filename = joinpath(tempdir(), string(T))
    open(filename, "w") do io
        println(io, """
type $type_name
    val::$T
end
                """)
    end
    eval(include(filename))
    nothing
end

Is this somehow less evil than doing it in a generated function?

Best,
--Tim

On Wednesday, August 10, 2016 9:49:23 PM CDT Jameson Nash wrote:
> > Why is it impossible to generate a new type at run time? I surely can do
> 
> this by calling `eval` at module scope.
> 
> module scope is compile time != runtime
> 
> > Or I could create a type via a macro.
> 
> Again, compile time != runtime
> 
> > Given this, I can also call `eval` in a function, if I ensure the
> 
> function is called only once.
> 
> > Note that I've been doing this in Julia 0.4 without any (apparent)
> 
> problems.
> 
> Sure, I'm just here to tell you why it won't work that way in v0.5
> 
> > I'm not defining thousands of types in my code. I define one type, and
> 
> use it all over the place. However, each time my code runs (for days!), it
> defines a different type, chosen by a set of user parameters. I'm also not
> adding constraints to type parameters -- the type parameters are just `Int`
> values.
> 
> Right, the basic tradeoff required here is that you just need to provide a
> convenient way for your user to declare the type at the toplevel that will
> be used for the run. For example, you can just JIT the code for the whole
> run at the beginning:
> 
> function do_run()
>   return @eval begin
>      lots of function definitions
>      do_work()
>   end
> end
> 
> On Wed, Aug 10, 2016 at 5:14 PM Erik Schnetter <schnet...@gmail.com> wrote:
> > On Wed, Aug 10, 2016 at 1:45 PM, Jameson <vtjn...@gmail.com> wrote:
> >> AFAIK, defining an arbitrary new type at runtime is impossible, sorry. In
> >> v0.4 it was allowed, because we hoped that people understood not to try.
> >> See also https://github.com/JuliaLang/julia/issues/16806. Note that it
> >> is insufficient to "handle" the repeat calling via caching in a Dict or
> >> similar such mechanism. It must always compute the exact final output
> >> from
> >> the input values alone (e.g. it must truly be const pure).
> > 
> > The generated function first calculates the name of the type, then checks
> > (`isdefined`) if this type is defined, and if so, returns it. Otherwise it
> > is defined and then returned. This corresponds to looking up the type via
> > `eval(typename)` (a symbol). I assume this is as pure as it gets.
> > 
> > Why is it impossible to generate a new type at run time? I surely can do
> > this by calling `eval` at module scope. Or I could create a type via a
> > macro. Given this, I can also call `eval` in a function, if I ensure the
> > function is called only once. Note that I've been doing this in Julia 0.4
> > without any (apparent) problems.
> > 
> > Being able to define types with arbitrary constraints in the type
> > 
> >> parameters works OK for toy demos, but it's intentionally rather
> >> difficult
> >> since it causes performance issues at scale. Operations on Array are
> >> likely
> >> to be much faster (including the allocation) than on Tuple (due to the
> >> cost
> >> of *not* allocating) unless that Tuple is very small.
> > 
> > I'm not defining thousands of types in my code. I define one type, and use
> > it all over the place. However, each time my code runs (for days!), it
> > defines a different type, chosen by a set of user parameters. I'm also not
> > adding constraints to type parameters -- the type parameters are just
> > `Int`
> > values.
> > 
> > And yes, I am using a mutable `Vector{T}` as underlying storage, that's
> > not the issue here. The speedup comes from knowing the size of the array
> > ahead of time, which allows the compiler to optimize indexing expressions.
> > I've benchmarked it, and examined the generated machine code. There's no
> > doubt that generating a type is the "right thing" to do in this case.
> > 
> > -erik
> > 
> > On Wednesday, August 10, 2016 at 1:25:15 PM UTC-4, Erik Schnetter wrote:
> >>> I want to create a type, and need more flexibility than Julia's `type`
> >>> definitions offer (see <https://github.com/eschnett/FastArrays.jl>).
> >>> Currently, I have a function that generates the type, and returns the
> >>> type.
> >>> 
> >>> I would like to make this a generated function (as it was in Julia 0.4).
> >>> The advantage is that this leads to type stability: The generated type
> >>> only
> >>> depends on the types of the arguments pass to the function, and Julia
> >>> would
> >>> be able to infer the type.
> >>> 
> >>> In practice, this looks like
> >>> 
> >>> using FastArrays
> >>> # A (10x10) fixed-size arraytypealias Arr2d_10x10 FastArray(1:10, 1:10)
> >>> a2 = Arr2d_10x10{Float64}(:,:)
> >>> 
> >>> 
> >>> In principle I'd like to write `FastArray{1:10, 1:10}` (with curly
> >>> braces), but Julia doesn't offer sufficient flexibility for this. Hence
> >>> I
> >>> use a regular function.
> >>> 
> >>> To generate the type in the function I need to call `eval`. (Yes, I'm
> >>> aware that the function might be called multiple times, and I'm handling
> >>> this.)
> >>> 
> >>> Do you have a suggestion for a different solution?
> >>> 
> >>> -erik
> >>> 
> >>> On Wed, Aug 10, 2016 at 11:51 AM, Jameson <vtjn...@gmail.com> wrote:
> >>>> It is tracking the dynamic scope of the code generator, it doesn't care
> >>>> about what code you emit. The generator function must not cause any
> >>>> side-effects and must be entirely computed from the types of the inputs
> >>>> and
> >>>> not other global state. Over time, these conditions are likely to be
> >>>> more
> >>>> accurately enforced, as needed to make various optimizations reliable
> >>>> and/or correct.
> >>>> 
> >>>> 
> >>>> 
> >>>> On Wednesday, August 10, 2016 at 10:48:31 AM UTC-4, Erik Schnetter
> >>>> 
> >>>> wrote:
> >>>>> I'm encountering the error "eval cannot be used in a generated
> >>>>> function" in Julia 0.5 for code that is working in Julia 0.4. My
> >>>>> question
> >>>>> is -- what exactly is now disallowed? For example, if a generated
> >>>>> function
> >>>>> `f` calls another (non-generated) function `g`, can `g` then call
> >>>>> `eval`?
> >>>>> Does the word "in" here refer to the code that is generated by the
> >>>>> generated function, or does it refer to the dynamical scope of the
> >>>>> code
> >>>>> generation state of the generated function?
> >>>>> 
> >>>>> To avoid the error I have to redesign my code, and I'd like to know
> >>>>> ahead of time what to avoid. A Google search only turned up the C file
> >>>>> within Julia that emits the respective error message, as well as the
> >>>>> Travis
> >>>>> build log for my package.
> >>>>> 
> >>>>> -erik
> >>>>> 
> >>>>> --
> >>>>> Erik Schnetter <schnet...@gmail.com>
> >>>>> http://www.perimeterinstitute.ca/personal/eschnetter/
> >>> 
> >>> --
> >>> Erik Schnetter <schnet...@gmail.com>
> >>> http://www.perimeterinstitute.ca/personal/eschnetter/
> > 
> > --
> > Erik Schnetter <schnet...@gmail.com>
> > http://www.perimeterinstitute.ca/personal/eschnetter/


Reply via email to