Subset a NamedTuple?

I forgot to mention one more thing: Your method is “simple” to you because your functions don’t have optional arguments. Is that right? My functions very often have optional arguments, where you can omit some of the arguments. To adopt your catch-all NamedTuple method, you would have to write a more complicated wrapper:

# -- in one module
function f(; x = "hello", y = 3.14, z = nothing)
  @show x, y, z
end
# The simple version doesn't allow for optional arguments:
#   f(nt::NamedTuple) = f(; nt.x, nt.y, nt.z)
# We need the following to allow for optional arguments:
function f(nt::NamedTuple)
  args = ()
  if haskey(nt, :x)
    args = (; x = nt.x,)
  end
  if haskey(nt, :y)
    args = (; args..., y = nt.y)
  end
  if haskey(nt, :z)
    args = (; args..., z = nt.z)
  end
  f(; args...) # Typo fixed (30 min after the posting)
end

#function g(; x = "hello", y = 3.14, z = nothing)
#  @show x, y, z
#end

read_data() = (x = "x", z = "z", y = "y")

# -- in the main program
vars = read_data()

nt1 = vars[(:x,:z)] # Omit :y .
nt2 = (; vars[(:x,:z)]..., y = "replaced")

f(nt1) # works
f(nt2) # works
f(; x = "x") # I sometimes call the original interface.

In the first call, you omit “y” because you want to let the function use its own default value. The 3rd call is to the original interface.

If I write the complicated f(nt::NamedTuple) version, then I’d also include the check in the f(nt::NamedTuple) to detect misspelt or extraneous arguments. Then, the f(nt::NamedTuple) would become as robust as I want.

If you want more robust control, I suggest writing function methods for custom composite types instead of NamedTuple or kwargs....

Sorry I don’t understand your point. I don’t think my method as I have shown earlier needs more improvements: I just maintain the strict interface without introducing the catch-all NamedTuple on the function side. To manage the variables to be sent to the function, I manipulate the NamedTuple on the caller’s side. What benefits would I get if I introduced a NamedTuple interface to my function f ?

But, I guess this is because I don’t understand what you are proposing.

1 Like

I had created a Chat GPT tailored to Julia with a pdf copy of the documentation at its disposal. It was able to come up with the simple solution.

3 Likes

Looks wonderful. Do you mean that there is a public website for your ChatGPT customization?

Sorry for piling on a solved topic, but I just wanted to highlight @Eben60 's answer, which looks similar to the originally proposed version

vars = read_data() # returns a large NamedTuple
subset = vars[(:a, :x, :q, :ii)] # Needs only a subset
func_with_optional_keyword_args(; subset...)

but has the advantage that the “extracted” parts of the tuple are also available in the local scope without needing to write nt.a multiple times, e.g.

(; a, x, q, ii) = read_data()
func_with_optional_keyword_args(; a, x, q, ii)

# Can also use `a` in the following

It makes it very clear what is used where, but it does require writing out the variable names twice though.

1 Like

I believe he’s created a “Custom GPT” which is a ChatGPT Plus feature. It doesn’t seem to be publicly available, or at least I couldn’t find it (Julia being such a common name doesn’t help either), but if the Julia manual is the only customization, it should be easy enough to replicate.

As @digital_carver said, it’s a custom GPT that has instructions to reference the documentation and github repository when responding to prompts. It was private before, but I made it available through this link: https://chatgpt.com/g/g-67b8b2d698a481918d45d117c8cf1acd-julia-gpt

Thank you for the idea. That sometimes works. But, I actually have functions that use different subsets of the dataset that includes many variables. That means I would end up writing out many variables like this:

(; a, x, q, ii, p, z, y) = read_data()
u = f(; z, y)
v = g(; u, ii, q)
. . .

The problems with this approach are

  1. The list sometimes becomes too long; I sometimes need two lines to receive the variables from my data-generating function like read_data() when some of the names are longer.
  2. I would end up spilling little names like x, z, . . . into the current scope.

It’s very uncomfortable to have may variables with short names into a single scope. (For that reason, I very often use let in my programs to limit the scope of local variables.) To avoid that, you want to use somewhat longer names, or to encapsulate the variables into a single object . . . for the latter purpose, NamedTuple is ideal (if the number of the variables are fewer than a few tens).

If you don’t have many variables, your solution is better and I would use it.

1 Like