Convenient syntax is parsed and lowered to sequences of method calls.
julia> @code_lowered NamedTuple((:a=>1,))
CodeInfo(
1 ─ %1 = Base.NamedTuple()
│ %2 = Base.merge(%1, itr)
└── return %2
)
julia> @which merge(NamedTuple(), (:a=>1,))
merge(a::NamedTuple, itr) in Base at namedtuple.jl:288
Using code_lowered further doesn’t seem to help because it just says it’s applying Core.NamedTuple, so I looked at the source code. It seems to be down to NamedTuple{(names...,)}((vals...,)) which takes in a Tuple, so:
julia> @which NamedTuple{(:a,)}((1,))
(NamedTuple{names})(args::Tuple) where names in Core at boot.jl:601
boot.jl only has a few lines of source code for NamedTuple, so you can take a look at that. This has already gotten uncomfortably close to Core and generated functions for me, so I’m not really sure of what exactly happens past this point. I think boot.jl runs before namedtuple.jl does, so I’m guessing the lines in boot.jl is where it calls Core code.
Interestingly, namedtuple.jl has an @evaled method that is very similar to the evaled definition in boot.jl, I think the difference is that it belongs to Base vs Core, though I can’t tell you which happens when.
This shows us that a NamedTuple is a built-in type that has one or more names
[ hence NamedTuple ] and becomes constructed when given a tuple of value[s]
[ hence NamedTuple] to be assigned to the name[s].
to_obtain = (three = 3,)
name_to_use = :three
value_to_assign = 3
# we start with the Type,
# which is specialized by the name[s]
# we finish with the value
NamedTuple_type =
Core.apply_type(Core.NamedTuple, (name_to_use,))
namedtuple =
NamedTuple_type( Core.tuple(value_to_assign) )
namedtuple == (three = 3,)