Approach 1: Parse to get an AST and then eval
Probably the easiest way is to create a string of what you want and then parse it to get an AST, and then eval the AST. You can do any or all within the function. Here's possible simple implementation that does it all
function CreateRecordType(typeName::ASCIIString,fieldNames::Array{ASCIIString,1},fieldTypes::Array{ASCIIString,1})
s::ASCIIString = "type $typeName <: RecordType\n";
for i = 1:length(fieldNames)
s = s*"$(fieldNames[i])::$(fieldTypes[i])\n"
end
eval(parse(s*"end"));
return;
end
Using it...
julia> abstract RecordType;
julia> CreateRecordType("Person",["name","age"],["ASCIIString","Int64"])
julia> bubba = Person("Bubba",2)
Person("Bubba",2)
julia> print(bubba.age)
2
That's probably not as efficient as it could be, instead you can take a look at the AST that parse produces and then create the Expr to make the AST directly and not use parse and not use a string.
Approach 2: Making the AST directly
Here's an alternate form that creates an AST, it's a little more safe because it requires types and symbols rather than opaque strings. This was created by experimenting with the output of various parses as alluded to above. Using Dict instead of 2 arrays is probably better because the field and the type must always be paired.
function createTypeAST(typeName::Symbol,parentType::Type,fields::Dict{Symbol,DataType})
e = Expr(:type,true)
push!(e.args,Expr(:<:));
push!(e.args[2].args,typeName);
push!(e.args[2].args,parentType);
push!(e.args,Expr(:block))
for field in fields
push!(e.args[3].args,:($(field[1])::$(field[2])));
end
return e;
end
2nd form in action
julia> x = createTypeAST(:P1,RecordType,Dict(:a => Int64))
:(type P1<:RecordType
a::Int64
end)
julia> eval(x)
julia> y = P1(1)
P1(1)
julia> y.a
1