Coder Social home page Coder Social logo

Comments (5)

slwu89 avatar slwu89 commented on June 14, 2024 1

I tried to prototype a way to include that type information in the macro and was "partially successful". But there is a very odd issue about how the code emitted by the macro was evaluated that prevented it from being successful. I don't yet understand enough about how evaluation in Julia works to figure this out. Here's an MWE of the issue I encountered during prototyping:

using MacroTools

# crude version of aagent for prototype
macro make_type(name, fields)
    param_tnames = map(name.args[2:end]) do x
        if x isa Symbol
            return x
        else
            return x.args[1]
        end
    end # like T,L
    param_tnames_constraints = :({$(name.args[2:end]...)}) # like T<:Number,L<:Real
    tname = :($(name.args[1]){$(param_tnames...)})

    define_type(name, fields, __module__, quote
        function $(tname)() where $(param_tnames_constraints)
            m = new()
            m
        end
    end)
end

# crude version of define_agent for prototype
function define_type(name, fields, __module, constructor)
    fields = MacroTools.striplines(fields)
    quote
        let
            name = $(QuoteNode(name))
            additional_fields = $(QuoteNode(fields.args))
            additional_fieldnames = [Meta.isexpr(f, :(::)) ? f.args[1] : f for f in $(QuoteNode(fields.args))]

            expr = quote
                mutable struct $name
                    $(additional_fields...)
                    $$(QuoteNode(constructor))
                end
            end
            println("returned expr: ", expr)
            Core.eval($(__module), expr)
        end
    end
end

Calling the above results in an error:

julia> @make_type MyAgent{T<:AbstractString} begin
           myname::T
       end
returned expr: begin
    #= /Users/wusea/Desktop/misc/agentypes.jl:89 =#
    mutable struct MyAgent{T <: AbstractString}
        #= /Users/wusea/Desktop/misc/agentypes.jl:90 =#
        myname::T
        #= /Users/wusea/Desktop/misc/agentypes.jl:91 =#
        begin
            #= /Users/wusea/Desktop/misc/agentypes.jl:73 =#
            function MyAgent{T}() where {T <: AbstractString}
                #= /Users/wusea/Desktop/misc/agentypes.jl:73 =#
                #= /Users/wusea/Desktop/misc/agentypes.jl:74 =#
                m = new()
                #= /Users/wusea/Desktop/misc/agentypes.jl:75 =#
                m
            end
        end
    end
end
ERROR: syntax: invalid variable expression in "where" around /Users/wusea/Desktop/misc/agentypes.jl:89
Stacktrace:
 [1] top-level scope
   @ none:1

Now, the very weird part is that if you just copy and paste the returned code into the REPL it works just fine:

julia> mutable struct MyAgent{T <: AbstractString}
           #= /Users/wusea/Desktop/misc/agentypes.jl:90 =#
           myname::T
           #= /Users/wusea/Desktop/misc/agentypes.jl:91 =#
           begin
               #= /Users/wusea/Desktop/misc/agentypes.jl:73 =#
               function MyAgent{T}() where {T <: AbstractString}
                   #= /Users/wusea/Desktop/misc/agentypes.jl:73 =#
                   #= /Users/wusea/Desktop/misc/agentypes.jl:74 =#
                   m = new()
                   #= /Users/wusea/Desktop/misc/agentypes.jl:75 =#
                   m
               end
           end
       end

julia> alice = MyAgent{String}()
MyAgent{String}(#undef)

from algebraicagents.jl.

thevolatilebit avatar thevolatilebit commented on June 14, 2024 1

Got it! It seems to me that Julia applies some extra expression "normalisation" when you run the code from REPL; when you construct an expression manually and eval it, you need to be more careful.

In this case, the braces around parameter constraints are redundant. We need the following:

# in make_type
param_tnames_constraints = name.args[2:end] # like T<:Number,L<:Real`
# in define_type
function $(tname)() where $(param_tnames_constraints...)

from algebraicagents.jl.

thevolatilebit avatar thevolatilebit commented on June 14, 2024

I refined the support for parametric types in @aagent.

from algebraicagents.jl.

thevolatilebit avatar thevolatilebit commented on June 14, 2024

Consider

@aagent struct MyAgent{T <: Real, P <: Real}
    myname1::T
    myname2::P
end

a = MyAgent{Float64, Int}("myagent", 1, 2)
@test a isa MyAgent{Float64, Int}

from algebraicagents.jl.

slwu89 avatar slwu89 commented on June 14, 2024

Cool! I think this issue can be closed.

from algebraicagents.jl.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.